diff --git a/.all-contributorsrc b/.all-contributorsrc deleted file mode 100644 index ced3b155b..000000000 --- a/.all-contributorsrc +++ /dev/null @@ -1,1871 +0,0 @@ -{ - "files": [ - "website/src/pages/credits.mdx" - ], - "imageSize": 75, - "commit": false, - "badgeTemplate": "Contributors", - "contributors": [ - { - "login": "leaanthony", - "name": "Lea Anthony", - "avatar_url": "https://avatars.githubusercontent.com/u/1943904?v=4", - "profile": "https://github.com/leaanthony", - "contributions": [ - "code", - "ideas", - "design", - "content", - "example", - "mentoring", - "projectManagement", - "tool", - "bug", - "blog", - "maintenance", - "platform", - "review", - "question", - "research", - "test", - "tutorial", - "talk", - "review", - "doc" - ] - }, - { - "login": "stffabi", - "name": "stffabi", - "avatar_url": "https://avatars.githubusercontent.com/u/9464631?v=4", - "profile": "https://github.com/stffabi", - "contributions": [ - "code", - "ideas", - "design", - "bug", - "maintenance", - "platform", - "review", - "question", - "research", - "review", - "doc", - "test" - ] - }, - { - "login": "tmclane", - "name": "Travis McLane", - "avatar_url": "https://avatars.githubusercontent.com/u/511975?v=4", - "profile": "https://github.com/tmclane", - "contributions": [ - "code", - "research", - "platform", - "ideas", - "bug", - "review", - "test", - "question", - "doc" - ] - }, - { - "login": "misitebao", - "name": "Misite Bao", - "avatar_url": "https://avatars.githubusercontent.com/u/28185258?v=4", - "profile": "https://misitebao.com/", - "contributions": [ - "doc", - "translation", - "research", - "maintenance" - ] - }, - { - "login": "bh90210", - "name": "Byron Chris", - "avatar_url": "https://avatars.githubusercontent.com/u/22690219?v=4", - "profile": "https://github.com/bh90210", - "contributions": [ - "code", - "research", - "maintenance", - "bug", - "review", - "test", - "question", - "ideas", - "design", - "platform", - "infra" - ] - }, - { - "login": "konez2k", - "name": "konez2k", - "avatar_url": "https://avatars.githubusercontent.com/u/32417933?v=4", - "profile": "https://github.com/konez2k", - "contributions": [ - "code", - "platform", - "ideas" - ] - }, - { - "login": "dedo1911", - "name": "Dario Emerson", - "avatar_url": "https://avatars.githubusercontent.com/u/1364496?v=4", - "profile": "https://github.com/dedo1911", - "contributions": [ - "code", - "bug", - "ideas", - "test" - ] - }, - { - "login": "ianmjones", - "name": "Ian M. Jones", - "avatar_url": "https://avatars.githubusercontent.com/u/4710?v=4", - "profile": "https://ianmjones.com/", - "contributions": [ - "code", - "bug", - "ideas", - "test", - "review", - "platform" - ] - }, - { - "login": "marktohark", - "name": "marktohark", - "avatar_url": "https://avatars.githubusercontent.com/u/19359934?v=4", - "profile": "https://github.com/marktohark", - "contributions": [ - "code" - ] - }, - { - "login": "rh12503", - "name": "Ryan H", - "avatar_url": "https://avatars.githubusercontent.com/u/48951973?v=4", - "profile": "https://github.com/rh12503", - "contributions": [ - "code" - ] - }, - { - "login": "sircodemane", - "name": "Cody Bentley", - "avatar_url": "https://avatars.githubusercontent.com/u/6968902?v=4", - "profile": "https://codybentley.dev/", - "contributions": [ - "code", - "platform", - "ideas", - "financial" - ] - }, - { - "login": "napalu", - "name": "Florent", - "avatar_url": "https://avatars.githubusercontent.com/u/6690378?v=4", - "profile": "https://github.com/napalu", - "contributions": [ - "code", - "bug" - ] - }, - { - "login": "akhudek", - "name": "Alexander Hudek", - "avatar_url": "https://avatars.githubusercontent.com/u/147633?v=4", - "profile": "https://github.com/akhudek", - "contributions": [ - "code", - "financial" - ] - }, - { - "login": "timkippdev", - "name": "Tim Kipp", - "avatar_url": "https://avatars.githubusercontent.com/u/37030721?v=4", - "profile": "https://twitter.com/timkippdev", - "contributions": [ - "code" - ] - }, - { - "login": "gelleson", - "name": "Altynbek Kaliakbarov", - "avatar_url": "https://avatars.githubusercontent.com/u/44272887?v=4", - "profile": "https://github.com/gelleson", - "contributions": [ - "code" - ] - }, - { - "login": "Chronophylos", - "name": "Nikolai Zimmermann", - "avatar_url": "https://avatars.githubusercontent.com/u/14890588?v=4", - "profile": "https://github.com/Chronophylos", - "contributions": [ - "code" - ] - }, - { - "login": "k-muchmore", - "name": "k-muchmore", - "avatar_url": "https://avatars.githubusercontent.com/u/16393095?v=4", - "profile": "https://github.com/k-muchmore", - "contributions": [ - "code" - ] - }, - { - "login": "Snider", - "name": "Snider", - "avatar_url": "https://avatars.githubusercontent.com/u/631881?v=4", - "profile": "https://peakd.com/@snider", - "contributions": [ - "code", - "ideas", - "doc", - "financial" - ] - }, - { - "login": "albert-sun", - "name": "Albert Sun", - "avatar_url": "https://avatars.githubusercontent.com/u/54585592?v=4", - "profile": "https://github.com/albert-sun", - "contributions": [ - "code", - "test" - ] - }, - { - "login": "adalessa", - "name": "Ariel", - "avatar_url": "https://avatars.githubusercontent.com/u/7914601?v=4", - "profile": "https://github.com/adalessa", - "contributions": [ - "code", - "bug" - ] - }, - { - "login": "ilgityildirim", - "name": "Ilgıt Yıldırım", - "avatar_url": "https://avatars.githubusercontent.com/u/4365245?v=4", - "profile": "https://triplebits.com/", - "contributions": [ - "code", - "bug", - "financial" - ] - }, - { - "login": "Vaelatern", - "name": "Toyam Cox", - "avatar_url": "https://avatars.githubusercontent.com/u/7906072?v=4", - "profile": "https://github.com/Vaelatern", - "contributions": [ - "code", - "platform", - "bug" - ] - }, - { - "login": "hi019", - "name": "hi019", - "avatar_url": "https://avatars.githubusercontent.com/u/65871571?v=4", - "profile": "https://github.com/hi019", - "contributions": [ - "code", - "bug" - ] - }, - { - "login": "artooro", - "name": "Arthur Wiebe", - "avatar_url": "https://avatars.githubusercontent.com/u/393395?v=4", - "profile": "https://artooro.com/", - "contributions": [ - "code", - "bug" - ] - }, - { - "login": "aayush420", - "name": "Balakrishna Prasad Ganne", - "avatar_url": "https://avatars.githubusercontent.com/u/16898783?v=4", - "profile": "https://sectcs.com/", - "contributions": [ - "code" - ] - }, - { - "login": "BillBuilt", - "name": "BillBuilt", - "avatar_url": "https://avatars.githubusercontent.com/u/28831382?v=4", - "profile": "https://github.com/BillBuilt", - "contributions": [ - "code", - "platform", - "ideas", - "question", - "financial" - ] - }, - { - "login": "Juneezee", - "name": "Eng Zer Jun", - "avatar_url": "https://avatars.githubusercontent.com/u/20135478?v=4", - "profile": "https://github.com/Juneezee", - "contributions": [ - "maintenance", - "code" - ] - }, - { - "login": "LGiki", - "name": "LGiki", - "avatar_url": "https://avatars.githubusercontent.com/u/20807713?v=4", - "profile": "https://lgiki.net/", - "contributions": [ - "doc" - ] - }, - { - "login": "lontten", - "name": "Lontten", - "avatar_url": "https://avatars.githubusercontent.com/u/30745595?v=4", - "profile": "https://github.com/lontten", - "contributions": [ - "doc" - ] - }, - { - "login": "phoenix147", - "name": "Lukas Crepaz", - "avatar_url": "https://avatars.githubusercontent.com/u/809358?v=4", - "profile": "https://github.com/phoenix147", - "contributions": [ - "code", - "bug" - ] - }, - { - "login": "marcus-crane", - "name": "Marcus Crane", - "avatar_url": "https://avatars.githubusercontent.com/u/14816406?v=4", - "profile": "https://utf9k.net/", - "contributions": [ - "bug", - "doc", - "financial" - ] - }, - { - "login": "qaisjp", - "name": "Qais Patankar", - "avatar_url": "https://avatars.githubusercontent.com/u/923242?v=4", - "profile": "https://qaisjp.com/", - "contributions": [ - "doc" - ] - }, - { - "login": "Wakeful-Cloud", - "name": "Wakeful-Cloud", - "avatar_url": "https://avatars.githubusercontent.com/u/38930607?v=4", - "profile": "https://wakefulcloud.dev/", - "contributions": [ - "code", - "bug" - ] - }, - { - "login": "Lyimmi", - "name": "Zámbó, Levente", - "avatar_url": "https://avatars.githubusercontent.com/u/8627125?v=4", - "profile": "https://github.com/Lyimmi", - "contributions": [ - "code", - "platform", - "bug", - "test" - ] - }, - { - "login": "Ironpark", - "name": "Ironpark", - "avatar_url": "https://avatars.githubusercontent.com/u/4973597?v=4", - "profile": "https://github.com/Ironpark", - "contributions": [ - "code", - "ideas" - ] - }, - { - "login": "mondy", - "name": "mondy", - "avatar_url": "https://avatars.githubusercontent.com/u/3961824?v=4", - "profile": "https://github.com/mondy", - "contributions": [ - "code", - "doc" - ] - }, - { - "login": "redraskal", - "name": "Benjamin Ryan", - "avatar_url": "https://avatars.githubusercontent.com/u/6241454?v=4", - "profile": "https://ryben.dev/", - "contributions": [ - "bug" - ] - }, - { - "login": "fallendusk", - "name": "fallendusk", - "avatar_url": "https://avatars.githubusercontent.com/u/565631?v=4", - "profile": "https://github.com/fallendusk", - "contributions": [ - "platform", - "code" - ] - }, - { - "login": "matryer", - "name": "Mat Ryer", - "avatar_url": "https://avatars.githubusercontent.com/u/101659?v=4", - "profile": "https://twitter.com/matryer", - "contributions": [ - "code", - "ideas", - "bug" - ] - }, - { - "login": "abtin", - "name": "Abtin", - "avatar_url": "https://avatars.githubusercontent.com/u/441372?v=4", - "profile": "https://github.com/abtin", - "contributions": [ - "code", - "bug" - ] - }, - { - "login": "lanzafame", - "name": "Adrian Lanzafame", - "avatar_url": "https://avatars.githubusercontent.com/u/5924712?v=4", - "profile": "https://github.com/lanzafame", - "contributions": [ - "platform", - "code" - ] - }, - { - "login": "polikow", - "name": "Aleksey Polyakov", - "avatar_url": "https://avatars.githubusercontent.com/u/58259700?v=4", - "profile": "https://github.com/polikow", - "contributions": [ - "bug", - "code" - ] - }, - { - "login": "alexmat", - "name": "Alexander Matviychuk", - "avatar_url": "https://avatars.githubusercontent.com/u/745421?v=4", - "profile": "https://github.com/alexmat", - "contributions": [ - "code", - "platform" - ] - }, - { - "login": "AlienRecall", - "name": "AlienRecall", - "avatar_url": "https://avatars.githubusercontent.com/u/68950287?v=4", - "profile": "https://github.com/AlienRecall", - "contributions": [ - "code", - "platform" - ] - }, - { - "login": "achhabra2", - "name": "Aman", - "avatar_url": "https://avatars.githubusercontent.com/u/17457975?v=4", - "profile": "https://blog.checkyo.tech/", - "contributions": [ - "doc" - ] - }, - { - "login": "amaury-tobias", - "name": "Amaury Tobias Quiroz", - "avatar_url": "https://avatars.githubusercontent.com/u/37311888?v=4", - "profile": "https://github.com/amaury-tobias", - "contributions": [ - "code", - "bug" - ] - }, - { - "login": "andywenk", - "name": "Andreas Wenk", - "avatar_url": "https://avatars.githubusercontent.com/u/51517?v=4", - "profile": "http://blog.nms.de/", - "contributions": [ - "doc" - ] - }, - { - "login": "stankovic98", - "name": "Antonio Stanković", - "avatar_url": "https://avatars.githubusercontent.com/u/29852655?v=4", - "profile": "https://github.com/stankovic98", - "contributions": [ - "code", - "platform" - ] - }, - { - "login": "antimatter96", - "name": "Arpit Jain", - "avatar_url": "https://avatars.githubusercontent.com/u/12068176?v=4", - "profile": "https://github.com/antimatter96", - "contributions": [ - "doc" - ] - }, - { - "login": "aschey", - "name": "Austin Schey", - "avatar_url": "https://avatars.githubusercontent.com/u/5882266?v=4", - "profile": "https://github.com/aschey", - "contributions": [ - "code", - "bug" - ] - }, - { - "login": "benjamin-thomas", - "name": "Benjamin Thomas", - "avatar_url": "https://avatars.githubusercontent.com/u/1557738?v=4", - "profile": "https://github.com/benjamin-thomas", - "contributions": [ - "code", - "platform", - "ideas" - ] - }, - { - "login": "bt", - "name": "Bertram Truong", - "avatar_url": "https://avatars.githubusercontent.com/u/1100843?v=4", - "profile": "https://www.bertramtruong.com/", - "contributions": [ - "code", - "bug" - ] - }, - { - "login": "TechplexEngineer", - "name": "Blake Bourque", - "avatar_url": "https://avatars.githubusercontent.com/u/175873?v=4", - "profile": "http://techwizworld.net/", - "contributions": [ - "doc" - ] - }, - { - "login": "raitonoberu", - "name": "Denis", - "avatar_url": "https://avatars.githubusercontent.com/u/64320078?v=4", - "profile": "http://vk.com/raitonoberu", - "contributions": [ - "doc" - ] - }, - { - "login": "diogox", - "name": "diogox", - "avatar_url": "https://avatars.githubusercontent.com/u/13244408?v=4", - "profile": "https://github.com/diogox", - "contributions": [ - "code", - "platform" - ] - }, - { - "login": "kyoto44", - "name": "Dmitry Gomzyakov", - "avatar_url": "https://avatars.githubusercontent.com/u/17720761?v=4", - "profile": "https://github.com/kyoto44", - "contributions": [ - "code", - "platform" - ] - }, - { - "login": "edwardbrowncross", - "name": "Edward Browncross", - "avatar_url": "https://avatars.githubusercontent.com/u/35063432?v=4", - "profile": "https://github.com/edwardbrowncross", - "contributions": [ - "code" - ] - }, - { - "login": "elie-g", - "name": "Elie Grenon", - "avatar_url": "https://avatars.githubusercontent.com/u/14944216?v=4", - "profile": "http://pr0gramming.ca/", - "contributions": [ - "code" - ] - }, - { - "login": "fdidron", - "name": "Florian Didron", - "avatar_url": "https://avatars.githubusercontent.com/u/1848786?v=4", - "profile": "https://github.com/fdidron", - "contributions": [ - "code", - "bug", - "ideas", - "test", - "review", - "platform" - ] - }, - { - "login": "GargantuaX", - "name": "GargantuaX", - "avatar_url": "https://avatars.githubusercontent.com/u/14013111?v=4", - "profile": "https://github.com/GargantuaX", - "contributions": [ - "financial" - ] - }, - { - "login": "Igogrek", - "name": "Igor Minin", - "avatar_url": "https://avatars.githubusercontent.com/u/12101721?v=4", - "profile": "https://bednya.ga/", - "contributions": [ - "code", - "bug" - ] - }, - { - "login": "jaesung9507", - "name": "Jae-Sung Lee", - "avatar_url": "https://avatars.githubusercontent.com/u/39658806?v=4", - "profile": "https://www.jae-sung.com/", - "contributions": [ - "code", - "ideas" - ] - }, - { - "login": "Jarek-SRT", - "name": "Jarek", - "avatar_url": "https://avatars.githubusercontent.com/u/3391365?v=4", - "profile": "https://github.com/Jarek-SRT", - "contributions": [ - "code", - "platform" - ] - }, - { - "login": "Junkher", - "name": "Junker", - "avatar_url": "https://avatars.githubusercontent.com/u/85776620?v=4", - "profile": "https://github.com/Junkher", - "contributions": [ - "doc" - ] - }, - { - "login": "kraney", - "name": "Kris Raney", - "avatar_url": "https://avatars.githubusercontent.com/u/5760081?v=4", - "profile": "https://github.com/kraney", - "contributions": [ - "code", - "bug" - ] - }, - { - "login": "LukenSkyne", - "name": "Luken", - "avatar_url": "https://avatars.githubusercontent.com/u/29918069?v=4", - "profile": "https://github.com/LukenSkyne", - "contributions": [ - "doc" - ] - }, - { - "login": "ocelotsloth", - "name": "Mark Stenglein", - "avatar_url": "https://avatars.githubusercontent.com/u/9255772?v=4", - "profile": "https://markstenglein.com/", - "contributions": [ - "code", - "bug" - ] - }, - { - "login": "buddyabaddon", - "name": "buddyabaddon", - "avatar_url": "https://avatars.githubusercontent.com/u/33861511?v=4", - "profile": "https://github.com/buddyabaddon", - "contributions": [ - "code" - ] - }, - { - "login": "MikeSchaap", - "name": "MikeSchaap", - "avatar_url": "https://avatars.githubusercontent.com/u/35368821?v=4", - "profile": "https://github.com/MikeSchaap", - "contributions": [ - "code", - "bug" - ] - }, - { - "login": "Orijhins", - "name": "NYSSEN Michaël", - "avatar_url": "https://avatars.githubusercontent.com/u/47521598?v=4", - "profile": "https://github.com/Orijhins", - "contributions": [ - "code", - "bug" - ] - }, - { - "login": "NanoNik", - "name": "Nan0", - "avatar_url": "https://avatars.githubusercontent.com/u/11991329?v=4", - "profile": "https://github.com/NanoNik", - "contributions": [ - "code", - "ideas", - "test", - "review" - ] - }, - { - "login": "marcio199226", - "name": "oskar", - "avatar_url": "https://avatars.githubusercontent.com/u/10244404?v=4", - "profile": "https://github.com/marcio199226", - "contributions": [ - "doc" - ] - }, - { - "login": "pierrejoye", - "name": "Pierre Joye", - "avatar_url": "https://avatars.githubusercontent.com/u/282408?v=4", - "profile": "https://github.com/pierrejoye", - "contributions": [ - "code", - "bug", - "ideas", - "test" - ] - }, - { - "login": "Rested", - "name": "Reuben Thomas-Davis", - "avatar_url": "https://avatars.githubusercontent.com/u/2003608?v=4", - "profile": "https://github.com/Rested", - "contributions": [ - "code", - "bug" - ] - }, - { - "login": "mewmew", - "name": "Robin", - "avatar_url": "https://avatars.githubusercontent.com/u/1414531?v=4", - "profile": "https://github.com/mewmew", - "contributions": [ - "code", - "bug" - ] - }, - { - "login": "sebastian0x62", - "name": "Sebastian Bauer", - "avatar_url": "https://avatars.githubusercontent.com/u/70367451?v=4", - "profile": "https://threema.id/YSB3TVF7", - "contributions": [ - "code", - "ideas", - "test", - "review", - "question" - ] - }, - { - "login": "sidwebworks", - "name": "Sidharth Rathi", - "avatar_url": "https://avatars.githubusercontent.com/u/58144379?v=4", - "profile": "https://github.com/sidwebworks", - "contributions": [ - "doc", - "bug" - ] - }, - { - "login": "sithembiso", - "name": "Sithembiso Khumalo", - "avatar_url": "https://avatars.githubusercontent.com/u/6559905?v=4", - "profile": "https://github.com/sithembiso", - "contributions": [ - "code", - "bug" - ] - }, - { - "login": "LanguageAgnostic", - "name": "Soheib El-Harrache", - "avatar_url": "https://avatars.githubusercontent.com/u/19310562?v=4", - "profile": "https://github.com/LanguageAgnostic", - "contributions": [ - "code", - "bug", - "financial" - ] - }, - { - "login": "SophieAu", - "name": "Sophie Au", - "avatar_url": "https://avatars.githubusercontent.com/u/11145039?v=4", - "profile": "https://www.sophieau.com/", - "contributions": [ - "code", - "bug" - ] - }, - { - "login": "stefpap", - "name": "Stefanos Papadakis", - "avatar_url": "https://avatars.githubusercontent.com/u/22637722?v=4", - "profile": "https://github.com/stefpap", - "contributions": [ - "code", - "bug" - ] - }, - { - "login": "s12chung", - "name": "Steve Chung", - "avatar_url": "https://avatars.githubusercontent.com/u/263394?v=4", - "profile": "https://github.com/s12chung", - "contributions": [ - "code", - "bug" - ] - }, - { - "login": "TAINCER", - "name": "Timm Ortloff", - "avatar_url": "https://avatars.githubusercontent.com/u/41272726?v=4", - "profile": "https://tortloff.de/", - "contributions": [ - "doc" - ] - }, - { - "login": "tomanagle", - "name": "Tom", - "avatar_url": "https://avatars.githubusercontent.com/u/8683577?v=4", - "profile": "https://github.com/tomanagle", - "contributions": [ - "code" - ] - }, - { - "login": "ValentinTrinque", - "name": "Valentin Trinqué", - "avatar_url": "https://avatars.githubusercontent.com/u/4662842?v=4", - "profile": "https://www.linkedin.com/in/valentintrinque", - "contributions": [ - "code", - "bug" - ] - }, - { - "login": "mattn", - "name": "mattn", - "avatar_url": "https://avatars.githubusercontent.com/u/10111?v=4", - "profile": "https://mattn.kaoriya.net/", - "contributions": [ - "code", - "bug" - ] - }, - { - "login": "bearsh", - "name": "bearsh", - "avatar_url": "https://avatars.githubusercontent.com/u/1089356?v=4", - "profile": "https://github.com/bearsh", - "contributions": [ - "code", - "ideas", - "doc" - ] - }, - { - "login": "chenxiao1990", - "name": "chenxiao", - "avatar_url": "https://avatars.githubusercontent.com/u/16933565?v=4", - "profile": "https://github.com/chenxiao1990", - "contributions": [ - "code", - "ideas", - "doc" - ] - }, - { - "login": "fengweiqiang", - "name": "fengweiqiang", - "avatar_url": "https://avatars.githubusercontent.com/u/22905300?v=4", - "profile": "https://github.com/fengweiqiang", - "contributions": [ - "code", - "platform" - ] - }, - { - "login": "flin7", - "name": "flin7", - "avatar_url": "https://avatars.githubusercontent.com/u/58138185?v=4", - "profile": "https://github.com/flin7", - "contributions": [ - "doc" - ] - }, - { - "login": "fred21O4", - "name": "fred21O4", - "avatar_url": "https://avatars.githubusercontent.com/u/67189813?v=4", - "profile": "https://github.com/fred21O4", - "contributions": [ - "doc" - ] - }, - { - "login": "gardc", - "name": "gardc", - "avatar_url": "https://avatars.githubusercontent.com/u/41453409?v=4", - "profile": "https://github.com/gardc", - "contributions": [ - "doc", - "tutorial" - ] - }, - { - "login": "rayshoo", - "name": "rayshoo", - "avatar_url": "https://avatars.githubusercontent.com/u/52561899?v=4", - "profile": "https://github.com/rayshoo", - "contributions": [ - "doc" - ] - }, - { - "login": "Yz4230", - "name": "Ishiyama Yuzuki", - "avatar_url": "https://avatars.githubusercontent.com/u/38999742?v=4", - "profile": "https://github.com/Yz4230", - "contributions": [ - "code", - "bug" - ] - }, - { - "login": "Baiyuetribe", - "name": "佰阅", - "avatar_url": "https://avatars.githubusercontent.com/u/43716063?v=4", - "profile": "https://baiyue.one/", - "contributions": [ - "code" - ] - }, - { - "login": "daodao97", - "name": "刀刀", - "avatar_url": "https://avatars.githubusercontent.com/u/15009280?v=4", - "profile": "https://github.com/daodao97", - "contributions": [ - "doc", - "bug" - ] - }, - { - "login": "jicg", - "name": "归位", - "avatar_url": "https://avatars.githubusercontent.com/u/6479672?v=4", - "profile": "https://github.com/jicg", - "contributions": [ - "code", - "bug" - ] - }, - { - "login": "skamensky", - "name": "skamensky", - "avatar_url": "https://avatars.githubusercontent.com/u/19151369?v=4", - "profile": "https://github.com/skamensky", - "contributions": [ - "code", - "ideas", - "doc" - ] - }, - { - "login": "dependabot[bot]", - "name": "dependabot[bot]", - "avatar_url": "https://avatars.githubusercontent.com/in/29110?v=4", - "profile": "https://github.com/apps/dependabot", - "contributions": [ - "code", - "maintenance" - ] - }, - { - "login": "dsieradzki", - "name": "Damian Sieradzki", - "avatar_url": "https://avatars.githubusercontent.com/u/10297559?v=4", - "profile": "https://www.linkedin.com/in/dsieradzki/", - "contributions": [ - "financial" - ] - }, - { - "login": "boostchicken", - "name": "John Dorman", - "avatar_url": "https://avatars.githubusercontent.com/u/427295?v=4", - "profile": "https://github.com/boostchicken", - "contributions": [ - "financial" - ] - }, - { - "login": "iansinnott", - "name": "Ian Sinnott", - "avatar_url": "https://avatars.githubusercontent.com/u/3154865?v=4", - "profile": "https://blog.iansinnott.com/", - "contributions": [ - "financial" - ] - }, - { - "login": "Shackelford-Arden", - "name": "Arden Shackelford", - "avatar_url": "https://avatars.githubusercontent.com/u/7362263?v=4", - "profile": "https://github.com/Shackelford-Arden", - "contributions": [ - "financial" - ] - }, - { - "login": "Bironou", - "name": "Bironou", - "avatar_url": "https://avatars.githubusercontent.com/u/107761511?v=4", - "profile": "https://github.com/Bironou", - "contributions": [ - "financial" - ] - }, - { - "login": "CharlieGo19", - "name": "CharlieGo_", - "avatar_url": "https://avatars.githubusercontent.com/u/62405980?v=4", - "profile": "https://github.com/CharlieGo19", - "contributions": [ - "financial" - ] - }, - { - "login": "overnet", - "name": "overnet", - "avatar_url": "https://avatars.githubusercontent.com/u/6376126?v=4", - "profile": "https://github.com/overnet", - "contributions": [ - "financial" - ] - }, - { - "login": "jugglingjsons", - "name": "jugglingjsons", - "avatar_url": "https://avatars.githubusercontent.com/u/20739064?v=4", - "profile": "https://jugglingjsons.dev/", - "contributions": [ - "financial" - ] - }, - { - "login": "selvindev", - "name": "Selvin Ortiz", - "avatar_url": "https://avatars.githubusercontent.com/u/1922523?v=4", - "profile": "https://selvin.dev/", - "contributions": [ - "financial" - ] - }, - { - "login": "zandercodes", - "name": "ZanderCodes", - "avatar_url": "https://avatars.githubusercontent.com/u/46308805?v=4", - "profile": "https://github.com/zandercodes", - "contributions": [ - "financial" - ] - }, - { - "login": "DonTomato", - "name": "Michael Voronov", - "avatar_url": "https://avatars.githubusercontent.com/u/1098084?v=4", - "profile": "https://github.com/DonTomato", - "contributions": [ - "financial" - ] - }, - { - "login": "letheanVPN", - "name": "letheanVPN", - "avatar_url": "https://avatars.githubusercontent.com/u/83868036?v=4", - "profile": "https://lt.hn/", - "contributions": [ - "financial" - ] - }, - { - "login": "taigrr", - "name": "Tai Groot", - "avatar_url": "https://avatars.githubusercontent.com/u/8261498?v=4", - "profile": "https://taigrr.com/", - "contributions": [ - "financial" - ] - }, - { - "login": "easy-web-it", - "name": "easy-web-it", - "avatar_url": "https://avatars.githubusercontent.com/u/95484991?v=4", - "profile": "https://github.com/easy-web-it", - "contributions": [ - "financial" - ] - }, - { - "login": "michaelolson1996", - "name": "Michael Olson", - "avatar_url": "https://avatars.githubusercontent.com/u/45323107?v=4", - "profile": "https://michaelolson1996.github.io/portfolio", - "contributions": [ - "financial" - ] - }, - { - "login": "EdenNetworkItalia", - "name": "EdenNetwork Italia", - "avatar_url": "https://avatars.githubusercontent.com/u/4912777?v=4", - "profile": "https://eden.network/", - "contributions": [ - "financial" - ] - }, - { - "login": "ondoki", - "name": "ondoki", - "avatar_url": "https://avatars.githubusercontent.com/u/88536792?v=4", - "profile": "https://github.com/ondoki", - "contributions": [ - "financial" - ] - }, - { - "login": "questrail", - "name": "QuEST Rail LLC", - "avatar_url": "https://avatars.githubusercontent.com/u/3536569?v=4", - "profile": "https://github.com/questrail", - "contributions": [ - "financial" - ] - }, - { - "login": "Gilgames000", - "name": "Gilgameš", - "avatar_url": "https://avatars.githubusercontent.com/u/22778436?v=4", - "profile": "https://github.com/Gilgames000", - "contributions": [ - "financial" - ] - }, - { - "login": "bbergshaven", - "name": "Bernt-Johan Bergshaven", - "avatar_url": "https://avatars.githubusercontent.com/u/4091634?v=4", - "profile": "https://github.com/bbergshaven", - "contributions": [ - "financial" - ] - }, - { - "login": "bglw", - "name": "Liam Bigelow", - "avatar_url": "https://avatars.githubusercontent.com/u/40188355?v=4", - "profile": "https://github.com/bglw", - "contributions": [ - "financial" - ] - }, - { - "login": "nickarellano", - "name": "Nick Arellano", - "avatar_url": "https://avatars.githubusercontent.com/u/13930605?v=4", - "profile": "https://github.com/nickarellano", - "contributions": [ - "financial" - ] - }, - { - "login": "fcjr", - "name": "Frank Chiarulli Jr.", - "avatar_url": "https://avatars.githubusercontent.com/u/2053002?v=4", - "profile": "https://github.com/fcjr", - "contributions": [ - "financial" - ] - }, - { - "login": "tylertravisty", - "name": "Tyler", - "avatar_url": "https://avatars.githubusercontent.com/u/8620352?v=4", - "profile": "https://github.com/tylertravisty", - "contributions": [ - "financial" - ] - }, - { - "login": "trea", - "name": "Trea Hauet", - "avatar_url": "https://avatars.githubusercontent.com/u/1181448?v=4", - "profile": "https://github.com/trea", - "contributions": [ - "financial" - ] - }, - { - "login": "picatz", - "name": "Kent 'picat' Gruber", - "avatar_url": "https://avatars.githubusercontent.com/u/14850816?v=4", - "profile": "https://picatz.github.io/", - "contributions": [ - "financial" - ] - }, - { - "login": "tc-hib", - "name": "tc-hib", - "avatar_url": "https://avatars.githubusercontent.com/u/55949036?v=4", - "profile": "https://github.com/tc-hib", - "contributions": [ - "financial" - ] - }, - { - "login": "acheong08", - "name": "Antonio", - "avatar_url": "https://avatars.githubusercontent.com/u/36258159?v=4", - "profile": "https://github.com/acheong08", - "contributions": [ - "doc" - ] - }, - { - "login": "MyNameIsAres", - "name": "MyNameIsAres", - "avatar_url": "https://avatars.githubusercontent.com/u/32432637?v=4", - "profile": "https://github.com/MyNameIsAres", - "contributions": [ - "doc" - ] - }, - { - "login": "Maicarons2022", - "name": "Maicarons J", - "avatar_url": "https://avatars.githubusercontent.com/u/101958587?v=4", - "profile": "http://mai.car.ons", - "contributions": [ - "doc" - ] - }, - { - "login": "KiddoV", - "name": "kiddov", - "avatar_url": "https://avatars.githubusercontent.com/u/28552977?v=4", - "profile": "https://github.com/KiddoV", - "contributions": [ - "doc", - "financial", - "test", - "ideas" - ] - }, - { - "login": "Ilshidur", - "name": "Nicolas Coutin", - "avatar_url": "https://avatars.githubusercontent.com/u/6564012?v=4", - "profile": "https://nicolas-coutin.com/", - "contributions": [ - "financial" - ] - }, - { - "login": "ParvinEyvazov", - "name": "Parvin Eyvazov", - "avatar_url": "https://avatars.githubusercontent.com/u/32189770?v=4", - "profile": "https://github.com/ParvinEyvazov", - "contributions": [ - "doc" - ] - }, - { - "login": "github-actions[bot]", - "name": "github-actions[bot]", - "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", - "profile": "https://github.com/apps/github-actions", - "contributions": [ - "code" - ] - }, - { - "login": "OlegGulevskyy", - "name": "Oleg Gulevskyy", - "avatar_url": "https://avatars.githubusercontent.com/u/43781031?v=4", - "profile": "https://github.com/OlegGulevskyy", - "contributions": [ - "code", - "doc", - "maintenance", - "platform" - ] - }, - { - "login": "raguay", - "name": "Richard Guay", - "avatar_url": "https://avatars.githubusercontent.com/u/2487495?v=4", - "profile": "http://www.customct.com/", - "contributions": [ - "doc" - ] - }, - { - "login": "ATenderholt", - "name": "Adam Tenderholt", - "avatar_url": "https://avatars.githubusercontent.com/u/740623?v=4", - "profile": "https://github.com/ATenderholt", - "contributions": [ - "code" - ] - }, - { - "login": "JulioDRF", - "name": "JulioDRF", - "avatar_url": "https://avatars.githubusercontent.com/u/15677708?v=4", - "profile": "https://github.com/JulioDRF", - "contributions": [ - "code" - ] - }, - { - "login": "scottopell", - "name": "Scott Opell", - "avatar_url": "https://avatars.githubusercontent.com/u/996472?v=4", - "profile": "http://scottopell.com/", - "contributions": [ - "code" - ] - }, - { - "login": "avengerweb", - "name": "Vadim Shchepotev", - "avatar_url": "https://avatars.githubusercontent.com/u/2055581?v=4", - "profile": "https://aven.dev/", - "contributions": [ - "code" - ] - }, - { - "login": "willdot", - "name": "Will Andrews", - "avatar_url": "https://avatars.githubusercontent.com/u/4906530?v=4", - "profile": "https://willdot.net/", - "contributions": [ - "code" - ] - }, - { - "login": "gwynforthewyn", - "name": "Gwyn", - "avatar_url": "https://avatars.githubusercontent.com/u/434656?v=4", - "profile": "https://github.com/gwynforthewyn", - "contributions": [ - "code", - "review", - "question", - "research" - ] - }, - { - "login": "xijaja", - "name": "希嘉嘉", - "avatar_url": "https://avatars.githubusercontent.com/u/47017666?v=4", - "profile": "https://github.com/xijaja", - "contributions": [ - "code" - ] - }, - { - "login": "almas1992", - "name": "ALMAS", - "avatar_url": "https://avatars.githubusercontent.com/u/9382335?v=4", - "profile": "https://www.almas.cc/", - "contributions": [ - "code" - ] - }, - { - "login": "o8x", - "name": "Alex", - "avatar_url": "https://avatars.githubusercontent.com/u/20666153?v=4", - "profile": "https://stdout.com.cn/", - "contributions": [ - "code" - ] - }, - { - "login": "arifali123", - "name": "Arif Ali", - "avatar_url": "https://avatars.githubusercontent.com/u/51419655?v=4", - "profile": "https://github.com/arifali123", - "contributions": [ - "code" - ] - }, - { - "login": "hotafrika", - "name": "Artur Siarohau", - "avatar_url": "https://avatars.githubusercontent.com/u/18332839?v=4", - "profile": "https://github.com/hotafrika", - "contributions": [ - "code" - ] - }, - { - "login": "binyamin", - "name": "Binyamin Aron Green", - "avatar_url": "https://avatars.githubusercontent.com/u/39805353?v=4", - "profile": "https://binyam.in/", - "contributions": [ - "code" - ] - }, - { - "login": "bdwyertech", - "name": "Brian Dwyer", - "avatar_url": "https://avatars.githubusercontent.com/u/2973273?v=4", - "profile": "http://bdwyertech.net/", - "contributions": [ - "code" - ] - }, - { - "login": "ckilb", - "name": "Christian Kilb", - "avatar_url": "https://avatars.githubusercontent.com/u/7283097?v=4", - "profile": "http://www.cilb.de/", - "contributions": [ - "code" - ] - }, - { - "login": "edwargix", - "name": "David Florness", - "avatar_url": "https://avatars.githubusercontent.com/u/22877007?v=4", - "profile": "https://github.com/edwargix", - "contributions": [ - "doc" - ] - }, - { - "login": "BuckeyeCoder", - "name": "David Walton", - "avatar_url": "https://avatars.githubusercontent.com/u/95933880?v=4", - "profile": "https://github.com/BuckeyeCoder", - "contributions": [ - "code" - ] - }, - { - "login": "Debdut", - "name": "Debdut Karmakar", - "avatar_url": "https://avatars.githubusercontent.com/u/7561070?v=4", - "profile": "https://github.com/Debdut", - "contributions": [ - "code" - ] - }, - { - "login": "gotid", - "name": "Dieter Zhu", - "avatar_url": "https://avatars.githubusercontent.com/u/4010854?v=4", - "profile": "https://github.com/gotid", - "contributions": [ - "code" - ] - }, - { - "login": "Holmqvist1990", - "name": "Fredrik Holmqvist", - "avatar_url": "https://avatars.githubusercontent.com/u/22743750?v=4", - "profile": "https://fredrikholmqvist.com/", - "contributions": [ - "code" - ] - }, - { - "login": "giopalma", - "name": "Giovanni Palma", - "avatar_url": "https://avatars.githubusercontent.com/u/33783684?v=4", - "profile": "https://github.com/giopalma", - "contributions": [ - "code" - ] - }, - { - "login": "Nexus26404", - "name": "Hao", - "avatar_url": "https://avatars.githubusercontent.com/u/83110373?v=4", - "profile": "https://github.com/Nexus26404", - "contributions": [ - "code" - ] - }, - { - "login": "i7tsov", - "name": "Igor Sementsov", - "avatar_url": "https://avatars.githubusercontent.com/u/44977153?v=4", - "profile": "https://github.com/i7tsov", - "contributions": [ - "code" - ] - }, - { - "login": "derhasi", - "name": "Johannes Haseitl", - "avatar_url": "https://avatars.githubusercontent.com/u/118502?v=4", - "profile": "https://github.com/derhasi", - "contributions": [ - "code" - ] - }, - { - "login": "joshbuddy", - "name": "Joshua Hull", - "avatar_url": "https://avatars.githubusercontent.com/u/8898?v=4", - "profile": "https://github.com/joshbuddy", - "contributions": [ - "code" - ] - }, - { - "login": "joshm998", - "name": "Joshua Mangiola", - "avatar_url": "https://avatars.githubusercontent.com/u/1779737?v=4", - "profile": "https://github.com/joshm998", - "contributions": [ - "doc" - ] - }, - { - "login": "prurigro", - "name": "Kevin MacMartin", - "avatar_url": "https://avatars.githubusercontent.com/u/1149238?v=4", - "profile": "https://github.com/prurigro", - "contributions": [ - "code" - ] - }, - { - "login": "liang-li-dev", - "name": "Liang Li", - "avatar_url": "https://avatars.githubusercontent.com/u/112530363?v=4", - "profile": "https://github.com/liang-li-dev", - "contributions": [ - "code" - ] - }, - { - "login": "marvinhosea", - "name": "Marvin Collins Hosea", - "avatar_url": "https://avatars.githubusercontent.com/u/7722584?v=4", - "profile": "https://appslab.co.ke/", - "contributions": [ - "code" - ] - }, - { - "login": "mholt", - "name": "Matt Holt", - "avatar_url": "https://avatars.githubusercontent.com/u/1128849?v=4", - "profile": "https://matt.life/", - "contributions": [ - "code" - ] - }, - { - "login": "Gurkengewuerz", - "name": "Niklas", - "avatar_url": "https://avatars.githubusercontent.com/u/10966337?v=4", - "profile": "https://github.com/Gurkengewuerz", - "contributions": [ - "code" - ] - }, - { - "login": "Xhofe", - "name": "Andy Hsu", - "avatar_url": "https://avatars.githubusercontent.com/u/36558727?v=4", - "profile": "https://github.com/Xhofe", - "contributions": [ - "code" - ] - }, - { - "login": "NullCode1337", - "name": "NullCode", - "avatar_url": "https://avatars.githubusercontent.com/u/70959549?v=4", - "profile": "https://github.com/NullCode1337", - "contributions": [ - "code" - ] - }, - { - "login": "oSethoum", - "name": "Oussama Sethoum", - "avatar_url": "https://avatars.githubusercontent.com/u/88779394?v=4", - "profile": "https://github.com/oSethoum", - "contributions": [ - "code" - ] - }, - { - "login": "ParkourLiu", - "name": "ParkourLiu", - "avatar_url": "https://avatars.githubusercontent.com/u/33681340?v=4", - "profile": "https://github.com/ParkourLiu", - "contributions": [ - "code" - ] - }, - { - "login": "zllovesuki", - "name": "Rachel Chen", - "avatar_url": "https://avatars.githubusercontent.com/u/298453?v=4", - "profile": "https://github.com/zllovesuki", - "contributions": [ - "code" - ] - }, - { - "login": "rnice01", - "name": "Rob Nice", - "avatar_url": "https://avatars.githubusercontent.com/u/11394384?v=4", - "profile": "https://github.com/rnice01", - "contributions": [ - "code" - ] - }, - { - "login": "RyoTagami", - "name": "Ryo TAGAMI", - "avatar_url": "https://avatars.githubusercontent.com/u/9672589?v=4", - "profile": "https://github.com/RyoTagami", - "contributions": [ - "code" - ] - }, - { - "login": "SamHennessy", - "name": "Sam Hennessy", - "avatar_url": "https://avatars.githubusercontent.com/u/119867?v=4", - "profile": "https://github.com/SamHennessy", - "contributions": [ - "code" - ] - }, - { - "login": "AlbinoDrought", - "name": "Sean", - "avatar_url": "https://avatars.githubusercontent.com/u/852873?v=4", - "profile": "https://albinodrought.com/", - "contributions": [ - "code" - ] - }, - { - "login": "sgosiaco", - "name": "Sean Gosiaco", - "avatar_url": "https://avatars.githubusercontent.com/u/212341?v=4", - "profile": "https://github.com/sgosiaco", - "contributions": [ - "code" - ] - }, - { - "login": "SheetJSDev", - "name": "Eric P Sheets", - "avatar_url": "https://avatars.githubusercontent.com/u/6070939?v=4", - "profile": "https://sheetjs.com/", - "contributions": [ - "code" - ] - }, - { - "login": "SupianIDz", - "name": "Supian M", - "avatar_url": "https://avatars.githubusercontent.com/u/37969970?v=4", - "profile": "https://www.octopy.dev/", - "contributions": [ - "code" - ] - }, - { - "login": "Watson-Sei", - "name": "Watson-Sei", - "avatar_url": "https://avatars.githubusercontent.com/u/55475145?v=4", - "profile": "https://github.com/Watson-Sei", - "contributions": [ - "code", - "doc" - ] - }, - { - "login": "shinshin86", - "name": "Yuki Shindo", - "avatar_url": "https://avatars.githubusercontent.com/u/8216064?v=4", - "profile": "https://shinshin86.com/", - "contributions": [ - "code" - ] - }, - { - "login": "cuigege", - "name": "cuigege", - "avatar_url": "https://avatars.githubusercontent.com/u/26080122?v=4", - "profile": "https://github.com/cuigege", - "contributions": [ - "code" - ] - }, - { - "login": "cybertramp", - "name": "cybertramp", - "avatar_url": "https://avatars.githubusercontent.com/u/30935096?v=4", - "profile": "https://cybertramp.net/", - "contributions": [ - "code" - ] - }, - { - "login": "h8gi", - "name": "hiroki yagi", - "avatar_url": "https://avatars.githubusercontent.com/u/10811057?v=4", - "profile": "https://github.com/h8gi", - "contributions": [ - "code" - ] - }, - { - "login": "imgbot[bot]", - "name": "imgbot[bot]", - "avatar_url": "https://avatars.githubusercontent.com/in/4706?v=4", - "profile": "https://github.com/apps/imgbot", - "contributions": [ - "code" - ] - }, - { - "login": "tong3jie", - "name": "juju", - "avatar_url": "https://avatars.githubusercontent.com/u/14191774?v=4", - "profile": "https://github.com/tong3jie", - "contributions": [ - "code" - ] - }, - { - "login": "meatherly", - "name": "Michael Eatherly", - "avatar_url": "https://avatars.githubusercontent.com/u/1327960?v=4", - "profile": "http://meatherly.github.io/", - "contributions": [ - "code" - ] - }, - { - "login": "tk103331", - "name": "tk", - "avatar_url": "https://avatars.githubusercontent.com/u/4404609?v=4", - "profile": "https://github.com/tk103331", - "contributions": [ - "code" - ] - }, - { - "login": "allcontributors[bot]", - "name": "allcontributors[bot]", - "avatar_url": "https://avatars.githubusercontent.com/in/23186?v=4", - "profile": "https://github.com/apps/allcontributors", - "contributions": [ - "doc" - ] - }, - { - "login": "wandercn", - "name": "wander", - "avatar_url": "https://avatars.githubusercontent.com/u/77320953?v=4", - "profile": "https://www.ffactory.org/", - "contributions": [ - "doc" - ] - } - ], - "contributorsPerLine": 8, - "projectName": "wails", - "projectOwner": "wailsapp", - "repoType": "github", - "repoHost": "https://github.com", - "skipCi": true, - "commitConvention": "none" -} diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 000000000..6b6c2075e --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +runtime/assets/default.html \ No newline at end of file diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 000000000..570dfef81 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,30 @@ +{ + "env": { + "browser": true, + "es6": true, + "node": true, + }, + "extends": "eslint:recommended", + "parserOptions": { + "ecmaVersion": 2016, + "sourceType": "module", + }, + "rules": { + "indent": [ + "error", + "tab" + ], + "linebreak-style": [ + "error", + "unix" + ], + "quotes": [ + "error", + "single" + ], + "semi": [ + "error", + "always" + ] + } +} \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..8fad79124 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,41 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: bug +assignees: '' + +--- + +##################################################### + **If you have a technical issue, please do not open a bug this way!** + Please use the `wails issue` command! + If you do not do this then the issue may be closed automatically. + + NOTE: If your bug is related to Windows, make sure you read + the [Windows Developer Guide](https://wails.app/guides/windows/) +##################################################### + +**Description** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behaviour: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behaviour** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**System Details** +Please provide your platform, GO version and variables, etc + +**Additional context** +Add any other context about the problem here. + +- [ ] This issue is for Windows and I have read the [Windows Developer Guide](https://wails.app/guides/windows/) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml deleted file mode 100644 index 9faf71704..000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ /dev/null @@ -1,87 +0,0 @@ -name: Bug Report -description: Create a report to help us improve -# title: "" -labels: ["Bug"] - -body: - - type: markdown - attributes: - value: | - ***Please note: No bug reports are currently being accepted for Wails v3*** - Before submitting this issue, please do the following: - - Do a web search for your error. This usually leads to a much better understanding of the issue. - - Prove that the error is indeed a Wails bug and not an application bug, with a specific set of steps to reproduce. - - Search the issue tracker using [this link](https://github.com/wailsapp/wails/issues?q=is%3Aissue+). - - Search the [discussion forums](https://github.com/wailsapp/wails/discussions?discussions_q=type+your+issue+here). - - Read the [Troubleshooting Guide](https://wails.io/docs/next/guides/troubleshooting). - - Create a [Minimal Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example) and link to it in the issue. - - If your issue is related to TypeScript generation, please open a ticket and create a PR with a failing test case. - TS tests can be found [here](https://github.com/wailsapp/wails/tree/master/v2/internal/binding/binding_test). Remember to add - your test to the `binding_test.go` file. - - Try to fix it yourself. Keep a list of things you have done to fix the problem. - - If after doing all the above, the problem remains, please continue with this ticket providing *all* the information requested. - - Bug reports that do not follow these steps will likely be closed, so please help us to help you. - - - type: textarea - id: description - attributes: - label: Description - description: A clear and concise description of what the bug is. - placeholder: A clear and concise description of what the bug is. - # value: "" - validations: - required: true - - type: textarea - id: reproduce - attributes: - label: To Reproduce - description: Steps to reproduce the behaviour - placeholder: | - 1. Go to '...' - 2. Click on '....' - 3. Scroll down to '....' - 4. See error - validations: - required: true - - type: textarea - id: expected-behaviour - attributes: - label: Expected behaviour - description: A clear and concise description of what you expected to happen. - placeholder: A clear and concise description of what you expected to happen. - validations: - required: true - - type: textarea - id: screenshots - attributes: - label: Screenshots - description: If applicable, add screenshots to help explain your problem. - placeholder: If applicable, add screenshots to help explain your problem. - validations: - required: false - - type: textarea - id: attempted-fixes - attributes: - label: Attempted Fixes - description: A list of things you have tried to fix the problem, including search engine links. - placeholder: A list of things you have tried to fix the problem, including search engine links. - validations: - required: false - - type: textarea - id: systemdetails - attributes: - label: System Details - description: Please add the output of `wails doctor`. - render: shell - validations: - required: true - - type: textarea - id: additional-context - attributes: - label: Additional context - description: Add any other context about the problem here. - placeholder: Add any other context about the problem here. - validations: - required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index e3632ecaa..000000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,9 +0,0 @@ -blank_issues_enabled: true -contact_links: - - name: Discord Chat - url: https://discord.gg/BrRSWTaxVK - about: Ask questions and discuss with other Wails users in real time. - - - name: GitHub Community Discussions - url: https://github.com/wailsapp/wails/discussions - about: If your question is not a feature or a bug, please go to the discussion panel and retrieve if your question already exists before submitting. diff --git a/.github/ISSUE_TEMPLATE/documentation.yml b/.github/ISSUE_TEMPLATE/documentation.yml deleted file mode 100644 index c1259587b..000000000 --- a/.github/ISSUE_TEMPLATE/documentation.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: Documentation -description: Report an issue related to documentation. -# title: "" -labels: ["Documentation"] - -body: - - type: markdown - attributes: - value: | - This template is only used for documentation related requests, including: - - - Log undocumented APIs - - Update link - - Documentation other than non-project code - - Add new language - - If you followed the documentation but things don't work, take some time to consider if it's the documentation or the code that's wrong. In the latter, prefer using the "[Bug Report](https://github.com/wailsapp/wails/issues/new?assignees=&labels=bug&template=bug_report.yml)" template. - - - type: checkboxes - attributes: - label: Have you read the Documentation Contribution Guidelines? - options: - - label: I have read the [Documentation Contribution Guidelines](https://wails.io/community-guide#ways-of-contributing). - required: true - - - type: textarea - attributes: - label: Description - description: A clear and concise description of what the issue is. - validations: - required: true - - - type: checkboxes - attributes: - label: Self-service - description: | - If you feel like you could contribute to this issue, please check the box below. This would tell us and other people looking for contributions that someone's working on it. - If you do check this box, please send a pull request within 7 days so we can still delegate this to someone else. - options: - - label: I'd be willing to address this documentation request myself. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..11fc491ef --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml deleted file mode 100644 index b346c0bdc..000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: Feature request -description: Suggest an idea for this project -# title: "" -labels: ["Enhancement"] - -body: - - type: markdown - attributes: - value: | - Before opening a feature request, please check the [Roadmap](https://github.com/wailsapp/wails/discussions/1484) to see if it has already been requested. - ***Please note: No new feature requests are being accepted for Wails v1*** - - - type: textarea - attributes: - label: Is your feature request related to a problem? Please describe. - description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - validations: - required: false - - - type: textarea - attributes: - label: Describe the solution you'd like - description: A clear and concise description of what you want to happen. - validations: - required: true - - - type: textarea - attributes: - label: Describe alternatives you've considered - description: A clear and concise description of any alternative solutions or features you've considered. - validations: - required: false - - - type: textarea - attributes: - label: Additional context - description: Add any other context or screenshots about the feature request here. - validations: - required: false \ No newline at end of file diff --git a/.github/file-labeler.yml b/.github/file-labeler.yml deleted file mode 100644 index 69494cbae..000000000 --- a/.github/file-labeler.yml +++ /dev/null @@ -1,44 +0,0 @@ -# File path specific labels -v2-only: - - 'v2/**/*' - -v3-alpha: - - 'v3/**/*' - -windows: - - '**/*_windows.go' - - 'v2/internal/frontend/desktop/windows/**/*' - -macos: - - '**/*_darwin.go' - - 'v2/internal/frontend/desktop/darwin/**/*' - -linux: - - '**/*_linux.go' - - 'v2/internal/frontend/desktop/linux/**/*' - -cli: - - 'v2/cmd/**/*' - - 'v3/cmd/**/*' - - '**/cli/**/*' - - '**/commands/**/*' - -documentation: - - '**/*.md' - - 'docs/**/*' - - 'website/**/*' - - 'mkdocs-website/**/*' - -templates: - - '**/templates/**/*' - - '**/template/**/*' - -runtime: - - '**/runtime/**/*' - - 'v2/internal/runtime/**/*' - - 'v3/internal/runtime/**/*' - -bindings: - - 'v2/internal/binding/**/*' - - 'v3/internal/generator/**/*' - diff --git a/.github/issue-labeler.yml b/.github/issue-labeler.yml deleted file mode 100644 index 0a7949051..000000000 --- a/.github/issue-labeler.yml +++ /dev/null @@ -1,144 +0,0 @@ -# Version labels -v2-only: - - '\[v2\]' - - '\(v2\)' - - 'v2:' - - 'version 2' - - 'wails v2' - - 'using v2' - - 'master branch' - -v3-alpha: - - '\[v3\]' - - '\(v3\)' - - 'v3:' - - '\[v3-alpha\]' - - '\(v3-alpha\)' - - 'version 3' - - 'wails v3' - - 'using v3' - - 'v3-alpha branch' - -# Component labels -webview2: - - 'webview2' - - 'windows' - - 'microsoft edge' - - 'edge browser' - - 'IE' - - 'Explorer' - - 'browser crashes' - -macos: - - 'macOS' - - 'mac OS' - - 'OS X' - - 'darwin' - - 'cocoa' - - 'Safari' - - 'Catalyst' - - 'Ventura' - - 'Sonoma' - - 'apple' - -linux: - - 'linux' - - 'ubuntu' - - 'debian' - - 'fedora' - - 'gtk' - - 'webkitgtk' - - 'webkit2gtk' - - 'gnome' - - 'x11' - - 'wayland' - -cli: - - 'cli' - - 'command line' - - 'wails doctor' - - 'wails init' - - 'wails build' - - 'wails dev' - - 'template' - - 'scaffolding' - -# Type labels -bug: - - 'bug' - - 'crash' - - 'broken' - - 'failure' - - 'error' - - 'failed' - - 'panic' - - 'segfault' - - 'issue' - - 'not working' - - 'problem' - -enhancement: - - 'feature' - - 'enhancement' - - 'request' - - 'add' - - 'new' - - 'improve' - - 'functionality' - - 'support for' - - 'please add' - - 'would be nice' - -documentation: - - 'docs' - - 'documentation' - - 'readme' - - 'example' - - 'tutorial' - - 'guide' - - 'explanation' - - 'clarification' - - 'instructions' - -security: - - 'security' - - 'vulnerability' - - 'exploit' - - 'hack' - - 'CVE' - - 'secure' - - 'encryption' - - 'hardening' - -performance: - - 'performance' - - 'slow' - - 'speed' - - 'memory leak' - - 'cpu usage' - - 'high memory' - - 'lag' - - 'freeze' - - 'optimization' - -# Priority labels -high-priority: - - 'urgent' - - 'critical' - - 'security' - - 'high priority' - - 'important' - - 'production' - - 'blocker' - - 'blocking' - -question: - - 'how to' - - 'how do i' - - 'can I' - - 'is it possible' - - 'question' - - 'help me' - - 'need help' - - 'assistance' - - 'confused' diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md deleted file mode 100644 index d73efffa8..000000000 --- a/.github/pull_request_template.md +++ /dev/null @@ -1,57 +0,0 @@ - - - -# Description - -Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. - -Fixes # (issue) - -## Type of change - -Please select the option that is relevant. - -- [ ] Bug fix (non-breaking change which fixes an issue) -- [ ] New feature (non-breaking change which adds functionality) -- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) -- [ ] This change requires a documentation update - -# How Has This Been Tested? - -Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration using `wails doctor`. - -- [ ] Windows -- [ ] macOS -- [ ] Linux - -If you checked Linux, please specify the distro and version. - -## Test Configuration - -Please paste the output of `wails doctor`. If you are unable to run this command, please describe your environment in as much detail as possible. - -# Checklist: - -- [ ] I have updated `website/src/pages/changelog.mdx` with details of this PR -- [ ] My code follows the general coding style of this project -- [ ] I have performed a self-review of my own code -- [ ] I have commented my code, particularly in hard-to-understand areas -- [ ] I have made corresponding changes to the documentation -- [ ] My changes generate no new warnings -- [ ] I have added tests that prove my fix is effective or that my feature works -- [ ] New and existing unit tests pass locally with my changes diff --git a/.github/stale.yml b/.github/stale.yml index d8bcc83ec..5d7a12a8c 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -1,36 +1,19 @@ # Number of days of inactivity before an issue becomes stale -daysUntilStale: 45 +daysUntilStale: 30 # Number of days of inactivity before a stale issue is closed -daysUntilClose: 10 +daysUntilClose: 7 # Issues with these labels will never be considered stale exemptLabels: - pinned - security - onhold - inprogress - - "Selected For Development" - - bug - - enhancement - - v3-alpha - - high-priority # Label to use when marking an issue as stale -staleLabel: "stale" +staleLabel: wontfix # Comment to post when marking an issue as stale. Set to `false` to disable markComment: > This issue has been automatically marked as stale because it has not had - recent activity. It will be closed if no further activity occurs within the next 10 days. - - If this issue is still relevant, please add a comment to keep it open. - Thank you for your contributions. + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. # Comment to post when closing a stale issue. Set to `false` to disable -closeComment: > - This issue has been automatically closed due to lack of activity. - Please feel free to reopen it if it's still relevant. -exemptMilestones: true -exemptAssignees: true -# Only mark issues (not PRs) -only: issues -# Exempt issues created before a certain date -exemptCreatedBefore: "2024-01-01T00:00:00Z" -# Starts checking issues only after the specified date -startDate: "2025-06-01T00:00:00Z" +closeComment: false \ No newline at end of file diff --git a/.github/workflows/auto-label-issues.yml b/.github/workflows/auto-label-issues.yml deleted file mode 100644 index 3d7a86450..000000000 --- a/.github/workflows/auto-label-issues.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: Auto Label Issues - -on: - issues: - types: [opened, edited, reopened] - pull_request: - types: [opened, edited, reopened, synchronize] - -jobs: - auto-label: - runs-on: ubuntu-latest - permissions: - issues: write - pull-requests: write - contents: read - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - - name: Label issues and PRs by content - uses: github/issue-labeler@v3.4 - with: - repo-token: "${{ secrets.GITHUB_TOKEN }}" - configuration-path: .github/issue-labeler.yml - enable-versioned-regex: 0 - include-title: 1 - - - name: Label issues and PRs by file paths - uses: actions/labeler@v4 - with: - repo-token: "${{ secrets.GITHUB_TOKEN }}" - configuration-path: .github/file-labeler.yml - sync-labels: true diff --git a/.github/workflows/build-and-test-v3.yml b/.github/workflows/build-and-test-v3.yml deleted file mode 100644 index bfcef85a3..000000000 --- a/.github/workflows/build-and-test-v3.yml +++ /dev/null @@ -1,201 +0,0 @@ -name: Build + Test v3 - -on: - pull_request: - types: [opened, synchronize, reopened, ready_for_review] - branches: - - v3-alpha - paths: - - 'v3/**' - pull_request_review: - types: [submitted] - branches: - - v3-alpha - -jobs: - check_approval: - name: Check PR Approval - runs-on: ubuntu-latest - if: github.base_ref == 'v3-alpha' - outputs: - approved: ${{ steps.check.outputs.approved }} - steps: - - name: Check if PR is approved - id: check - run: | - if [[ "${{ github.event.review.state }}" == "approved" || "${{ github.event.pull_request.approved }}" == "true" ]]; then - echo "approved=true" >> $GITHUB_OUTPUT - else - echo "approved=false" >> $GITHUB_OUTPUT - fi - - test_go: - name: Run Go Tests v3 - needs: check_approval - runs-on: ${{ matrix.os }} - if: github.base_ref == 'v3-alpha' - strategy: - fail-fast: false - matrix: - os: [windows-latest, ubuntu-latest, macos-latest] - go-version: [1.24] - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Install linux dependencies - uses: awalsh128/cache-apt-pkgs-action@latest - if: matrix.os == 'ubuntu-latest' - with: - packages: libgtk-3-dev libwebkit2gtk-4.1-dev build-essential pkg-config xvfb x11-xserver-utils at-spi2-core xdg-desktop-portal-gtk - version: 1.0 - - - name: Setup Go - uses: actions/setup-go@v5 - with: - go-version: ${{ matrix.go-version }} - cache-dependency-path: "v3/go.sum" - - - name: Install Task - uses: arduino/setup-task@v2 - with: - version: 3.x - repo-token: ${{ secrets.GITHUB_TOKEN }} - - - name: Build Examples - working-directory: v3 - run: task test:examples - - - name: Run tests (mac) - if: matrix.os == 'macos-latest' - env: - CGO_LDFLAGS: -framework UniformTypeIdentifiers -mmacosx-version-min=10.13 - working-directory: v3 - run: go test -v ./... - - - name: Run tests (windows) - if: matrix.os == 'windows-latest' - working-directory: v3 - run: go test -v ./... - - - name: Run tests (ubuntu) - if: matrix.os == 'ubuntu-latest' - working-directory: v3 - run: > - xvfb-run --auto-servernum - sh -c ' - dbus-update-activation-environment --systemd --all && - go test -v ./... - ' - - - name: Typecheck binding generator output - working-directory: v3 - run: task generator:test:check - - test_js: - name: Run JS Tests - needs: check_approval - runs-on: ubuntu-latest - if: github.base_ref == 'v3-alpha' - strategy: - matrix: - node-version: [20.x] - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - - - name: Install dependencies - run: npm install - working-directory: v2/internal/frontend/runtime - - - name: Run tests - run: npm test - working-directory: v2/internal/frontend/runtime - - test_templates: - name: Test Templates - needs: test_go - runs-on: ${{ matrix.os }} - if: github.base_ref == 'v3-alpha' - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - template: - - svelte - - svelte-ts - - vue - - vue-ts - - react - - react-ts - - preact - - preact-ts - - lit - - lit-ts - - vanilla - - vanilla-ts - go-version: [1.24] - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Install linux dependencies - uses: awalsh128/cache-apt-pkgs-action@latest - if: matrix.os == 'ubuntu-latest' - with: - packages: libgtk-3-dev libwebkit2gtk-4.1-dev build-essential pkg-config - version: 1.0 - - - name: Setup Go - uses: actions/setup-go@v5 - with: - go-version: ${{ matrix.go-version }} - cache-dependency-path: "v3/go.sum" - - - name: Install Task - uses: arduino/setup-task@v2 - with: - version: 3.x - repo-token: ${{ secrets.GITHUB_TOKEN }} - - - name: Build Wails3 CLI - working-directory: v3 - run: | - task install - wails3 doctor - - - name: Generate template '${{ matrix.template }}' - run: | - mkdir -p ./test-${{ matrix.template }} - cd ./test-${{ matrix.template }} - wails3 init -n ${{ matrix.template }} -t ${{ matrix.template }} - cd ${{ matrix.template }} - wails3 build - - build_results: - if: ${{ always() }} - runs-on: ubuntu-latest - name: v3 Build Results - needs: [test_go, test_js, test_templates] - steps: - - run: | - go_result="${{ needs.test_go.result }}" - js_result="${{ needs.test_js.result }}" - templates_result="${{ needs.test_templates.result }}" - - if [[ $go_result == "success" || $go_result == "skipped" ]] && \ - [[ $js_result == "success" || $js_result == "skipped" ]] && \ - [[ $templates_result == "success" || $templates_result == "skipped" ]]; then - echo "All required jobs succeeded or were skipped" - exit 0 - else - echo "One or more required jobs failed" - exit 1 - fi \ No newline at end of file diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml deleted file mode 100644 index 8fe647c6f..000000000 --- a/.github/workflows/build-and-test.yml +++ /dev/null @@ -1,160 +0,0 @@ -name: Build + Test v2 - -on: - push: - branches: [release/*, master, bugfix/*] - workflow_dispatch: - -jobs: - test_go: - name: Run Go Tests - if: github.repository == 'wailsapp/wails' - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-22.04, ubuntu-24.04, windows-latest, macos-latest] - go-version: ['1.22'] - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - uses: awalsh128/cache-apt-pkgs-action@latest - if: matrix.os == 'ubuntu-22.04' - with: - packages: libgtk-3-dev libwebkit2gtk-4.0-dev build-essential pkg-config - version: 1.0 - - - uses: awalsh128/cache-apt-pkgs-action@latest - if: matrix.os == 'ubuntu-24.04' - with: - packages: libgtk-3-dev libwebkit2gtk-4.1-dev build-essential pkg-config libegl1 - version: 1.0 - - - name: Setup Go - uses: actions/setup-go@v4 - with: - go-version: ${{ matrix.go-version }} - cache-dependency-path: ./v2/go.sum - - - name: Run tests (mac) - if: matrix.os == 'macos-latest' - env: - CGO_LDFLAGS: -framework UniformTypeIdentifiers -mmacosx-version-min=10.13 - working-directory: ./v2 - run: go test -v ./... - - - name: Run tests (!mac) - if: matrix.os != 'macos-latest' && matrix.os != 'ubuntu-24.04' - working-directory: ./v2 - run: go test -v ./... - - - name: Run tests (Ubuntu 24.04) - if: matrix.os == 'ubuntu-24.04' - working-directory: ./v2 - run: go test -v -tags webkit2_41 ./... - - test_js: - name: Run JS Tests - if: github.repository == 'wailsapp/wails' - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [20.x] - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - - - name: Install dependencies - run: npm install - working-directory: v2/internal/frontend/runtime - - - name: Run tests - run: npm test - working-directory: v2/internal/frontend/runtime - - test_templates: - name: Test Templates - needs: test_go - runs-on: ${{ matrix.os }} - strategy: - fail-fast: true - matrix: - os: [ubuntu-22.04, windows-latest, macos-latest, ubuntu-24.04] - template: - [ - svelte, - svelte-ts, - vue, - vue-ts, - react, - react-ts, - preact, - preact-ts, - lit, - lit-ts, - vanilla, - vanilla-ts, - plain, - ] - go-version: ['1.22'] - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Go - uses: actions/setup-go@v5 - with: - go-version: ${{ matrix.go-version }} - cache-dependency-path: ./v2/go.sum - - - name: Build Wails CLI - run: | - cd ./v2/cmd/wails - go install - wails -help - - - uses: awalsh128/cache-apt-pkgs-action@latest - if: matrix.os == 'ubuntu-22.04' - with: - packages: libgtk-3-dev libwebkit2gtk-4.0-dev build-essential pkg-config - version: 1.0 - -# - name: Install linux dependencies ( 22.04 ) -# if: matrix.os == 'ubuntu-22.04' -# run: sudo apt-get update -y && sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev build-essential pkg-config - - - uses: awalsh128/cache-apt-pkgs-action@latest - if: matrix.os == 'ubuntu-24.04' - with: - packages: libgtk-3-dev libwebkit2gtk-4.1-dev build-essential pkg-config libegl1 - version: 1.0 - -# - name: Install linux dependencies ( 24.04 ) -# if: matrix.os == 'ubuntu-24.04' -# run: sudo apt-get update -y && sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev build-essential pkg-config - - - name: Generate & Build template '${{ matrix.template }}' - if: matrix.os != 'ubuntu-24.04' - run: | - mkdir -p ./test-${{ matrix.template }} - cd ./test-${{ matrix.template }} - wails init -n ${{ matrix.template }} -t ${{ matrix.template }} -ci - cd ${{ matrix.template }} - wails build -v 2 - - - name: Generate & Build template '${{ matrix.template }}' (ubuntu-24.04) - if: matrix.os == 'ubuntu-24.04' - run: | - mkdir -p ./test-${{ matrix.template }} - cd ./test-${{ matrix.template }} - wails init -n ${{ matrix.template }} -t ${{ matrix.template }} -ci - cd ${{ matrix.template }} - wails build -v 2 -tags webkit2_41 - diff --git a/.github/workflows/build-cross-image.yml b/.github/workflows/build-cross-image.yml deleted file mode 100644 index 83b40f2be..000000000 --- a/.github/workflows/build-cross-image.yml +++ /dev/null @@ -1,423 +0,0 @@ -name: Build Cross-Compiler Image - -on: - workflow_dispatch: - inputs: - branch: - description: 'Branch containing Dockerfile' - required: true - default: 'v3-alpha' - sdk_version: - description: 'macOS SDK version' - required: true - default: '14.5' - zig_version: - description: 'Zig version' - required: true - default: '0.14.0' - image_version: - description: 'Image version tag' - required: true - default: 'latest' - skip_tests: - description: 'Skip cross-compilation tests' - required: false - default: 'false' - type: boolean - push: - branches: - - v3-alpha - paths: - - 'v3/internal/commands/build_assets/docker/Dockerfile.cross' - -env: - REGISTRY: ghcr.io - IMAGE_NAME: wailsapp/wails-cross - -jobs: - build: - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - outputs: - image_tag: ${{ steps.vars.outputs.image_version }} - - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - ref: ${{ inputs.branch || github.ref }} - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Log in to Container Registry - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Set build variables - id: vars - run: | - echo "sdk_version=${{ inputs.sdk_version || '14.5' }}" >> $GITHUB_OUTPUT - echo "zig_version=${{ inputs.zig_version || '0.14.0' }}" >> $GITHUB_OUTPUT - echo "image_version=${{ inputs.image_version || 'latest' }}" >> $GITHUB_OUTPUT - - - name: Extract metadata - id: meta - uses: docker/metadata-action@v5 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - tags: | - type=raw,value=latest - type=raw,value=${{ steps.vars.outputs.image_version }} - type=raw,value=sdk-${{ steps.vars.outputs.sdk_version }} - - - name: Build and push - uses: docker/build-push-action@v5 - with: - context: v3/internal/commands/build_assets/docker - file: v3/internal/commands/build_assets/docker/Dockerfile.cross - platforms: linux/amd64,linux/arm64 - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: | - ${{ steps.meta.outputs.labels }} - io.wails.zig.version=${{ steps.vars.outputs.zig_version }} - io.wails.sdk.version=${{ steps.vars.outputs.sdk_version }} - build-args: | - ZIG_VERSION=${{ steps.vars.outputs.zig_version }} - MACOS_SDK_VERSION=${{ steps.vars.outputs.sdk_version }} - cache-from: type=gha - cache-to: type=gha,mode=max - - # Test cross-compilation for all platforms - test-cross-compile: - needs: build - if: ${{ inputs.skip_tests != 'true' }} - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - include: - # Darwin targets (Zig + macOS SDK) - no platform emulation needed - - os: darwin - arch: arm64 - platform: "" - expected_file: "Mach-O 64-bit.*arm64" - - os: darwin - arch: amd64 - platform: "" - expected_file: "Mach-O 64-bit.*x86_64" - # Linux targets (GCC) - need platform to match architecture - - os: linux - arch: amd64 - platform: "linux/amd64" - expected_file: "ELF 64-bit LSB.*x86-64" - - os: linux - arch: arm64 - platform: "linux/arm64" - expected_file: "ELF 64-bit LSB.*ARM aarch64" - # Windows targets (Zig + mingw) - no platform emulation needed - - os: windows - arch: amd64 - platform: "" - expected_file: "PE32\\+ executable.*x86-64" - - os: windows - arch: arm64 - platform: "" - expected_file: "PE32\\+ executable.*Aarch64" - - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - ref: ${{ inputs.branch || github.ref }} - - - name: Set up QEMU - if: matrix.platform != '' - uses: docker/setup-qemu-action@v3 - - - name: Log in to Container Registry - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Create test CGO project - run: | - mkdir -p test-project - cd test-project - - # Create a minimal CGO test program - cat > main.go << 'EOF' - package main - - /* - #include - - int add(int a, int b) { - return a + b; - } - */ - import "C" - import "fmt" - - func main() { - result := C.add(1, 2) - fmt.Printf("CGO test: 1 + 2 = %d\n", result) - } - EOF - - cat > go.mod << 'EOF' - module test-cgo - - go 1.21 - EOF - - - name: Build ${{ matrix.os }}/${{ matrix.arch }} (CGO) - run: | - cd test-project - PLATFORM_FLAG="" - if [ -n "${{ matrix.platform }}" ]; then - PLATFORM_FLAG="--platform ${{ matrix.platform }}" - fi - - docker run --rm $PLATFORM_FLAG \ - -v "$(pwd):/app" \ - -e APP_NAME="test-cgo" \ - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.build.outputs.image_tag || 'latest' }} \ - ${{ matrix.os }} ${{ matrix.arch }} - - - name: Verify binary format - run: | - cd test-project/bin - ls -la - - # Find the built binary - if [ "${{ matrix.os }}" = "windows" ]; then - BINARY=$(ls test-cgo-${{ matrix.os }}-${{ matrix.arch }}.exe 2>/dev/null || ls *.exe | head -1) - else - BINARY=$(ls test-cgo-${{ matrix.os }}-${{ matrix.arch }} 2>/dev/null || ls test-cgo* | grep -v '.exe' | head -1) - fi - - echo "Binary: $BINARY" - FILE_OUTPUT=$(file "$BINARY") - echo "File output: $FILE_OUTPUT" - - # Verify the binary format matches expected - if echo "$FILE_OUTPUT" | grep -qE "${{ matrix.expected_file }}"; then - echo "✅ Binary format verified: ${{ matrix.os }}/${{ matrix.arch }}" - else - echo "❌ Binary format mismatch!" - echo "Expected pattern: ${{ matrix.expected_file }}" - echo "Got: $FILE_OUTPUT" - exit 1 - fi - - - name: Check library dependencies (Linux only) - if: matrix.os == 'linux' - run: | - cd test-project/bin - BINARY=$(ls test-cgo-${{ matrix.os }}-${{ matrix.arch }} 2>/dev/null || ls test-cgo* | grep -v '.exe' | head -1) - - echo "## Library Dependencies for $BINARY" - echo "" - - # Use readelf to show dynamic dependencies - echo "### NEEDED libraries:" - readelf -d "$BINARY" | grep NEEDED || echo "No dynamic dependencies (statically linked)" - - # Verify expected libraries are linked - echo "" - echo "### Verifying required libraries..." - NEEDED=$(readelf -d "$BINARY" | grep NEEDED) - - MISSING="" - for lib in libwebkit2gtk-4.1.so libgtk-3.so libglib-2.0.so libc.so; do - if echo "$NEEDED" | grep -q "$lib"; then - echo "✅ $lib" - else - echo "❌ $lib MISSING" - MISSING="$MISSING $lib" - fi - done - - if [ -n "$MISSING" ]; then - echo "" - echo "ERROR: Missing required libraries:$MISSING" - exit 1 - fi - - # Test non-CGO builds (pure Go cross-compilation) - test-non-cgo: - needs: build - if: ${{ inputs.skip_tests != 'true' }} - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - include: - - os: darwin - arch: arm64 - expected_file: "Mach-O 64-bit.*arm64" - - os: darwin - arch: amd64 - expected_file: "Mach-O 64-bit.*x86_64" - - os: linux - arch: amd64 - expected_file: "ELF 64-bit LSB" - - os: linux - arch: arm64 - expected_file: "ELF 64-bit LSB.*ARM aarch64" - - os: windows - arch: amd64 - expected_file: "PE32\\+ executable.*x86-64" - - os: windows - arch: arm64 - expected_file: "PE32\\+ executable.*Aarch64" - - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - ref: ${{ inputs.branch || github.ref }} - - - name: Log in to Container Registry - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Create test non-CGO project - run: | - mkdir -p test-project - cd test-project - - # Create a pure Go test program (no CGO) - cat > main.go << 'EOF' - package main - - import "fmt" - - func main() { - fmt.Println("Pure Go cross-compilation test") - } - EOF - - cat > go.mod << 'EOF' - module test-pure-go - - go 1.21 - EOF - - - name: Build ${{ matrix.os }}/${{ matrix.arch }} (non-CGO) - run: | - cd test-project - - # For non-CGO, we can use any platform since Go handles cross-compilation - # We set CGO_ENABLED=0 to ensure pure Go build - docker run --rm \ - -v "$(pwd):/app" \ - -e APP_NAME="test-pure-go" \ - -e CGO_ENABLED=0 \ - --entrypoint /bin/sh \ - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.build.outputs.image_tag || 'latest' }} \ - -c "GOOS=${{ matrix.os }} GOARCH=${{ matrix.arch }} go build -o bin/test-pure-go-${{ matrix.os }}-${{ matrix.arch }}${{ matrix.os == 'windows' && '.exe' || '' }} ." - - - name: Verify binary format - run: | - cd test-project/bin - ls -la - - # Find the built binary - if [ "${{ matrix.os }}" = "windows" ]; then - BINARY="test-pure-go-${{ matrix.os }}-${{ matrix.arch }}.exe" - else - BINARY="test-pure-go-${{ matrix.os }}-${{ matrix.arch }}" - fi - - echo "Binary: $BINARY" - FILE_OUTPUT=$(file "$BINARY") - echo "File output: $FILE_OUTPUT" - - # Verify the binary format matches expected - if echo "$FILE_OUTPUT" | grep -qE "${{ matrix.expected_file }}"; then - echo "✅ Binary format verified: ${{ matrix.os }}/${{ matrix.arch }} (non-CGO)" - else - echo "❌ Binary format mismatch!" - echo "Expected pattern: ${{ matrix.expected_file }}" - echo "Got: $FILE_OUTPUT" - exit 1 - fi - - - name: Check library dependencies (Linux only) - if: matrix.os == 'linux' - run: | - cd test-project/bin - BINARY="test-pure-go-${{ matrix.os }}-${{ matrix.arch }}" - - echo "## Library Dependencies for $BINARY (non-CGO)" - echo "" - - # Non-CGO builds should have minimal dependencies (just libc or statically linked) - echo "### NEEDED libraries:" - readelf -d "$BINARY" | grep NEEDED || echo "No dynamic dependencies (statically linked)" - - # Verify NO GTK/WebKit libraries (since CGO is disabled) - NEEDED=$(readelf -d "$BINARY" | grep NEEDED || true) - if echo "$NEEDED" | grep -q "libwebkit\|libgtk"; then - echo "❌ ERROR: Non-CGO binary should not link to GTK/WebKit!" - exit 1 - else - echo "✅ Confirmed: No GTK/WebKit dependencies (expected for non-CGO)" - fi - - # Summary job - test-summary: - needs: [build, test-cross-compile, test-non-cgo] - if: always() && inputs.skip_tests != 'true' - runs-on: ubuntu-latest - steps: - - name: Check test results - run: | - echo "## Cross-Compilation Test Results" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - - if [ "${{ needs.test-cross-compile.result }}" = "success" ]; then - echo "✅ **CGO Tests**: All passed" >> $GITHUB_STEP_SUMMARY - else - echo "❌ **CGO Tests**: Failed" >> $GITHUB_STEP_SUMMARY - fi - - if [ "${{ needs.test-non-cgo.result }}" = "success" ]; then - echo "✅ **Non-CGO Tests**: All passed" >> $GITHUB_STEP_SUMMARY - else - echo "❌ **Non-CGO Tests**: Failed" >> $GITHUB_STEP_SUMMARY - fi - - echo "" >> $GITHUB_STEP_SUMMARY - echo "### Tested Platforms" >> $GITHUB_STEP_SUMMARY - echo "| Platform | Architecture | CGO | Non-CGO |" >> $GITHUB_STEP_SUMMARY - echo "|----------|-------------|-----|---------|" >> $GITHUB_STEP_SUMMARY - echo "| Darwin | arm64 | ✅ | ✅ |" >> $GITHUB_STEP_SUMMARY - echo "| Darwin | amd64 | ✅ | ✅ |" >> $GITHUB_STEP_SUMMARY - echo "| Linux | arm64 | ✅ | ✅ |" >> $GITHUB_STEP_SUMMARY - echo "| Linux | amd64 | ✅ | ✅ |" >> $GITHUB_STEP_SUMMARY - echo "| Windows | arm64 | ✅ | ✅ |" >> $GITHUB_STEP_SUMMARY - echo "| Windows | amd64 | ✅ | ✅ |" >> $GITHUB_STEP_SUMMARY - - # Fail if any test failed - if [ "${{ needs.test-cross-compile.result }}" != "success" ] || [ "${{ needs.test-non-cgo.result }}" != "success" ]; then - echo "" - echo "❌ Some tests failed. Check the individual job logs for details." - exit 1 - fi diff --git a/.github/workflows/changelog-v3.yml b/.github/workflows/changelog-v3.yml deleted file mode 100644 index 688959b9e..000000000 --- a/.github/workflows/changelog-v3.yml +++ /dev/null @@ -1,216 +0,0 @@ -name: Changelog Validation (v3) - -on: - pull_request: - branches: [ v3-alpha ] - paths: - - 'docs/src/content/docs/changelog.mdx' - workflow_dispatch: - inputs: - pr_number: - description: 'PR number to validate' - required: true - type: string - -jobs: - validate: - runs-on: ubuntu-latest - permissions: - contents: write - pull-requests: write - actions: write - - steps: - - name: Checkout PR code - uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.head.sha || format('refs/pull/{0}/head', github.event.inputs.pr_number) }} - fetch-depth: 0 - token: ${{ secrets.GITHUB_TOKEN || github.token }} - - - name: Get REAL validation script from v3-alpha - run: | - echo "Fetching the REAL validation script from v3-alpha branch..." - git fetch origin v3-alpha - git checkout origin/v3-alpha -- v3/scripts/validate-changelog.go - - echo "Validation script fetched successfully:" - ls -la v3/scripts/ - - - name: Setup Go - uses: actions/setup-go@v4 - with: - go-version: '1.23' - - - name: Get PR information - id: pr_info - run: | - if [ "${{ github.event_name }}" = "pull_request" ]; then - echo "pr_number=${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT - echo "base_ref=${{ github.event.pull_request.base.ref }}" >> $GITHUB_OUTPUT - else - echo "pr_number=${{ github.event.inputs.pr_number }}" >> $GITHUB_OUTPUT - echo "base_ref=v3-alpha" >> $GITHUB_OUTPUT - fi - - - name: Check changelog modifications - id: changelog_check - run: | - echo "Checking PR #${{ steps.pr_info.outputs.pr_number }} for changelog changes" - git fetch origin ${{ steps.pr_info.outputs.base_ref }} - - if git diff --name-only origin/${{ steps.pr_info.outputs.base_ref }}..HEAD | grep -q "docs/src/content/docs/changelog.mdx"; then - echo "changelog_modified=true" >> $GITHUB_OUTPUT - echo "✅ Changelog was modified in this PR" - else - echo "changelog_modified=false" >> $GITHUB_OUTPUT - echo "ℹ️ Changelog was not modified - skipping validation" - fi - - - name: Get changelog diff - id: get_diff - if: steps.changelog_check.outputs.changelog_modified == 'true' - run: | - echo "Getting diff for changelog changes..." - git diff origin/${{ steps.pr_info.outputs.base_ref }}..HEAD docs/src/content/docs/changelog.mdx | grep "^+" | grep -v "^+++" | sed 's/^+//' > /tmp/pr_added_lines.txt - - echo "Lines added in this PR:" - cat /tmp/pr_added_lines.txt - echo "Total lines added: $(wc -l < /tmp/pr_added_lines.txt)" - - - name: Validate changelog - id: validate - if: steps.changelog_check.outputs.changelog_modified == 'true' - run: | - echo "Running changelog validation..." - cd v3/scripts - OUTPUT=$(go run validate-changelog.go ../../docs/src/content/docs/changelog.mdx /tmp/pr_added_lines.txt 2>&1) - echo "$OUTPUT" - - RESULT=$(echo "$OUTPUT" | grep "VALIDATION_RESULT=" | cut -d'=' -f2) - echo "result=$RESULT" >> $GITHUB_OUTPUT - - - name: Commit fixes - id: commit_fixes - if: steps.validate.outputs.result == 'fixed' - run: | - echo "Committing automatic fixes..." - git config --local user.email "action@github.com" - git config --local user.name "GitHub Action" - - # Check only the changelog file for changes - if git diff --quiet docs/src/content/docs/changelog.mdx; then - echo "No changes to commit" - echo "committed=false" >> $GITHUB_OUTPUT - else - # Ensure validation script doesn't get committed - echo "v3/scripts/validate-changelog.go" >> .git/info/exclude - # Get the correct branch name to push to - REPO_OWNER="wailsapp" # Always wailsapp for this repo - - if [ "${{ github.event_name }}" = "pull_request" ]; then - BRANCH_NAME="${{ github.event.pull_request.head.ref }}" - else - # For manual workflow dispatch, get PR info - PR_INFO=$(gh pr view ${{ steps.pr_info.outputs.pr_number }} --json headRefName,headRepository) - BRANCH_NAME=$(echo "$PR_INFO" | jq -r '.headRefName') - HEAD_REPO=$(echo "$PR_INFO" | jq -r '.headRepository.name') - - echo "🔍 PR source branch: $BRANCH_NAME" - echo "🔍 Head repository: $HEAD_REPO" - - # Don't push if this is from a fork or if branch is v3-alpha (main branch) - if [ "$HEAD_REPO" != "wails" ] || [ "$BRANCH_NAME" = "v3-alpha" ]; then - echo "⚠️ Cannot push - either fork or direct v3-alpha branch. Manual fix required." - echo "committed=false" >> $GITHUB_OUTPUT - exit 0 - fi - fi - - echo "Pushing to branch: $BRANCH_NAME in repo: $REPO_OWNER" - - # Only commit the changelog changes, not the validation script - git add docs/src/content/docs/changelog.mdx - git commit -m "🤖 Fix changelog: move entries to Unreleased section" - - # Only push if running on the main wailsapp repository - if [ "${{ github.repository }}" = "wailsapp/wails" ]; then - # Pull latest changes and rebase our commit - git fetch origin $BRANCH_NAME - git rebase origin/$BRANCH_NAME - git push origin HEAD:$BRANCH_NAME - else - echo "⚠️ Running on fork (${{ github.repository }}). Skipping push - manual fix required." - echo "committed=false" >> $GITHUB_OUTPUT - exit 0 - fi - - echo "committed=true" >> $GITHUB_OUTPUT - echo "✅ Changes committed and pushed" - fi - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Get PR author for tagging - id: pr_author - if: steps.validate.outputs.result && github.event.inputs.pr_number - run: | - PR_AUTHOR=$(gh pr view ${{ steps.pr_info.outputs.pr_number }} --json author --jq '.author.login') - echo "author=$PR_AUTHOR" >> $GITHUB_OUTPUT - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Comment on PR - if: steps.validate.outputs.result && github.event.inputs.pr_number - uses: actions/github-script@v7 - with: - script: | - const result = '${{ steps.validate.outputs.result }}'; - const committed = '${{ steps.commit_fixes.outputs.committed }}'; - const author = '${{ steps.pr_author.outputs.author }}'; - - let message; - if (result === 'success') { - message = '## ✅ Changelog Validation Passed\n\nNo misplaced changelog entries detected.'; - } else if (result === 'fixed' && committed === 'true') { - message = '## 🔧 Changelog Updated\n\nMisplaced entries were automatically moved to the `[Unreleased]` section. The changes have been committed to this PR.'; - } else if (result === 'fixed' || result === 'cannot_fix' || result === 'error') { - // Read the fixed changelog content - const fs = require('fs'); - let fixedContent = ''; - try { - fixedContent = fs.readFileSync('docs/src/content/docs/changelog.mdx', 'utf8'); - } catch (error) { - fixedContent = 'Error reading fixed changelog content'; - } - - message = '## ⚠️ Changelog Validation Issue\\n\\n' + - '@' + author + ' Your PR contains changelog entries that were added to already-released versions. These need to be moved to the `[Unreleased]` section.\\n\\n' + - (committed === 'true' ? - '✅ **Auto-fix applied**: The changes have been automatically committed to this PR.' : - '❌ **Manual fix required**: Please apply the changes shown below manually.') + '\\n\\n' + - '
\\n' + - '📝 Click to see the corrected changelog content\\n\\n' + - '```mdx\\n' + - fixedContent + - '\\n```\\n\\n' + - '
\\n\\n' + - '**What happened?** \\n' + - 'The validation script detected that you added changelog entries to a version section that has already been released (like `v3.0.0-alpha.10`). All new entries should go in the `[Unreleased]` section under the appropriate category (`### Added`, `### Fixed`, etc.).\\n\\n' + - (committed !== 'true' ? '**Action needed:** Please copy the corrected content from above and replace your changelog file.' : ''); - } - - if (message) { - await github.rest.issues.createComment({ - issue_number: ${{ steps.pr_info.outputs.pr_number }}, - owner: context.repo.owner, - repo: context.repo.repo, - body: message - }); - } - - - name: Fail if validation failed - if: steps.validate.outputs.result == 'cannot_fix' || steps.validate.outputs.result == 'error' - run: | - echo "❌ Changelog validation failed" - exit 1 \ No newline at end of file diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml deleted file mode 100644 index b5e8cfd4d..000000000 --- a/.github/workflows/claude-code-review.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: Claude Code Review - -on: - pull_request: - types: [opened, synchronize, ready_for_review, reopened] - # Optional: Only run on specific file changes - # paths: - # - "src/**/*.ts" - # - "src/**/*.tsx" - # - "src/**/*.js" - # - "src/**/*.jsx" - -jobs: - claude-review: - # Optional: Filter by PR author - # if: | - # github.event.pull_request.user.login == 'external-contributor' || - # github.event.pull_request.user.login == 'new-developer' || - # github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR' - - runs-on: ubuntu-latest - permissions: - contents: read - pull-requests: read - issues: read - id-token: write - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 1 - - - name: Run Claude Code Review - id: claude-review - uses: anthropics/claude-code-action@v1 - with: - claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} - plugin_marketplaces: 'https://github.com/anthropics/claude-code.git' - plugins: 'code-review@claude-code-plugins' - prompt: '/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }}' - # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md - # or https://code.claude.com/docs/en/cli-reference for available options - diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml deleted file mode 100644 index d300267f1..000000000 --- a/.github/workflows/claude.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: Claude Code - -on: - issue_comment: - types: [created] - pull_request_review_comment: - types: [created] - issues: - types: [opened, assigned] - pull_request_review: - types: [submitted] - -jobs: - claude: - if: | - (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) || - (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) || - (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) || - (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))) - runs-on: ubuntu-latest - permissions: - contents: read - pull-requests: read - issues: read - id-token: write - actions: read # Required for Claude to read CI results on PRs - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 1 - - - name: Run Claude Code - id: claude - uses: anthropics/claude-code-action@v1 - with: - claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} - - # This is an optional setting that allows Claude to read CI results on PRs - additional_permissions: | - actions: read - - # Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it. - # prompt: 'Update the pull request description to include a summary of changes.' - - # Optional: Add claude_args to customize behavior and configuration - # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md - # or https://code.claude.com/docs/en/cli-reference for available options - # claude_args: '--allowed-tools Bash(gh pr:*)' - diff --git a/.github/workflows/deploy-website-to-wails.top-mirror.yml b/.github/workflows/deploy-website-to-wails.top-mirror.yml new file mode 100644 index 000000000..88966f189 --- /dev/null +++ b/.github/workflows/deploy-website-to-wails.top-mirror.yml @@ -0,0 +1,35 @@ +name: Deploy mirror | 部署镜像 + +on: + push: + branches: [master] + # pull_request: + # branches: [ main ] + +jobs: + build-and-deploy: + name: Automatic deployment | 自动部署 + runs-on: ubuntu-latest + if: github.repository == 'misitebao/wails' + + steps: + - name: Checkout | 切换到部署分支 + uses: actions/checkout@v2 + with: + ref: "master" + submodules: true + fetch-depth: 0 + + - name: Build Site | 构建网站 + run: | + cd website && + npm install && npm run build + + - name: Deploy to Server | 部署到服务器 + uses: hengkx/ssh-deploy@v1.0.1 + with: + HOST: ${{ secrets.DEPLOY_HOST }} + USERNAME: ${{ secrets.DEPLOY_HOST_USER }} + PASSWORD: ${{ secrets.DEPLOY_HOST_PASSWORD }} + SOURCE: "website/build" + TARGET: "/www/wwwroot/wails.top" diff --git a/.github/workflows/generate-sponsor-image.yml b/.github/workflows/generate-sponsor-image.yml deleted file mode 100644 index 56548ab43..000000000 --- a/.github/workflows/generate-sponsor-image.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: Generate Sponsor Image - -on: - workflow_dispatch: - schedule: - - cron: "0 0 * * *" - -jobs: - update-sponsors: - name: Update Sponsors - runs-on: ubuntu-latest - if: github.repository == 'wailsapp/wails' - steps: - - uses: actions/checkout@v3 - - - name: Set Node - uses: actions/setup-node@v2 - with: - node-version: 20.x - - - name: Update Sponsors - run: cd scripts/sponsors && chmod 755 ./generate-sponsor-image.sh && ./generate-sponsor-image.sh - env: - SPONSORKIT_GITHUB_TOKEN: ${{ secrets.SPONSORS_TOKEN }} - SPONSORKIT_GITHUB_LOGIN: wailsapp - - - name: Create Pull Request - uses: peter-evans/create-pull-request@v6 - with: - commit-message: "chore: update sponsors.svg" - add-paths: "website/static/img/sponsors.svg" - title: "chore: update sponsors.svg" - body: | - Auto-generated by the sponsor image workflow - - [skip ci] [skip actions] - branch: update-sponsors - base: master - delete-branch: true - draft: false diff --git a/.github/workflows/issue-triage-automation.yml b/.github/workflows/issue-triage-automation.yml deleted file mode 100644 index 99159a2f5..000000000 --- a/.github/workflows/issue-triage-automation.yml +++ /dev/null @@ -1,77 +0,0 @@ -name: Issue Triage Automation - -on: - issues: - types: [opened] - -jobs: - triage: - runs-on: ubuntu-latest - permissions: - issues: write - contents: read - steps: - # Request more info for unclear bug reports - - name: Request more info - uses: actions/github-script@v6 - if: | - contains(github.event.issue.labels.*.name, 'bug') && - !contains(github.event.issue.body, 'wails doctor') && - !contains(github.event.issue.body, 'reproduction') - with: - script: | - github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: `👋 Thanks for reporting this issue! To help us investigate, could you please: - - 1. Add the output of \`wails doctor\` if not already included - 2. Provide clear steps to reproduce the issue - 3. If possible, create a minimal reproduction of the issue - - This will help us resolve your issue much faster. Thank you!` - }); - github.rest.issues.addLabels({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - labels: ['awaiting feedback'] - }); - - # Prioritize security issues - - name: Prioritize security issues - uses: actions/github-script@v6 - if: contains(github.event.issue.labels.*.name, 'security') - with: - script: | - github.rest.issues.addLabels({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - labels: ['high-priority'] - }); - - # Tag version-specific issues for project boards - - name: Add to v2 project - uses: actions/github-script@v6 - if: | - contains(github.event.issue.labels.*.name, 'v2-only') && - !contains(github.event.issue.labels.*.name, 'v3-alpha') - with: - script: | - // Replace PROJECT_ID with your actual GitHub project ID - // This is a placeholder as the actual implementation would require - // GraphQL API calls to add to a project board - console.log('Would add to v2 project board'); - - # Tag version-specific issues for project boards - - name: Add to v3 project - uses: actions/github-script@v6 - if: contains(github.event.issue.labels.*.name, 'v3-alpha') - with: - script: | - // Replace PROJECT_ID with your actual GitHub project ID - // This is a placeholder as the actual implementation would require - // GraphQL API calls to add to a project board - console.log('Would add to v3 project board'); diff --git a/.github/workflows/latest-pre.yml b/.github/workflows/latest-pre.yml new file mode 100644 index 000000000..870fe55d5 --- /dev/null +++ b/.github/workflows/latest-pre.yml @@ -0,0 +1,34 @@ +name: latest pre-release +on: + push: + branches: + - develop + tags: + - '**-pre**' +jobs: + + build: + name: Test Build Latest Pre-Release + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macOS-latest] + steps: + + - name: Set up Go 1.16 + uses: actions/setup-go@v1 + with: + go-version: 1.16 + id: go + + - name: Check out code into the Go module directory + uses: actions/checkout@v1 + + - name: Get dependencies + run: | + go get -v -d ./... + - name: Build + run: go build -v ./cmd/wails + + - name: Test + run: ./wails version diff --git a/.github/workflows/nightly-release-v3.yml b/.github/workflows/nightly-release-v3.yml deleted file mode 100644 index ae56ba7bc..000000000 --- a/.github/workflows/nightly-release-v3.yml +++ /dev/null @@ -1,210 +0,0 @@ -name: Nightly Release v3-alpha - -on: - schedule: - - cron: '0 2 * * *' # 2 AM UTC daily - workflow_dispatch: - inputs: - force_release: - description: 'Force release even if no changes detected' - required: false - default: false - type: boolean - dry_run: - description: 'Run in dry-run mode (no actual release)' - required: false - default: true - type: boolean - -jobs: - nightly-release: - runs-on: ubuntu-latest - - permissions: - contents: write - pull-requests: read - actions: write - - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - ref: v3-alpha - fetch-depth: 0 - token: ${{ secrets.WAILS_REPO_TOKEN || github.token }} - - - name: Setup Go - uses: actions/setup-go@v4 - with: - go-version: '1.24' - cache: true - cache-dependency-path: 'v3/go.sum' - - - name: Install Task - uses: arduino/setup-task@v2 - with: - version: 3.x - repo-token: ${{ secrets.GITHUB_TOKEN }} - - - name: Setup Git - run: | - git config --global user.name "github-actions[bot]" - git config --global user.email "github-actions[bot]@users.noreply.github.com" - - # Configure git to use the token for authentication - git config --global url."https://x-access-token:${{ secrets.WAILS_REPO_TOKEN || github.token }}@github.com/".insteadOf "https://github.com/" - - - name: Check for existing release tag - id: check_tag - run: | - if git describe --tags --exact-match HEAD 2>/dev/null; then - echo "has_tag=true" >> $GITHUB_OUTPUT - echo "tag=$(git describe --tags --exact-match HEAD)" >> $GITHUB_OUTPUT - else - echo "has_tag=false" >> $GITHUB_OUTPUT - echo "tag=" >> $GITHUB_OUTPUT - fi - - - name: Check for unreleased changelog content - id: changelog_check - run: | - echo "🔍 Checking UNRELEASED_CHANGELOG.md for content..." - - # Run the release script in check mode to see if there's content - cd v3/tasks/release - - # Use the release script itself to check for content - if go run release.go --check-only 2>/dev/null; then - echo "has_unreleased_content=true" >> $GITHUB_OUTPUT - echo "✅ Found unreleased changelog content" - else - echo "has_unreleased_content=false" >> $GITHUB_OUTPUT - echo "ℹ️ No unreleased changelog content found" - fi - - - name: Quick change detection and early exit - id: quick_check - run: | - echo "🔍 Quick check for changes to determine if we should continue..." - - # First check if we have unreleased changelog content - if [ "${{ steps.changelog_check.outputs.has_unreleased_content }}" == "true" ]; then - echo "✅ Found unreleased changelog content, proceeding with release" - echo "has_changes=true" >> $GITHUB_OUTPUT - echo "should_continue=true" >> $GITHUB_OUTPUT - echo "reason=Found unreleased changelog content" >> $GITHUB_OUTPUT - exit 0 - fi - - # If no unreleased changelog content, check for git changes as fallback - echo "No unreleased changelog content found, checking for git changes..." - - # Check if current commit has a release tag - if git describe --tags --exact-match HEAD 2>/dev/null; then - CURRENT_TAG=$(git describe --tags --exact-match HEAD) - echo "Current commit has release tag: $CURRENT_TAG" - - # For tagged commits, check if there are changes since the tag - COMMIT_COUNT=$(git rev-list ${CURRENT_TAG}..HEAD --count) - if [ "$COMMIT_COUNT" -eq 0 ]; then - echo "has_changes=false" >> $GITHUB_OUTPUT - echo "should_continue=false" >> $GITHUB_OUTPUT - echo "reason=No changes since existing tag $CURRENT_TAG and no unreleased changelog content" >> $GITHUB_OUTPUT - else - echo "has_changes=true" >> $GITHUB_OUTPUT - echo "should_continue=true" >> $GITHUB_OUTPUT - fi - else - # No current tag, check against latest release - LATEST_TAG=$(git tag --list "v3.0.0-alpha.*" | sort -V | tail -1) - if [ -z "$LATEST_TAG" ]; then - echo "No previous release found, proceeding with release" - echo "has_changes=true" >> $GITHUB_OUTPUT - echo "should_continue=true" >> $GITHUB_OUTPUT - else - COMMIT_COUNT=$(git rev-list ${LATEST_TAG}..HEAD --count) - if [ "$COMMIT_COUNT" -gt 0 ]; then - echo "Found $COMMIT_COUNT commits since $LATEST_TAG" - echo "has_changes=true" >> $GITHUB_OUTPUT - echo "should_continue=true" >> $GITHUB_OUTPUT - else - echo "has_changes=false" >> $GITHUB_OUTPUT - echo "should_continue=false" >> $GITHUB_OUTPUT - echo "reason=No changes since latest release $LATEST_TAG and no unreleased changelog content" >> $GITHUB_OUTPUT - fi - fi - fi - - - name: Early exit - No changes detected - if: | - steps.quick_check.outputs.should_continue == 'false' && - github.event.inputs.force_release != 'true' - run: | - echo "🛑 EARLY EXIT: ${{ steps.quick_check.outputs.reason }}" - echo "" - echo "ℹ️ No changes detected since last release and force_release is not enabled." - echo " Workflow will exit early to save resources." - echo "" - echo " To force a release anyway, run this workflow with 'force_release=true'" - echo "" - echo "## 🛑 Early Exit Summary" >> $GITHUB_STEP_SUMMARY - echo "**Reason:** ${{ steps.quick_check.outputs.reason }}" >> $GITHUB_STEP_SUMMARY - echo "**Action:** Workflow exited early to save resources" >> $GITHUB_STEP_SUMMARY - echo "**Force Release:** Set 'force_release=true' to override this behavior" >> $GITHUB_STEP_SUMMARY - exit 0 - - - name: Continue with release process - if: | - steps.quick_check.outputs.should_continue == 'true' || - github.event.inputs.force_release == 'true' - run: | - echo "✅ Proceeding with release process..." - if [ "${{ github.event.inputs.force_release }}" == "true" ]; then - echo "🔨 FORCE RELEASE: Overriding change detection" - fi - - - name: Run release script - id: release - if: | - steps.quick_check.outputs.should_continue == 'true' || - github.event.inputs.force_release == 'true' - env: - WAILS_REPO_TOKEN: ${{ secrets.WAILS_REPO_TOKEN || github.token }} - GITHUB_TOKEN: ${{ secrets.WAILS_REPO_TOKEN || github.token }} - run: | - cd v3/tasks/release - ARGS=() - if [ "${{ github.event.inputs.dry_run }}" == "true" ]; then - ARGS+=(--dry-run) - fi - go run release.go "${ARGS[@]}" - - - name: Summary - if: always() - run: | - if [ "${{ github.event.inputs.dry_run }}" == "true" ]; then - echo "## 🧪 DRY RUN Release Summary" >> $GITHUB_STEP_SUMMARY - else - echo "## 🚀 Nightly Release Summary" >> $GITHUB_STEP_SUMMARY - fi - echo "================================" >> $GITHUB_STEP_SUMMARY - - if [ -n "${{ steps.release.outputs.release_version }}" ]; then - echo "- **Version:** ${{ steps.release.outputs.release_version }}" >> $GITHUB_STEP_SUMMARY - echo "- **Tag:** ${{ steps.release.outputs.release_tag }}" >> $GITHUB_STEP_SUMMARY - echo "- **Status:** ${{ steps.release.outcome == 'success' && '✅ Success' || '⚠️ Failed' }}" >> $GITHUB_STEP_SUMMARY - echo "- **Mode:** ${{ steps.release.outputs.release_dry_run == 'true' && '🧪 Dry Run' || '🚀 Live release' }}" >> $GITHUB_STEP_SUMMARY - if [ -n "${{ steps.release.outputs.release_url }}" ]; then - echo "- **Release URL:** ${{ steps.release.outputs.release_url }}" >> $GITHUB_STEP_SUMMARY - fi - echo "" >> $GITHUB_STEP_SUMMARY - echo "### Changelog" >> $GITHUB_STEP_SUMMARY - if [ "${{ steps.changelog_check.outputs.has_unreleased_content }}" == "true" ]; then - echo "✅ Unreleased changelog processed and reset." >> $GITHUB_STEP_SUMMARY - else - echo "ℹ️ No unreleased changelog content detected." >> $GITHUB_STEP_SUMMARY - fi - else - echo "- Release script did not run (skipped or failed before execution)." >> $GITHUB_STEP_SUMMARY - fi - diff --git a/.github/workflows/pr-master.yml b/.github/workflows/pr-master.yml deleted file mode 100644 index c961b4434..000000000 --- a/.github/workflows/pr-master.yml +++ /dev/null @@ -1,104 +0,0 @@ -# Updated to ensure "Run Go Tests" runs for pull requests as expected. -# Key fix: the test_go job previously required github.event.review.state == 'approved' -# which only exists on pull_request_review events. That prevented the job from -# running for regular pull_request events (opened / synchronize / reopened). -# New logic: run tests for pull_request events, and also allow running when a -# pull_request_review is submitted with state == 'approved'. -on: - pull_request: - types: [opened, synchronize, reopened] - branches: - - master - pull_request_review: - types: [submitted] - branches: - - master - workflow_dispatch: {} - -name: PR Checks (master) - -jobs: - check_docs: - name: Check Docs - if: ${{ github.repository == 'wailsapp/wails' && github.base_ref == 'master' }} - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - name: Verify Changed files - uses: step-security/changed-files@3dbe17c78367e7d60f00d78ae6781a35be47b4a1 # v45.0.1 - id: verify-changed-files - with: - files: | - website/**/*.mdx - website/**/*.md - - name: Run step only when files change. - if: steps.verify-changed-files.outputs.files_changed != 'true' - run: | - echo "::warning::Feature branch does not contain any changes to the website." - - test_go: - name: Run Go Tests - runs-on: ${{ matrix.os }} - # Run when: - # - the event is a pull_request (opened/synchronize/reopened) OR - # - the event is a pull_request_review AND the review state is 'approved' - # plus other existing filters (not the update-sponsors branch, repo and base_ref) - if: > - github.repository == 'wailsapp/wails' && - github.base_ref == 'master' && - github.event.pull_request.head.ref != 'update-sponsors' && - ( - github.event_name == 'pull_request' || - (github.event_name == 'pull_request_review' && github.event.review.state == 'approved') - ) - strategy: - matrix: - os: [ubuntu-22.04, windows-latest, macos-latest, ubuntu-24.04] - go-version: ['1.23'] - - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Install linux dependencies (22.04) - if: matrix.os == 'ubuntu-22.04' - run: sudo apt-get update -y && sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev build-essential pkg-config - - - name: Install linux dependencies (24.04) - if: matrix.os == 'ubuntu-24.04' - run: sudo apt-get update -y && sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev build-essential pkg-config - - - name: Setup Go - uses: actions/setup-go@v3 - with: - go-version: ${{ matrix.go-version }} - - - name: Run tests (mac) - if: matrix.os == 'macos-latest' - env: - CGO_LDFLAGS: -framework UniformTypeIdentifiers -mmacosx-version-min=10.13 - working-directory: ./v2 - run: go test -v ./... - - - name: Run tests (!mac) - if: matrix.os != 'macos-latest' && matrix.os != 'ubuntu-24.04' - working-directory: ./v2 - run: go test -v ./... - - - name: Run tests (Ubuntu 24.04) - if: matrix.os == 'ubuntu-24.04' - working-directory: ./v2 - run: go test -v -tags webkit2_41 ./... - - # This job will run instead of test_go for the update-sponsors branch - skip_tests: - name: Skip Tests (Sponsor Update) - if: github.event.pull_request.head.ref == 'update-sponsors' - runs-on: ubuntu-latest - steps: - - name: Skip tests for sponsor updates - run: | - echo "Skipping tests for sponsor update branch" - echo "This is an automated update of the sponsors image." - continue-on-error: true diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml new file mode 100644 index 000000000..df5e53697 --- /dev/null +++ b/.github/workflows/pr.yml @@ -0,0 +1,32 @@ +name: pr +on: + pull_request: + branches: + - develop +jobs: + + build: + name: Test Build PR + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macOS-latest] + steps: + + - name: Set up Go 1.16 + uses: actions/setup-go@v1 + with: + go-version: 1.16 + id: go + + - name: Check out code into the Go module directory + uses: actions/checkout@v1 + + - name: Get dependencies + run: | + go get -v -d ./... + - name: Build + run: go build -v ./cmd/wails + + - name: Test + run: ./wails version diff --git a/.github/workflows/projects.yml b/.github/workflows/projects.yml deleted file mode 100644 index 3b81c64e7..000000000 --- a/.github/workflows/projects.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: Update Project - -on: - project_card: - types: [ moved ] - -jobs: - projectcardautolabel_job: - runs-on: ubuntu-latest - if: github.repository == 'wailsapp/wails' - steps: - - name: Run ProjectCard AutoLabel - id: runprojectcardautolabel - uses: Matticusau/projectcard-autolabel@v1.0.0 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - autolabel-config: '[{"column": "TODO", "add_labels":["TODO"], "remove_labels":["In Progress", "Ready For Testing"]},{"column":"In progress", "add_labels":["In Progress"], "remove_labels":["TODO", "Ready For Testing"]},{"column":"In review", "add_labels":["Ready For Testing"], "remove_labels":["TODO", "In Progress"]}, {"column":"Done", "add_labels":["Done"], "remove_labels":["TODO", "In Progress", "Ready For Testing"]}]' \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..03fe71f98 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,34 @@ +name: release +on: + push: + branches: + - master + tags: + - '!**pre**' +jobs: + + build: + name: Test Build Latest Release + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macOS-latest] + steps: + + - name: Set up Go 1.16 + uses: actions/setup-go@v1 + with: + go-version: 1.16 + id: go + + - name: Check out code into the Go module directory + uses: actions/checkout@v1 + + - name: Get dependencies + run: | + go get -v -d ./... + - name: Build + run: go build -v ./cmd/wails + + - name: Test + run: ./wails version diff --git a/.github/workflows/runtime.yml b/.github/workflows/runtime.yml index 2c97b628b..43cc5bdff 100644 --- a/.github/workflows/runtime.yml +++ b/.github/workflows/runtime.yml @@ -10,7 +10,7 @@ jobs: name: Rebuild the runtime runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: node-version: 14.17.6 diff --git a/.github/workflows/semgrep.yml b/.github/workflows/semgrep.yml deleted file mode 100644 index a59818660..000000000 --- a/.github/workflows/semgrep.yml +++ /dev/null @@ -1,25 +0,0 @@ -on: - workflow_dispatch: {} - pull_request: {} - push: - branches: - - main - - master - - v3-alpha - paths: - - .github/workflows/semgrep.yml - schedule: - # random HH:MM to avoid a load spike on GitHub Actions at 00:00 - - cron: 14 16 * * * -name: Semgrep -jobs: - semgrep: - name: semgrep/ci - runs-on: ubuntu-24.04 - env: - SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} - container: - image: returntocorp/semgrep - steps: - - uses: actions/checkout@v3 - - run: semgrep ci diff --git a/.github/workflows/stale-issues.yml b/.github/workflows/stale-issues.yml deleted file mode 100644 index c4ffd25fe..000000000 --- a/.github/workflows/stale-issues.yml +++ /dev/null @@ -1,57 +0,0 @@ -name: Mark and Close Stale Issues - -on: - schedule: - - cron: '0 1 * * *' # Run at 1 AM UTC every day - workflow_dispatch: # Allow manual triggering - -jobs: - stale: - runs-on: ubuntu-latest - permissions: - issues: write - pull-requests: write - - steps: - - uses: actions/stale@v9 - with: - # General settings - repo-token: ${{ secrets.GITHUB_TOKEN }} - days-before-stale: 45 - days-before-close: 10 - stale-issue-label: 'stale' - operations-per-run: 250 # Increased from 50 to 250 - - # Issue specific settings - stale-issue-message: | - This issue has been automatically marked as stale because it has not had recent activity. - It will be closed if no further activity occurs within the next 10 days. - - If this issue is still relevant, please add a comment to keep it open. - Thank you for your contributions. - - close-issue-message: | - This issue has been automatically closed due to lack of activity. - Please feel free to reopen it if it's still relevant. - - # PR specific settings - We will not mark PRs as stale - days-before-pr-stale: -1 # Disable PR staling - days-before-pr-close: -1 # Disable PR closing - - # Exemptions - exempt-issue-labels: 'pinned,security,onhold,inprogress,Selected For Development,bug,enhancement,v3-alpha,high-priority' - exempt-all-issue-milestones: true - exempt-all-issue-assignees: true - - # Protection for existing issues - exempt-issue-created-before: '2024-01-01T00:00:00Z' - start-date: '2025-06-01T00:00:00Z' # Don't start checking until June 1, 2025 - - # Only process issues, not PRs - only-labels: '' - any-of-labels: '' - remove-stale-when-updated: true - - # Debug options - debug-only: false # Set to true to test without actually marking issues - ascending: true # Process older issues first diff --git a/.github/workflows/sync-translated-documents.yml b/.github/workflows/sync-translated-documents.yml deleted file mode 100644 index 0aa06f11e..000000000 --- a/.github/workflows/sync-translated-documents.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: Sync Translations - -on: - workflow_dispatch: - schedule: - - cron: "0 0 * * *" - -jobs: - sync-translated-documents: - runs-on: ubuntu-latest - if: github.repository == 'wailsapp/wails' - steps: - - uses: actions/checkout@v3 - - - name: Setup Nodejs - uses: actions/setup-node@v2 - with: - node-version: 20.x - - - name: Install Task - uses: arduino/setup-task@v1 - with: - version: 3.x - repo-token: ${{ secrets.GITHUB_TOKEN }} - - - name: Sync Translated Documents - env: - CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} - working-directory: ./website - run: task crowdin:pull - - - name: Create Pull Request - uses: peter-evans/create-pull-request@v4 - with: - commit-message: "docs: sync translations" - title: "docs: sync translations" - body: "- [x] Sync translated documents" - branch: chore/sync-translations - labels: translation - delete-branch: true - draft: true diff --git a/.github/workflows/test-nightly-releases.yml b/.github/workflows/test-nightly-releases.yml deleted file mode 100644 index 63df09935..000000000 --- a/.github/workflows/test-nightly-releases.yml +++ /dev/null @@ -1,216 +0,0 @@ -name: Test Nightly Releases (Dry Run) - -on: - workflow_dispatch: - inputs: - dry_run: - description: 'Run in dry-run mode (no actual releases)' - required: false - default: true - type: boolean - test_branch: - description: 'Branch to test against' - required: false - default: 'master' - type: string - -env: - GO_VERSION: '1.24' - -jobs: - test-permissions: - name: Test Release Permissions - runs-on: ubuntu-latest - outputs: - authorized: ${{ steps.check.outputs.authorized }} - steps: - - name: Check if user is authorized - id: check - run: | - # Test authorization logic - AUTHORIZED_USERS="leaanthony" - - if [[ "$AUTHORIZED_USERS" == *"${{ github.actor }}"* ]]; then - echo "✅ User ${{ github.actor }} is authorized" - echo "authorized=true" >> $GITHUB_OUTPUT - else - echo "❌ User ${{ github.actor }} is not authorized" - echo "authorized=false" >> $GITHUB_OUTPUT - fi - - test-changelog-extraction: - name: Test Changelog Extraction - runs-on: ubuntu-latest - needs: test-permissions - if: needs.test-permissions.outputs.authorized == 'true' - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - ref: ${{ github.event.inputs.test_branch }} - fetch-depth: 0 - - - name: Test v2 changelog extraction - run: | - echo "🧪 Testing v2 changelog extraction..." - CHANGELOG_FILE="website/src/pages/changelog.mdx" - - if [ ! -f "$CHANGELOG_FILE" ]; then - echo "❌ v2 changelog file not found" - exit 1 - fi - - # Extract unreleased section - awk ' - /^## \[Unreleased\]/ { found=1; next } - found && /^## / { exit } - found && !/^$/ { print } - ' $CHANGELOG_FILE > v2_release_notes.md - - echo "📝 v2 changelog content (first 10 lines):" - head -10 v2_release_notes.md || echo "No content found" - echo "Total lines: $(wc -l < v2_release_notes.md)" - - - name: Test v3 changelog extraction (if accessible) - run: | - echo "🧪 Testing v3 changelog extraction..." - - if git show v3-alpha:docs/src/content/docs/changelog.mdx > /dev/null 2>&1; then - echo "✅ v3 changelog accessible" - - git show v3-alpha:docs/src/content/docs/changelog.mdx | awk ' - /^## \[Unreleased\]/ { found=1; next } - found && /^## / { exit } - found && !/^$/ { print } - ' > v3_release_notes.md - - echo "📝 v3 changelog content (first 10 lines):" - head -10 v3_release_notes.md || echo "No content found" - echo "Total lines: $(wc -l < v3_release_notes.md)" - else - echo "⚠️ v3 changelog not accessible from current context" - fi - - test-version-detection: - name: Test Version Detection - runs-on: ubuntu-latest - needs: test-permissions - if: needs.test-permissions.outputs.authorized == 'true' - outputs: - v2_current_version: ${{ steps.versions.outputs.v2_current }} - v2_next_patch: ${{ steps.versions.outputs.v2_next_patch }} - v2_next_minor: ${{ steps.versions.outputs.v2_next_minor }} - v2_next_major: ${{ steps.versions.outputs.v2_next_major }} - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Test version detection logic - id: versions - run: | - echo "🧪 Testing version detection..." - - # Test v2 version parsing - if [ -f "v2/cmd/wails/internal/version.txt" ]; then - CURRENT_V2=$(cat v2/cmd/wails/internal/version.txt | sed 's/^v//') - echo "Current v2 version: v$CURRENT_V2" - echo "v2_current=v$CURRENT_V2" >> $GITHUB_OUTPUT - - # Parse and increment - IFS='.' read -ra VERSION_PARTS <<< "$CURRENT_V2" - MAJOR=${VERSION_PARTS[0]} - MINOR=${VERSION_PARTS[1]} - PATCH=${VERSION_PARTS[2]} - - PATCH_VERSION="v$MAJOR.$MINOR.$((PATCH + 1))" - MINOR_VERSION="v$MAJOR.$((MINOR + 1)).0" - MAJOR_VERSION="v$((MAJOR + 1)).0.0" - - echo "v2_next_patch=$PATCH_VERSION" >> $GITHUB_OUTPUT - echo "v2_next_minor=$MINOR_VERSION" >> $GITHUB_OUTPUT - echo "v2_next_major=$MAJOR_VERSION" >> $GITHUB_OUTPUT - - echo "✅ Patch: v$CURRENT_V2 → $PATCH_VERSION" - echo "✅ Minor: v$CURRENT_V2 → $MINOR_VERSION" - echo "✅ Major: v$CURRENT_V2 → $MAJOR_VERSION" - else - echo "❌ v2 version file not found" - fi - - test-commit-analysis: - name: Test Commit Analysis - runs-on: ubuntu-latest - needs: test-permissions - if: needs.test-permissions.outputs.authorized == 'true' - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Test commit analysis - run: | - echo "🧪 Testing commit analysis..." - - # Get recent commits for testing - echo "Recent commits:" - git log --oneline -10 - - # Test conventional commit detection - RECENT_COMMITS=$(git log --oneline --since="7 days ago") - echo "Commits from last 7 days:" - echo "$RECENT_COMMITS" - - # Analyze for release type - RELEASE_TYPE="patch" - if echo "$RECENT_COMMITS" | grep -q "feat!\|fix!\|BREAKING CHANGE:"; then - RELEASE_TYPE="major" - elif echo "$RECENT_COMMITS" | grep -q "feat\|BREAKING CHANGE"; then - RELEASE_TYPE="minor" - fi - - echo "✅ Detected release type: $RELEASE_TYPE" - - test-summary: - name: Test Summary - runs-on: ubuntu-latest - needs: [test-permissions, test-changelog-extraction, test-version-detection, test-commit-analysis] - if: always() - steps: - - name: Print test results - run: | - echo "# 🧪 Nightly Release Workflow Test Results" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - - if [ "${{ needs.test-permissions.result }}" == "success" ]; then - echo "✅ **Permissions Test**: Passed" >> $GITHUB_STEP_SUMMARY - else - echo "❌ **Permissions Test**: Failed" >> $GITHUB_STEP_SUMMARY - fi - - if [ "${{ needs.test-changelog-extraction.result }}" == "success" ]; then - echo "✅ **Changelog Extraction**: Passed" >> $GITHUB_STEP_SUMMARY - else - echo "❌ **Changelog Extraction**: Failed" >> $GITHUB_STEP_SUMMARY - fi - - if [ "${{ needs.test-version-detection.result }}" == "success" ]; then - echo "✅ **Version Detection**: Passed" >> $GITHUB_STEP_SUMMARY - echo " - Current v2: ${{ needs.test-version-detection.outputs.v2_current_version }}" >> $GITHUB_STEP_SUMMARY - echo " - Next patch: ${{ needs.test-version-detection.outputs.v2_next_patch }}" >> $GITHUB_STEP_SUMMARY - echo " - Next minor: ${{ needs.test-version-detection.outputs.v2_next_minor }}" >> $GITHUB_STEP_SUMMARY - echo " - Next major: ${{ needs.test-version-detection.outputs.v2_next_major }}" >> $GITHUB_STEP_SUMMARY - else - echo "❌ **Version Detection**: Failed" >> $GITHUB_STEP_SUMMARY - fi - - if [ "${{ needs.test-commit-analysis.result }}" == "success" ]; then - echo "✅ **Commit Analysis**: Passed" >> $GITHUB_STEP_SUMMARY - else - echo "❌ **Commit Analysis**: Failed" >> $GITHUB_STEP_SUMMARY - fi - - echo "" >> $GITHUB_STEP_SUMMARY - echo "**Note**: This was a dry-run test. No actual releases were created." >> $GITHUB_STEP_SUMMARY \ No newline at end of file diff --git a/.github/workflows/unreleased-changelog-trigger.yml b/.github/workflows/unreleased-changelog-trigger.yml deleted file mode 100644 index 8cfe85de0..000000000 --- a/.github/workflows/unreleased-changelog-trigger.yml +++ /dev/null @@ -1,129 +0,0 @@ -name: Auto Release on Changelog Update - -on: - push: - branches: - - v3-alpha - paths: - - 'v3/UNRELEASED_CHANGELOG.md' - workflow_dispatch: - inputs: - dry_run: - description: 'Run in dry-run mode (no actual release)' - required: false - default: false - type: boolean - -jobs: - check-permissions: - name: Check Release Permissions - runs-on: ubuntu-latest - outputs: - authorized: ${{ steps.check.outputs.authorized }} - steps: - - name: Check if user is authorized for releases - id: check - run: | - # Only allow specific users to trigger releases - AUTHORIZED_USERS="leaanthony" - - if [[ "$AUTHORIZED_USERS" == *"${{ github.actor }}"* ]]; then - echo "✅ User ${{ github.actor }} is authorized for releases" - echo "authorized=true" >> $GITHUB_OUTPUT - else - echo "❌ User ${{ github.actor }} is not authorized for releases" - echo "authorized=false" >> $GITHUB_OUTPUT - fi - - trigger-release: - name: Trigger v3-alpha Release - permissions: - contents: read - actions: write - runs-on: ubuntu-latest - needs: check-permissions - if: needs.check-permissions.outputs.authorized == 'true' - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - ref: v3-alpha - fetch-depth: 0 - token: ${{ secrets.WAILS_REPO_TOKEN || github.token }} - - - name: Check for unreleased changelog content - id: changelog_check - run: | - echo "🔍 Checking UNRELEASED_CHANGELOG.md for content..." - - cd v3 - # Check if UNRELEASED_CHANGELOG.md has actual content beyond the template - if [ -f "UNRELEASED_CHANGELOG.md" ]; then - # Use a simple check for actual content (bullet points starting with -) - CONTENT_LINES=$(grep -E "^\s*-\s+[^[:space:]]" UNRELEASED_CHANGELOG.md | wc -l) - if [ "$CONTENT_LINES" -gt 0 ]; then - echo "✅ Found $CONTENT_LINES content lines in UNRELEASED_CHANGELOG.md" - echo "has_content=true" >> $GITHUB_OUTPUT - else - echo "ℹ️ No actual content found in UNRELEASED_CHANGELOG.md" - echo "has_content=false" >> $GITHUB_OUTPUT - fi - else - echo "❌ UNRELEASED_CHANGELOG.md not found" - echo "has_content=false" >> $GITHUB_OUTPUT - fi - - - name: Trigger nightly release workflow - if: steps.changelog_check.outputs.has_content == 'true' - uses: actions/github-script@v7 - with: - github-token: ${{ secrets.WAILS_REPO_TOKEN || github.token }} - script: | - const response = await github.rest.actions.createWorkflowDispatch({ - owner: context.repo.owner, - repo: context.repo.repo, - workflow_id: 'nightly-release-v3.yml', - ref: 'v3-alpha', - inputs: { - force_release: 'true', - dry_run: '${{ github.event.inputs.dry_run || "false" }}' - } - }); - - console.log('🚀 Successfully triggered nightly release workflow'); - console.log(`Workflow dispatch response status: ${response.status}`); - - // Create a summary - core.summary - .addHeading('🚀 Auto Release Triggered') - .addRaw('The v3-alpha release workflow has been automatically triggered due to changes in UNRELEASED_CHANGELOG.md') - .addTable([ - [{data: 'Trigger', header: true}, {data: 'Value', header: true}], - ['Repository', context.repo.repo], - ['Branch', 'v3-alpha'], - ['Actor', context.actor], - ['Dry Run', '${{ github.event.inputs.dry_run || "false" }}'], - ['Force Release', 'true'] - ]) - .addRaw('\n---\n*This release was automatically triggered by the unreleased-changelog-trigger workflow*') - .write(); - - - name: No content found - if: steps.changelog_check.outputs.has_content == 'false' - run: | - echo "ℹ️ No content found in UNRELEASED_CHANGELOG.md, skipping release trigger" - echo "## ℹ️ No Release Triggered" >> $GITHUB_STEP_SUMMARY - echo "**Reason:** UNRELEASED_CHANGELOG.md does not contain actual changelog content" >> $GITHUB_STEP_SUMMARY - echo "**Action:** No release workflow was triggered" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "To trigger a release, add actual changelog entries to the UNRELEASED_CHANGELOG.md file." >> $GITHUB_STEP_SUMMARY - - - name: Unauthorized user - if: needs.check-permissions.outputs.authorized == 'false' - run: | - echo "❌ User ${{ github.actor }} is not authorized to trigger releases" - echo "## ❌ Unauthorized Release Attempt" >> $GITHUB_STEP_SUMMARY - echo "**User:** ${{ github.actor }}" >> $GITHUB_STEP_SUMMARY - echo "**Action:** Release trigger was blocked due to insufficient permissions" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "Only authorized users can trigger automatic releases via changelog updates." >> $GITHUB_STEP_SUMMARY \ No newline at end of file diff --git a/.github/workflows/upload-source-documents.yml b/.github/workflows/upload-source-documents.yml deleted file mode 100644 index 69d6c3e48..000000000 --- a/.github/workflows/upload-source-documents.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: Upload Source Documents - -on: - push: - branches: [master] - workflow_dispatch: - -jobs: - push_files_to_crowdin: - name: Push files to Crowdin - if: github.repository == 'wailsapp/wails' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - - name: Verify Changed files - id: changed-files - uses: step-security/changed-files@3dbe17c78367e7d60f00d78ae6781a35be47b4a1 # v45.0.1 - with: - files: | - website/**/*.mdx - website/**/*.md - website/**/*.json - - - name: Setup Nodejs - uses: actions/setup-node@v2 - with: - node-version: 20.x - - - name: Setup Task - uses: arduino/setup-task@v1 - with: - version: 3.x - repo-token: ${{ secrets.GITHUB_TOKEN }} - - - name: Upload source documents - if: steps.changed-files.outputs.any_changed == 'true' - env: - CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} - working-directory: ./website - run: task crowdin:push diff --git a/.gitignore b/.gitignore index e7888b44a..620386a67 100644 --- a/.gitignore +++ b/.gitignore @@ -27,15 +27,7 @@ v2/pkg/parser/testproject/frontend/wails v2/test/kitchensink/frontend/public v2/test/kitchensink/build/darwin/desktop/kitchensink v2/test/kitchensink/frontend/package.json.md5 +/v2/internal/ffenestri/windows/test/cmake-build-debug/ +!v2/internal/ffenestri/windows/x64/webview2.dll +!v2/internal/ffenestri/windows/x64/WebView2Loader.dll .idea/ -v2/cmd/wails/internal/commands/initialise/templates/testtemplates/ -.env -/website/static/img/.cache.json - -/v3/.task -/v3/examples/build/bin/testapp -/websitev3/site/ -/v3/examples/plugins/bin/testapp - -# Temporary called mkdocs, should be renamed to more standard -website or similar -/mkdocs-website/site diff --git a/.goreleaser.yml b/.goreleaser.yml new file mode 100644 index 000000000..a5769985b --- /dev/null +++ b/.goreleaser.yml @@ -0,0 +1,34 @@ +# This is an example goreleaser.yaml file with some sane defaults. +# Make sure to check the documentation at http://goreleaser.com + +builds: +- env: + - CGO_ENABLED=0 + goos: + - windows + - linux + - darwin + goarch: + - 386 + - amd64 + ignore: + - goos: darwin + goarch: 386 + main: ./cmd/wails/main.go +archive: + replacements: + darwin: Darwin + linux: Linux + windows: Windows + 386: i386 + amd64: x86_64 +checksum: + name_template: 'checksums.txt' +snapshot: + name_template: "{{ .Tag }}-next" +changelog: + sort: asc + filters: + exclude: + - '^docs:' + - '^test:' diff --git a/.hound.yml b/.hound.yml new file mode 100644 index 000000000..c74b4a197 --- /dev/null +++ b/.hound.yml @@ -0,0 +1,6 @@ +jshint: + config_file: .jshintrc +eslint: + enabled: true + config_file: .eslintrc + ignore_file: .eslintignore \ No newline at end of file diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 000000000..53b202cb9 --- /dev/null +++ b/.jshintrc @@ -0,0 +1,3 @@ +{ + "esversion": 6 +} \ No newline at end of file diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index 52b962c55..000000000 --- a/.prettierignore +++ /dev/null @@ -1,3 +0,0 @@ -website -v2 -v3 \ No newline at end of file diff --git a/.prettierrc.yml b/.prettierrc.yml deleted file mode 100644 index 685d8b6e7..000000000 --- a/.prettierrc.yml +++ /dev/null @@ -1,6 +0,0 @@ -overrides: - - files: - - "**/*.md" - options: - printWidth: 80 - proseWrap: always diff --git a/.replit b/.replit deleted file mode 100644 index 619bd7227..000000000 --- a/.replit +++ /dev/null @@ -1,8 +0,0 @@ -modules = ["go-1.21", "web", "nodejs-20"] -run = "go run v2/cmd/wails/main.go" - -[nix] -channel = "stable-24_05" - -[deployment] -run = ["sh", "-c", "go run v2/cmd/wails/main.go"] diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..51158b5ba --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,48 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Test cmd package", + "type": "go", + "request": "launch", + "mode": "test", + "program": "${workspaceFolder}/cmd/" + }, + { + "name": "Wails Init", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${workspaceFolder}/cmd/wails/main.go", + "env": {}, + "cwd": "/tmp", + "args": [ + "init", + "-name", + "runtime", + "-dir", + "runtime", + "-output", + "runtime", + "-template", + "vuebasic" + ] + }, + { + "name": "Wails Update Pre", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${workspaceFolder}/cmd/wails/main.go", + "env": {}, + "cwd": "/tmp", + "args": [ + "update", + "-pre" + ] + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..da2d84ba6 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "go.formatTool": "goimports", + "eslint.alwaysShowStatus": true, + "files.associations": { + "__locale": "c", + "ios": "c" + } +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 62b09b25f..e74282965 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1 +1,34 @@ -The current changelog may be found at: https://wails.io/changelog/ + +2019-07-20 **v0.17.6-pre** +* Significant refactor of runtime +* Removed wailsbridge file - now a unified approach taken +* Fixed React on Windows - Thanks [Florian Didran](https://github.com/fdidron)! + +2019-06-18 **v0.16.0** +* React template FTW! - Thanks [admin_3.exe](https://github.com/bh90210)! +* Updated contributors +* Arch Linux detection without lsb-release +* Removed deprecated methods for dealing with JS/CSS in the backend + +2019-05-29 **v0.14.11-pre** +* Windows fix for spinner + +2019-05-29 **v0.14.10-pre** +* Windows fix for Vuetify + +2019-05-29 **v0.14.9-pre** +* Vuetify project template 🎉 + +2019-05-29 **v0.14.8-pre** +* Updated Ubuntu npm install command + +2019-05-22 **v0.14.7-pre** +* New projects are built automatically when initialised +* Go 1.12 is now a minimum requirement + +2019-05-21 **v0.14.6-pre** +* Hotfix for module dependency issue + +2019-05-20 **v0.14.5-pre** +* Added developer tooling - New Template Generator +* Documentation fixes - Thanks [admin_3.exe](https://github.com/bh90210)! diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index aa53c412a..000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1 +0,0 @@ -The current Contribution Guidelines can be found at: https://wails.io/community-guide diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index a7b5a60ab..72d6bd9d9 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -1,2 +1,48 @@ +# Contributors -The latest contributors list may be found at: https://wails.io/credits#contributors \ No newline at end of file +Wails is what it is because of the time and effort given by these great people. A huge thank you to each and every one! + + * [Dustin Krysak](https://wiki.ubuntu.com/bashfulrobot) + * [Qais Patankar](https://github.com/qaisjp) + * [Anthony Lee](https://github.com/alee792) + * [Adrian Lanzafame](https://github.com/lanzafame) + * [Mattn](https://github.com/mattn) + * [0xflotus](https://github.com/0xflotus) + * [Michael D Henderson](https://github.com/mdhender) + * [fred2104](https://github.com/fishfishfish2104) + * [intelwalk](https://github.com/intelwalk) + * [Mark Stenglein](https://github.com/ocelotsloth) + * [admin_3.exe](https://github.com/bh90210) + * [iceleo-com](https://github.com/iceleo-com) + * [fallendusk](https://github.com/fallendusk) + * [Nikolai Zimmermann](https://github.com/Chronophylos) + * [Toyam Cox](https://github.com/Vaelatern) + * [Robin Eklind](https://github.com/mewmew) + * [Kris Raney](https://github.com/kraney) + * [Jack Mordaunt](https://github.com/JackMordaunt) + * [Michael Hipp](https://github.com/MichaelHipp) + * [Travis McLane](https://github.com/tmclane) + * [Reuben Thomas-Davis](https://github.com/Rested) + * [Jarek](https://github.com/Jarek-SRT) + * [Konez2k](https://github.com/konez2k) + * [msms](https://github.com/sayuthisobri) + * [dedo1911](https://github.com/dedo1911) + * [Florian Didron](https://github.com/fdidron) + * [Christopher Murphy](https://github.com/Splode) + * [Zámbó, Levente](https://github.com/Lyimmi) + * [artem](https://github.com/Unix4ever) +* [Tim Kipp](https://github.com/timkippdev) +* [Dmitry Gomzyakov](https://github.com/kyoto44) +* [Arthur Wiebe](https://github.com/artooro) +* [Ilgıt Yıldırım](https://github.com/ilgityildirim) +* [Altynbek](https://github.com/gelleson) +* [Kyle](https://github.com/kmuchmore) +* [Balakrishna Prasad Ganne](https://github.com/aayush420) +* [Charaf Rezrazi](https://github.com/Rezrazi) +* [misitebao](https://github.com/misitebao) +* [Elie Grenon](https://github.com/DrunkenPoney) +* [SophieAu](https://github.com/SophieAu) +* [Alexander Matviychuk](https://github.com/alexmat) +* [RH12503](https://github.com/RH12503) +* [hi019](https://github.com/hi019) +* [Igor Minen](https://github.com/Igogrek) diff --git a/README.de.md b/README.de.md deleted file mode 100644 index 5df35de5b..000000000 --- a/README.de.md +++ /dev/null @@ -1,160 +0,0 @@ -

-
-

- -

-Erschaffe Desktop Anwendungen mit Go & Web Technologien. -
-
- - GitHub - - - - - - Go Reference - - - CodeFactor - - - - - - Awesome - - - Discord - -
- - Build - - - GitHub tag (latest SemVer pre-release) - -

- -
- - - -[English](README.md) · [简体中文](README.zh-Hans.md) · [日本語](README.ja.md) · -[한국어](README.ko.md) · [Español](README.es.md) · [Português](README.pt-br.md) · -[Русский](README.ru.md) · [Francais](README.fr.md) · [Uzbek](README.uz.md) · [Deutsch](README.de.md) - - - -
- -## Inhaltsverzeichnis - -- [Inhaltsverzeichnis](#inhaltsverzeichnis) -- [Einführung](#einführung) -- [Funktionen](#funktionen) - - [Roadmap](#roadmap) -- [Loslegen](#loslegen) -- [Sponsoren](#sponsoren) -- [FAQ](#faq) -- [Sterne Überblick](#sterne-überblick) -- [Mitwirkende](#mitwirkende) -- [Lizenz](#lizenz) -- [Inspiration](#inspiration) - -## Einführung - -Die herkömmliche Methode zur Bereitstellung von Web-Interfaces für Go ist über einen eingebauten Webserver. -Wails nutzt einen anderen Weg. Es kann sowohl Go-Code als auch ein Web-Frontend in eine einzige Datei bauen. -Beigelieferte Werkzeuge übernehmen die Projekterstellung, den Kompilierungsprozess und das bauen. -Du musst nur kreativ werden. - -## Funktionen - -- Nutze Standard Go für das Backend -- Nutze eine Frontend Technologie mit der du dich bereits auskennst um dein UI zu bauen. -- Erschaffe schnell und einfach Frontends mit vorgefertigten Vorlagen für deine Go-Programme -- Nutze Javascript um Go Methoden aufzurufen -- Automatisch generierte Typescript Definitionen für deine Go Strukturen und Methoden -- Native Dialoge und Menüs -- Native Dark-/Lightmode Unterstützung -- Unterstützt moderne Transluzenz- und Milchglaseffekte -- Vereinheitlichtes Eventsystem zwischen Go und Javascript -- Leistungsstarkes CLI-Tool zum einfachen erstellen und bauen von Projekten -- Multiplattformen -- Nutze native Render-Engines - _keine eingebetteten Browser_! - -### Roadmap - -Die Projekt Roadmap kann [hier](https://github.com/wailsapp/wails/discussions/1484) gefunden werden. Bitte lies diese -durch bevor du eine Idee vorschlägst - -## Loslegen - -Die Installationsinstruktionen sind auf der [offiziellen Website](https://wails.io/docs/gettingstarted/installation). - -## Sponsoren - -Dieses Projekt wird von diesen freundlichen Leuten und Firmen unterstützt: - - -

- -

- -## FAQ - -- Ist das eine Alternative zu Electron? - - Hängt von deinen Anforderungen ab. Wails wurde entwickelt um das Go-Programmieren leicht zu machen und effiziente - Desktop-Anwendungen zu erstellen oder ein Frontend zu einer bestehenden Anwendung hinzuzufügen. - Wails bietet native Elemente wie Dialoge und Menüs und könnte somit als eine leichte effiziente Electron-Alternative - betrachtet werden. - -- Für wen ist dieses projekt geeignet? - - Go Entwickler, die ein HTML/CSS/JS-Frontend in ihre Anwendung integrieren möchten, ohne einen Webserver zu erstellen und - einen Browser öffnen zu müssen, um dieses zu sehen - -- Wie kam es zu diesem Namen? - - Als ich WebView sah dachte ich "Was ich wirklich will, ist ein Werkzeug für die Erstellung von WebView Anwendungen so wie Rails für Ruby". - Also war es zunächst ein Wortspiel (Webview on Rails). Zufälligerweise ist es auch ein Homophon des englischen Namens des [Landes](https://en.wikipedia.org/wiki/Wales), aus dem ich komme. - Also ist es dabei geblieben. - -## Sterne Überblick - - - - - - Star History Chart - - - -## Mitwirkende - -Die Liste der Mitwirkenden wird zu groß für diese Readme. All die fantastischen Menschen, die zu diesem -Projekt beigetragen haben, haben [hier](https://wails.io/credits#contributors) ihre eigene Seite. - -## Lizenz - -[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fwailsapp%2Fwails.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fwailsapp%2Fwails?ref=badge_large) - -## Inspiration - -Dieses Projekt wurde hauptsächlich zu den folgenden Alben entwickelt - -- [Manic Street Preachers - Resistance Is Futile](https://open.spotify.com/album/1R2rsEUqXjIvAbzM0yHrxA) -- [Manic Street Preachers - This Is My Truth, Tell Me Yours](https://open.spotify.com/album/4VzCL9kjhgGQeKCiojK1YN) -- [The Midnight - Endless Summer](https://open.spotify.com/album/4Krg8zvprquh7TVn9OxZn8) -- [Gary Newman - Savage (Songs from a Broken World)](https://open.spotify.com/album/3kMfsD07Q32HRWKRrpcexr) -- [Steve Vai - Passion & Warfare](https://open.spotify.com/album/0oL0OhrE2rYVns4IGj8h2m) -- [Ben Howard - Every Kingdom](https://open.spotify.com/album/1nJsbWm3Yy2DW1KIc1OKle) -- [Ben Howard - Noonday Dream](https://open.spotify.com/album/6astw05cTiXEc2OvyByaPs) -- [Adwaith - Melyn](https://open.spotify.com/album/2vBE40Rp60tl7rNqIZjaXM) -- [Gwidaith Hen Fran - Cedors Hen Wrach](https://open.spotify.com/album/3v2hrfNGINPLuDP0YDTOjm) -- [Metallica - Metallica](https://open.spotify.com/album/2Kh43m04B1UkVcpcRa1Zug) -- [Bloc Party - Silent Alarm](https://open.spotify.com/album/6SsIdN05HQg2GwYLfXuzLB) -- [Maxthor - Another World](https://open.spotify.com/album/3tklE2Fgw1hCIUstIwPBJF) -- [Alun Tan Lan - Y Distawrwydd](https://open.spotify.com/album/0c32OywcLpdJCWWMC6vB8v) diff --git a/README.es.md b/README.es.md deleted file mode 100644 index 277d1c1fd..000000000 --- a/README.es.md +++ /dev/null @@ -1,169 +0,0 @@ -

-
-

- -

- Construye aplicaciones de escritorio usando Go y tecnologías web. -
-
- - GitHub - - - - - - Go Reference - - - CodeFactor - - - - - - Awesome - - - Discord - -
- - Build - - - GitHub tag (latest SemVer pre-release) - -

- -
- - - -[English](README.md) · [简体中文](README.zh-Hans.md) · [日本語](README.ja.md) · -[한국어](README.ko.md) · [Español](README.es.md) · [Português](README.pt-br.md) · -[Русский](README.ru.md) · [Francais](README.fr.md) · [Uzbek](README.uz.md) · [Deutsch](README.de.md) · -[Türkçe](README.tr.md) - - - -
- -## Tabla de Contenidos - -- [Tabla de Contenidos](#tabla-de-contenidos) -- [Introducción](#introducción) -- [Funcionalidades](#funcionalidades) - - [Plan de Trabajo](#plan-de-trabajo) -- [Empezando](#empezando) -- [Patrocinadores](#patrocinadores) -- [Preguntas Frecuentes](#preguntas-frecuentes) -- [Estrellas a lo Largo del Tiempo](#estrellas-a-lo-largo-del-tiempo) -- [Colaboradores](#colaboradores) -- [Licencia](#licencia) -- [Inspiración](#inspiración) - -## Introducción - -El método tradicional para proveer una interfaz web en programas hechos con Go -es a través del servidor web incorporado. Wails ofrece un enfoque diferente al -permitir combinar el código hecho en Go con un frontend web en un solo archivo -binario. Las herramientas que proporcionamos facilitan este trabajo para ti, al -crear, compilar y empaquetar tu proyecto. ¡Lo único que debes hacer es ponerte -creativo! - -## Funcionalidades - -- Utiliza Go estándar para el backend -- Utiliza cualquier tecnología frontend con la que ya estés familiarizado para - construir tu interfaz de usuario -- Crea rápidamente interfaces de usuario enriquecidas para tus programas en Go - utilizando plantillas predefinidas -- Invoca fácilmente métodos de Go desde Javascript -- Definiciones de Typescript generadas automáticamente para tus structs y - métodos de Go -- Diálogos y menús nativos -- Soporte nativo de modo oscuro / claro -- Soporte de translucidez y efectos de ventana esmerilada -- Sistema de eventos unificado entre Go y Javascript -- Herramienta CLI potente para generar y construir tus proyectos rápidamente -- Multiplataforma -- Usa motores de renderizado nativos - ¡_sin navegador integrado_! - -### Plan de Trabajo - -El plan de trabajo se puede encontrar -[aqui](https://github.com/wailsapp/wails/discussions/1484). Por favor, -consúltalo antes de abrir una solicitud de mejora. - -## Empezando - -Las instrucciones de instalacion se encuentran en nuestra -[pagina web oficial](https://wails.io/docs/gettingstarted/installation). - -## Patrocinadores - -Este Proyecto cuenta con el apoyo de estas amables personas/ compañías: - - -

- -

- -## Preguntas Frecuentes - -- ¿Es esta una alternativa a Electron? - - Depende de tus requisitos. Está diseñado para facilitar a los programadores de - Go la creación de aplicaciones de escritorio livianas o agregar una interfaz - gráfica a sus aplicaciones existentes. Wails ofrece elementos nativos como - menús y diálogos, por lo que podría considerarse una alternativa liviana a - Electron. - -- ¿A quien esta dirigido este proyecto? - - El proyecto esta dirigido a programadores de Go que desean integrar una - interfaz HMTL/JS/CSS en sus aplicaciones, sin tener que recurrir a la creación - de un servidor y abrir el navegador para visualizarla. - -- ¿Cual es el significado del nombre? - - Cuando vi WebView, pensé: "Lo que realmente quiero es una herramienta para - construir una aplicación WebView, algo similar a lo que Rails es para Ruby". - Así que inicialmente fue un juego de palabras (WebView en Rails). Además, por - casualidad, también es homófono del nombre en inglés del - [país](https://en.wikipedia.org/wiki/Wales) del que provengo. Así que se quedó - con ese nombre. - -## Estrellas a lo Largo del Tiempo - -[![Star History Chart](https://api.star-history.com/svg?repos=wailsapp/wails&type=Date)](https://star-history.com/#wailsapp/wails&Date) - -## Colaboradores - -¡La lista de colaboradores se está volviendo demasiado grande para el archivo -readme! Todas las personas increíbles que han contribuido a este proyecto tienen -su propia página [aqui](https://wails.io/credits#contributors). - -## Licencia - -[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fwailsapp%2Fwails.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fwailsapp%2Fwails?ref=badge_large) - -## Inspiración - -Este proyecto fue construido mientras se escuchaban estos álbumes: - -- [Manic Street Preachers - Resistance Is Futile](https://open.spotify.com/album/1R2rsEUqXjIvAbzM0yHrxA) -- [Manic Street Preachers - This Is My Truth, Tell Me Yours](https://open.spotify.com/album/4VzCL9kjhgGQeKCiojK1YN) -- [The Midnight - Endless Summer](https://open.spotify.com/album/4Krg8zvprquh7TVn9OxZn8) -- [Gary Newman - Savage (Songs from a Broken World)](https://open.spotify.com/album/3kMfsD07Q32HRWKRrpcexr) -- [Steve Vai - Passion & Warfare](https://open.spotify.com/album/0oL0OhrE2rYVns4IGj8h2m) -- [Ben Howard - Every Kingdom](https://open.spotify.com/album/1nJsbWm3Yy2DW1KIc1OKle) -- [Ben Howard - Noonday Dream](https://open.spotify.com/album/6astw05cTiXEc2OvyByaPs) -- [Adwaith - Melyn](https://open.spotify.com/album/2vBE40Rp60tl7rNqIZjaXM) -- [Gwidaith Hen Fran - Cedors Hen Wrach](https://open.spotify.com/album/3v2hrfNGINPLuDP0YDTOjm) -- [Metallica - Metallica](https://open.spotify.com/album/2Kh43m04B1UkVcpcRa1Zug) -- [Bloc Party - Silent Alarm](https://open.spotify.com/album/6SsIdN05HQg2GwYLfXuzLB) -- [Maxthor - Another World](https://open.spotify.com/album/3tklE2Fgw1hCIUstIwPBJF) -- [Alun Tan Lan - Y Distawrwydd](https://open.spotify.com/album/0c32OywcLpdJCWWMC6vB8v) - [Alun Tan Lan - Y Distawrwydd](https://open.spotify.com/album/0c32OywcLpdJCWWMC6vB8v) diff --git a/README.fr.md b/README.fr.md deleted file mode 100644 index 61230f353..000000000 --- a/README.fr.md +++ /dev/null @@ -1,144 +0,0 @@ -

-
-

- -

- Créer des applications de bureau avec Go et les technologies Web. -
-
- - GitHub - - - - - - Go Reference - - - CodeFactor - - - - - - Awesome - - - Discord - -
- - Build - - - GitHub tag (latest SemVer pre-release) - -

- -
- - - -[English](README.md) · [简体中文](README.zh-Hans.md) · [日本語](README.ja.md) · -[한국어](README.ko.md) · [Español](README.es.md) · [Português](README.pt-br.md) · -[Русский](README.ru.md) · [Francais](README.fr.md) · [Uzbek](README.uz.md) · [Deutsch](README.de.md) · -[Türkçe](README.tr.md) - - - -
- -## Sommaire - -- [Sommaire](#sommaire) -- [Introduction](#introduction) -- [Fonctionnalités](#fonctionnalités) - - [Feuille de route](#feuille-de-route) -- [Démarrage](#démarrage) -- [Les sponsors](#les-sponsors) -- [Foire aux questions](#foire-aux-questions) -- [Les étoiles au fil du temps](#les-étoiles-au-fil-du-temps) -- [Les contributeurs](#les-contributeurs) -- [License](#license) -- [Inspiration](#inspiration) - -## Introduction - -La méthode traditionnelle pour fournir des interfaces web aux programmes Go consiste à utiliser un serveur web intégré. Wails propose une approche différente : il offre la possibilité d'intégrer à la fois le code Go et une interface web dans un seul binaire. Des outils sont fournis pour vous faciliter la tâche en gérant la création, la compilation et le regroupement des projets. Il ne vous reste plus qu'à faire preuve de créativité! - -## Fonctionnalités - -- Utiliser Go pour le backend -- Utilisez n'importe quelle technologie frontend avec laquelle vous êtes déjà familier pour construire votre interface utilisateur. -- Créez rapidement des interfaces riches pour vos programmes Go à l'aide de modèles prédéfinis. -- Appeler facilement des méthodes Go à partir de Javascript -- Définitions Typescript auto-générées pour vos structures et méthodes Go -- Dialogues et menus natifs -- Prise en charge native des modes sombre et clair -- Prise en charge des effets modernes de translucidité et de "frosted window". -- Système d'événements unifié entre Go et Javascript -- Outil puissant pour générer et construire rapidement vos projets -- Multiplateforme -- Utilise des moteurs de rendu natifs - _pas de navigateur intégré_ ! - -### Feuille de route - -La feuille de route du projet peut être consultée [ici](https://github.com/wailsapp/wails/discussions/1484). Veuillez consulter avant d'ouvrir une demande d'amélioration. - -## Démarrage - -Les instructions d'installation se trouvent sur le site [site officiel](https://wails.io/docs/gettingstarted/installation). - -## Les sponsors - -Ce projet est soutenu par ces personnes aimables et entreprises: - - -

- -

- -## Foire aux questions - -- S'agit-il d'une alternative à Electron ? - - Cela dépend de vos besoins. Il est conçu pour permettre aux programmeurs Go de créer facilement des applications de bureau légères ou d'ajouter une interface à leurs applications existantes. Wails offre des éléments natifs tels que des menus et des boîtes de dialogue, il peut donc être considéré comme une alternative légère à electron. - -- À qui s'adresse ce projet ? - - Les programmeurs Go qui souhaitent intégrer une interface HTML/JS/CSS à leurs applications, sans avoir à créer un serveur et à ouvrir un navigateur pour l'afficher. - -- Pourquoi ce nom ?? - - Lorsque j'ai vu WebView, je me suis dit : "Ce que je veux vraiment, c'est un outil pour construire une application WebView, un peu comme Rails l'est pour Ruby". Au départ, il s'agissait donc d'un jeu de mots (Webview on Rails). Il se trouve que c'est aussi un homophone du nom anglais du [Pays](https://en.wikipedia.org/wiki/Wales) d'où je viens. Il s'est donc imposé. - -## Les étoiles au fil du temps - -[![Graphique de l'histoire des étoiles](https://api.star-history.com/svg?repos=wailsapp/wails&type=Date)](https://star-history.com/#wailsapp/wails&Date) - -## Les contributeurs - -La liste des contributeurs devient trop importante pour le readme ! Toutes les personnes extraordinaires qui ont contribué à ce projet ont leur propre page [ici](https://wails.io/credits#contributors). - -## License - -[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fwailsapp%2Fwails.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fwailsapp%2Fwails?ref=badge_large) - -## Inspiration - -Ce projet a été principalement codé sur les albums suivants : - -- [Manic Street Preachers - Resistance Is Futile](https://open.spotify.com/album/1R2rsEUqXjIvAbzM0yHrxA) -- [Manic Street Preachers - This Is My Truth, Tell Me Yours](https://open.spotify.com/album/4VzCL9kjhgGQeKCiojK1YN) -- [The Midnight - Endless Summer](https://open.spotify.com/album/4Krg8zvprquh7TVn9OxZn8) -- [Gary Newman - Savage (Songs from a Broken World)](https://open.spotify.com/album/3kMfsD07Q32HRWKRrpcexr) -- [Steve Vai - Passion & Warfare](https://open.spotify.com/album/0oL0OhrE2rYVns4IGj8h2m) -- [Ben Howard - Every Kingdom](https://open.spotify.com/album/1nJsbWm3Yy2DW1KIc1OKle) -- [Ben Howard - Noonday Dream](https://open.spotify.com/album/6astw05cTiXEc2OvyByaPs) -- [Adwaith - Melyn](https://open.spotify.com/album/2vBE40Rp60tl7rNqIZjaXM) -- [Gwidaith Hen Fran - Cedors Hen Wrach](https://open.spotify.com/album/3v2hrfNGINPLuDP0YDTOjm) -- [Metallica - Metallica](https://open.spotify.com/album/2Kh43m04B1UkVcpcRa1Zug) -- [Bloc Party - Silent Alarm](https://open.spotify.com/album/6SsIdN05HQg2GwYLfXuzLB) -- [Maxthor - Another World](https://open.spotify.com/album/3tklE2Fgw1hCIUstIwPBJF) -- [Alun Tan Lan - Y Distawrwydd](https://open.spotify.com/album/0c32OywcLpdJCWWMC6vB8v) diff --git a/README.ja.md b/README.ja.md deleted file mode 100644 index ffd9f8103..000000000 --- a/README.ja.md +++ /dev/null @@ -1,152 +0,0 @@ -

Wails

- -

-
-

- -

- GoとWebの技術を用いてデスクトップアプリケーションを構築します。 -
-
- - GitHub - - - - - - Go Reference - - - CodeFactor - - - - - - Awesome - - - Discord - -
- - Build - - - GitHub tag (latest SemVer pre-release) - -

- -
- - - -[English](README.md) · [简体中文](README.zh-Hans.md) · [日本語](README.ja.md) · -[한국어](README.ko.md) · [Español](README.es.md) · [Português](README.pt-br.md) · -[Русский](README.ru.md) · [Francais](README.fr.md) · [Uzbek](README.uz.md) · [Deutsch](README.de.md) · -[Türkçe](README.tr.md) - - - -
- -## 目次 - -- [目次](#目次) -- [はじめに](#はじめに) -- [特徴](#特徴) - - [ロードマップ](#ロードマップ) -- [始め方](#始め方) -- [スポンサー](#スポンサー) -- [FAQ](#faq) -- [スター数の推移](#スター数の推移) -- [コントリビューター](#コントリビューター) -- [ライセンス](#ライセンス) -- [インスピレーション](#インスピレーション) - - -## はじめに - -Go プログラムにウェブインタフェースを提供する従来の方法は内蔵のウェブサーバを経由するものですが、 Wails では異なるアプローチを提供します。 -Wails では Go のコードとウェブフロントエンドを単一のバイナリにまとめる機能を提供します。 -また、プロジェクトの作成、コンパイル、ビルドを行うためのツールが提供されています。あなたがすべきことは創造性を発揮することです! - -## 特徴 - -- バックエンドには Go を利用しています -- 使い慣れたフロントエンド技術を利用して UI を構築できます -- あらかじめ用意されたテンプレートを利用することで、リッチなフロントエンドを備えた Go プログラムを素早く作成できます -- JavaScript から Go のメソッドを簡単に呼び出すことができます -- あなたの書いた Go の構造体やメソットに応じた TypeScript の定義が自動生成されます -- ネイティブのダイアログとメニューが利用できます -- ネイティブなダーク/ライトモードをサポートします -- モダンな半透明や「frosted window」エフェクトをサポートしています -- Go と JavaScript 間で統一されたイベント・システムを備えています -- プロジェクトを素早く生成して構築する強力な cli ツールを用意しています -- マルチプラットフォームに対応しています -- ネイティブなレンダリングエンジンを使用しています - _つまりブラウザを埋め込んでいるわけではありません!_ - -### ロードマップ - -プロジェクトのロードマップは[こちら](https://github.com/wailsapp/wails/discussions/1484)になります。 -機能拡張のリクエストを出す前にご覧ください。 - -## 始め方 - -インストール方法は[公式サイト](https://wails.io/docs/gettingstarted/installation)に掲載されています。 - -## スポンサー - -このプロジェクトは、以下の方々・企業によって支えられています。 - - -## FAQ - -- Electron の代替品になりますか? - - それはあなたの求める要件によります。Wails は Go プログラマーが簡単に軽量のデスクトップアプリケーションを作成したり、既存のアプリケーションにフロントエンドを追加できるように設計されています。 - Wails v2 ではメニューやダイアログといったネイティブな要素を提供するようになったため、軽量な Electron の代替となりつつあります。 - -- このプロジェクトは誰に向けたものですか? - - HTML/JS/CSS のフロントエンド技術をアプリケーションにバンドルさせることで、サーバーを作成してブラウザ経由で表示させることなくアプリケーションを利用したい Go プログラマにおすすめです。 - -- 名前の由来を教えて下さい - - WebView を見たとき、私はこう思いました。 - 「私が本当に欲しいのは、WebView アプリを構築するためのツールであり、Ruby に対する Rails のようなものである」と。 - そのため、最初は言葉遊びのつもりでした(Webview on Rails)。 - また、私の[出身国](https://en.wikipedia.org/wiki/Wales)の英語名と同音異義語でもあります。そしてこの名前が定着しました。 - -## スター数の推移 - -[![Star History Chart](https://api.star-history.com/svg?repos=wailsapp/wails&type=Date)](https://star-history.com/#wailsapp/wails&Date) - -## コントリビューター - -貢献してくれた方のリストが大きくなりすぎて、readme に入りきらなくなりました! -このプロジェクトに貢献してくれた素晴らしい方々のページは[こちら](https://wails.io/credits#contributors)です。 - -## ライセンス - -[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fwailsapp%2Fwails.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fwailsapp%2Fwails?ref=badge_large) - -## インスピレーション - -プロジェクトを進める際に、以下のアルバムたちも支えてくれています。 - -- [Manic Street Preachers - Resistance Is Futile](https://open.spotify.com/album/1R2rsEUqXjIvAbzM0yHrxA) -- [Manic Street Preachers - This Is My Truth, Tell Me Yours](https://open.spotify.com/album/4VzCL9kjhgGQeKCiojK1YN) -- [The Midnight - Endless Summer](https://open.spotify.com/album/4Krg8zvprquh7TVn9OxZn8) -- [Gary Newman - Savage (Songs from a Broken World)](https://open.spotify.com/album/3kMfsD07Q32HRWKRrpcexr) -- [Steve Vai - Passion & Warfare](https://open.spotify.com/album/0oL0OhrE2rYVns4IGj8h2m) -- [Ben Howard - Every Kingdom](https://open.spotify.com/album/1nJsbWm3Yy2DW1KIc1OKle) -- [Ben Howard - Noonday Dream](https://open.spotify.com/album/6astw05cTiXEc2OvyByaPs) -- [Adwaith - Melyn](https://open.spotify.com/album/2vBE40Rp60tl7rNqIZjaXM) -- [Gwidaith Hen Fran - Cedors Hen Wrach](https://open.spotify.com/album/3v2hrfNGINPLuDP0YDTOjm) -- [Metallica - Metallica](https://open.spotify.com/album/2Kh43m04B1UkVcpcRa1Zug) -- [Bloc Party - Silent Alarm](https://open.spotify.com/album/6SsIdN05HQg2GwYLfXuzLB) -- [Maxthor - Another World](https://open.spotify.com/album/3tklE2Fgw1hCIUstIwPBJF) -- [Alun Tan Lan - Y Distawrwydd](https://open.spotify.com/album/0c32OywcLpdJCWWMC6vB8v) - diff --git a/README.ko.md b/README.ko.md deleted file mode 100644 index 075e04229..000000000 --- a/README.ko.md +++ /dev/null @@ -1,155 +0,0 @@ -

Wails

- -

-
-

- -

- Go & Web 기술을 사용하여 데스크탑 애플리케이션을 빌드하세요. -
-
- - GitHub - - - - - - Go Reference - - - CodeFactor - - - - - - Awesome - - - Discord - -
- - Build - - - GitHub tag (latest SemVer pre-release) - -

- -
- - - -[English](README.md) · [简体中文](README.zh-Hans.md) · [日本語](README.ja.md) · -[한국어](README.ko.md) · [Español](README.es.md) · [Português](README.pt-br.md) · -[Русский](README.ru.md) · [Francais](README.fr.md) · [Uzbek](README.uz.md) · [Deutsch](README.de.md) · -[Türkçe](README.tr.md) - - - -
- -## 목차 - -- [목차](#목차) -- [소개](#소개) -- [기능](#기능) - - [로드맵](#로드맵) -- [시작하기](#시작하기) -- [스폰서](#스폰서) -- [FAQ](#faq) -- [Stargazers 성장 추세](#stargazers-성장-추세) -- [기여자](#기여자) -- [라이센스](#라이센스) -- [영감](#영감) - -## 소개 - -Go 프로그램에 웹 인터페이스를 제공하는 전통적인 방법은 내장 웹 서버를 이용하는 것입니다. -Wails는 다르게 접근합니다: Go 코드와 웹 프론트엔드를 단일 바이너리로 래핑하는 기능을 제공합니다. -프로젝트 생성, 컴파일 및 번들링을 처리하여 이를 쉽게 수행할 수 있도록 도구가 제공됩니다. -창의력을 발휘하기만 하면 됩니다! - -## 기능 - -- 백엔드에 표준 Go 사용 -- 이미 익숙한 프론트엔드 기술을 사용하여 UI 구축 -- 사전 구축된 템플릿을 사용하여 Go 프로그램을 위한 풍부한 프론트엔드를 빠르게 생성 -- Javascript에서 Go 메서드를 쉽게 호출 -- Go 구조체 및 메서드에 대한 자동 생성된 Typescript 정의 -- 기본 대화 및 메뉴 -- 네이티브 다크/라이트 모드 지원 -- 최신 반투명도 및 "반투명 창" 효과 지원 -- Go와 Javascript 간의 통합 이벤트 시스템 -- 프로젝트를 빠르게 생성하고 구축하는 강력한 CLI 도구 -- 멀티플랫폼 -- 기본 렌더링 엔진 사용 - _내장 브라우저 없음_! - -### 로드맵 - -프로젝트 로드맵은 [여기](https://github.com/wailsapp/wails/discussions/1484)에서 -확인할 수 있습니다. 개선 요청을 하기 전에 이것을 참조하십시오. - -## 시작하기 - -설치 지침은 -[공식 웹사이트](https://wails.io/docs/gettingstarted/installation)에 있습니다. - -## 스폰서 - -이 프로젝트는 친절한 사람들 / 회사들이 지원합니다. - - -## FAQ - -- 이것은 Electron의 대안인가요? - - 요구 사항에 따라 다릅니다. Go 프로그래머가 쉽게 가벼운 데스크톱 애플리케이션을 - 만들거나 기존 애플리케이션에 프론트엔드를 추가할 수 있도록 설계되었습니다. - Wails는 메뉴 및 대화 상자와 같은 기본 요소를 제공하므로 가벼운 Electron 대안으로 - 간주될 수 있습니다. - -- 이 프로젝트는 누구를 대상으로 하나요? - - 서버를 생성하고 이를 보기 위해 브라우저를 열 필요 없이 HTML/JS/CSS 프런트엔드를 - 애플리케이션과 함께 묶고자 하는 프로그래머를 대상으로 합니다. - -- Wails 이름의 의미는 무엇인가요? - - WebView를 보았을 때 저는 "내가 정말로 원하는 것은 WebView 앱을 구축하기 위한 - 도구를 사용하는거야. 마치 Ruby on Rails 처럼 말이야."라고 생각했습니다. - 그래서 처음에는 말장난(Webview on Rails)이었습니다. - [국가](https://en.wikipedia.org/wiki/Wales)에 대한 영어 이름의 동음이의어이기도 하여 정했습니다. - -## Stargazers 성장 추세 - -[![Star History Chart](https://api.star-history.com/svg?repos=wailsapp/wails&type=Date)](https://star-history.com/#wailsapp/wails&Date) - -## 기여자 - -기여자 목록이 추가 정보에 비해 너무 커지고 있습니다! 이 프로젝트에 기여한 모든 놀라운 사람들은 -[여기](https://wails.io/credits#contributors)에 자신의 페이지를 가지고 있습니다. - -## 라이센스 - -[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fwailsapp%2Fwails.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fwailsapp%2Fwails?ref=badge_large) - -## 영감 - -이 프로젝트는 주로 다음 앨범을 들으며 코딩되었습니다. - -- [Manic Street Preachers - Resistance Is Futile](https://open.spotify.com/album/1R2rsEUqXjIvAbzM0yHrxA) -- [Manic Street Preachers - This Is My Truth, Tell Me Yours](https://open.spotify.com/album/4VzCL9kjhgGQeKCiojK1YN) -- [The Midnight - Endless Summer](https://open.spotify.com/album/4Krg8zvprquh7TVn9OxZn8) -- [Gary Newman - Savage (Songs from a Broken World)](https://open.spotify.com/album/3kMfsD07Q32HRWKRrpcexr) -- [Steve Vai - Passion & Warfare](https://open.spotify.com/album/0oL0OhrE2rYVns4IGj8h2m) -- [Ben Howard - Every Kingdom](https://open.spotify.com/album/1nJsbWm3Yy2DW1KIc1OKle) -- [Ben Howard - Noonday Dream](https://open.spotify.com/album/6astw05cTiXEc2OvyByaPs) -- [Adwaith - Melyn](https://open.spotify.com/album/2vBE40Rp60tl7rNqIZjaXM) -- [Gwidaith Hen Fran - Cedors Hen Wrach](https://open.spotify.com/album/3v2hrfNGINPLuDP0YDTOjm) -- [Metallica - Metallica](https://open.spotify.com/album/2Kh43m04B1UkVcpcRa1Zug) -- [Bloc Party - Silent Alarm](https://open.spotify.com/album/6SsIdN05HQg2GwYLfXuzLB) -- [Maxthor - Another World](https://open.spotify.com/album/3tklE2Fgw1hCIUstIwPBJF) -- [Alun Tan Lan - Y Distawrwydd](https://open.spotify.com/album/0c32OywcLpdJCWWMC6vB8v) diff --git a/README.md b/README.md index 5ab9309b4..545fd231a 100644 --- a/README.md +++ b/README.md @@ -1,114 +1,252 @@

-
+

-

- Build desktop applications using Go & Web Technologies. -
-
- - GitHub - - - - - - Go Reference - - - CodeFactor - - - - - - Awesome - - - Discord - -
- - Build - - - GitHub tag (latest SemVer pre-release) - + Build desktop applications using Go & Web Technologies.

+ + + + CodeFactor + CodeFactor + + + Awesome + Release Pipelines

-
- - + -[English](README.md) · [简体中文](README.zh-Hans.md) · [日本語](README.ja.md) · -[한국어](README.ko.md) · [Español](README.es.md) · [Português](README.pt-br.md) · -[Русский](README.ru.md) · [Francais](README.fr.md) · [Uzbek](README.uz.md) · [Deutsch](README.de.md) · -[Türkçe](README.tr.md) +## Internationalization - - -
- -## Table of Contents - -- [Table of Contents](#table-of-contents) -- [Introduction](#introduction) -- [Features](#features) - - [Roadmap](#roadmap) -- [Getting Started](#getting-started) -- [Sponsors](#sponsors) -- [FAQ](#faq) -- [Stargazers over time](#stargazers-over-time) -- [Contributors](#contributors) -- [License](#license) -- [Inspiration](#inspiration) - -## Introduction +English | [简体中文](README.zh-Hans.md) The traditional method of providing web interfaces to Go programs is via a built-in web server. Wails offers a different approach: it provides the ability to wrap both Go code and a web frontend into a single binary. Tools are provided to make this easy for you by handling project creation, compilation and bundling. All you have to do is get creative! +The official docs can be found at [https://wails.app](https://wails.app). + +Click [here](https://wails.io) if you are interested in trying out v2 Beta for Windows. + + + +## Contents + +- [1. Internationalization](#nav-1) +- [2. Contents](#nav-2) +- [3. Features](#nav-3) +- [4. Sponsors](#nav-4) +- [5. Installation](#nav-5) + - [5.1 MacOS](#nav-5-1) + - [5.2 Linux](#nav-5-2) + - [5.2.1 Debian/Ubuntu](#nav-5-2-1) + - [5.2.2 Arch Linux / ArchLabs / Ctlos Linux](#nav-5-2-2) + - [5.2.3 Centos](#nav-5-2-3) + - [5.2.4 Fedora](#nav-5-2-4) + - [5.2.5 VoidLinux & VoidLinux-musl](#nav-5-2-5) + - [5.2.6 Gentoo](#nav-5-2-6) + - [5.3 Windows](#nav-5-3) +- [6. Installation](#nav-6) +- [7. Next Steps](#nav-7) +- [8. FAQ](#nav-8) +- [9. Contributors](#nav-9) +- [10. Special Mentions](#nav-10) +- [11. Special Thanks](#nav-11) + + + ## Features - Use standard Go for the backend -- Use any frontend technology you are already familiar with to build your UI -- Quickly create rich frontends for your Go programs using pre-built templates -- Easily call Go methods from Javascript -- Auto-generated Typescript definitions for your Go structs and methods -- Native Dialogs & Menus -- Native Dark / Light mode support -- Supports modern translucency and "frosted window" effects -- Unified eventing system between Go and Javascript -- Powerful cli tool to quickly generate and build your projects +- Use any frontend technology to build your UI +- Quickly create Vue, Vuetify or React frontends for your Go programs +- Expose Go methods/functions to the frontend via a single bind command +- Uses native rendering engines - no embedded browser +- Shared events system +- Native file dialogs +- Powerful cli tool - Multiplatform -- Uses native rendering engines - _no embedded browser_! -### Roadmap - -The project roadmap may be found [here](https://github.com/wailsapp/wails/discussions/1484). Please consult -it before creating an enhancement request. - -## Getting Started - -The installation instructions are on the [official website](https://wails.io/docs/gettingstarted/installation). + ## Sponsors This project is supported by these kind people / companies: - -## Powered By + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -[![JetBrains logo.](https://resources.jetbrains.com/storage/products/company/brand/logos/jetbrains.svg)](https://jb.gg/OpenSource) + + +## Installation + +Wails uses cgo to bind to the native rendering engines so a number of platform dependent libraries are needed as well as +an installation of Go. The basic requirements are: + +- Go 1.16 +- npm + + + +### MacOS + +Make sure you have the xcode command line tools installed. This can be done by running: + +`xcode-select --install` + + + +### Linux + + + +#### Debian/Ubuntu + +`sudo apt install libgtk-3-dev libwebkit2gtk-4.0-dev` + +_Debian: 8, 9, 10_ + +_Ubuntu: 16.04, 18.04, 19.04_ + +_Also succesfully tested on: Zorin 15, Parrot 4.7, Linuxmint 19, Elementary 5, Kali, Neon_, Pop!\_OS + + + +#### Arch Linux / ArchLabs / Ctlos Linux + +`sudo pacman -S webkit2gtk gtk3` + +_Also succesfully test on: Manjaro & ArcoLinux_ + + + +#### Centos + +`sudo yum install webkitgtk3-devel gtk3-devel` + +_CentOS 6, 7_ + + + +#### Fedora + +`sudo yum install webkit2gtk3-devel gtk3-devel` + +_Fedora 29, 30_ + + + +#### VoidLinux & VoidLinux-musl + +`xbps-install gtk+3-devel webkit2gtk-devel` + + + +#### Gentoo + +`sudo emerge gtk+:3 webkit-gtk` + + + +### Windows + +Windows requires gcc and related tooling. The recommended download is +from [http://tdm-gcc.tdragon.net/download](http://tdm-gcc.tdragon.net/download). Once this is installed, you are good to +go. + + + +## Installation + +**Ensure Go modules are enabled: GO111MODULE=on and go/bin is in your PATH variable.** + +Installation is as simple as running the following command: + +
+go get -u github.com/wailsapp/wails/cmd/wails
+
+ + + +## Next Steps + +It is recommended at this stage to read the comprehensive documentation at [https://wails.app](https://wails.app). + + ## FAQ - Is this an alternative to Electron? Depends on your requirements. It's designed to make it easy for Go programmers to make lightweight desktop - applications or add a frontend to their existing applications. Wails does offer native elements such as menus - and dialogs, so it could be considered a lightweight electron alternative. + applications or add a frontend to their existing applications. Whilst Wails does not currently offer hooks into native + elements such as menus, this may change in the future. - Who is this project aimed at? @@ -121,26 +259,69 @@ This project is supported by these kind people / companies: Ruby". So initially it was a play on words (Webview on Rails). It just so happened to also be a homophone of the English name for the [Country](https://en.wikipedia.org/wiki/Wales) I am from. So it stuck. -## Stargazers over time - - - - - - Star History Chart - - + ## Contributors -The contributors list is getting too big for the readme! All the amazing people who have contributed to this -project have their own page [here](https://wails.io/credits#contributors). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -## License + -[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fwailsapp%2Fwails.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fwailsapp%2Fwails?ref=badge_large) +## Special Mentions -## Inspiration +Without the following people, this project would never have existed: + +- [Dustin Krysak](https://wiki.ubuntu.com/bashfulrobot) - His support and feedback has been immense. More patience than + you can throw a stick at (Not long now Dustin!). +- [Serge Zaitsev](https://github.com/zserge) - Creator of [Webview](https://github.com/zserge/webview) which Wails uses + for the windowing. +- [Byron](https://github.com/bh90210) - At times, Byron has single handedly kept this project alive. Without his + incredible input, we never would have got to v1. This project was mainly coded to the following albums: @@ -157,3 +338,19 @@ This project was mainly coded to the following albums: - [Bloc Party - Silent Alarm](https://open.spotify.com/album/6SsIdN05HQg2GwYLfXuzLB) - [Maxthor - Another World](https://open.spotify.com/album/3tklE2Fgw1hCIUstIwPBJF) - [Alun Tan Lan - Y Distawrwydd](https://open.spotify.com/album/0c32OywcLpdJCWWMC6vB8v) + + + +## Special Thanks + +

+
+ A huge thanks to Pace for sponsoring the project and helping the efforts to get Wails ported to Apple Silicon!

+ If you are looking for a Project Management tool that's powerful but quick and easy to use, check them out!

+

+ +

+ A special thank you to JetBrains for donating licenses to us!

+ Please click the logo to let them know your appreciation!

+ +

diff --git a/README.pt-br.md b/README.pt-br.md deleted file mode 100644 index 0e3883352..000000000 --- a/README.pt-br.md +++ /dev/null @@ -1,151 +0,0 @@ -

-
-

- -

- Crie aplicativos de desktop usando Go e tecnologias Web. -
-
- - GitHub - - - - - - Go Reference - - - CodeFactor - - - - - - Awesome - - - Discord - -
- - Build - - - GitHub tag (latest SemVer pre-release) - -

- -
- - - -[English](README.md) · [简体中文](README.zh-Hans.md) · [日本語](README.ja.md) · -[한국어](README.ko.md) · [Español](README.es.md) · [Português](README.pt-br.md) · [Francais](README.fr.md) · [Uzbek](README.uz.md) · [Deutsch](README.de.md) · -[Türkçe](README.tr.md) - - - -
- -## Índice - -- [Índice](#índice) -- [Introdução](#introdução) -- [Recursos e funcionalidades](#recursos-e-funcionalidades) - - [Plano de trabalho](#plano-de-trabalho) -- [Iniciando](#iniciando) -- [Patrocinadores](#patrocinadores) -- [Perguntas frequentes](#perguntas-frequentes) -- [Estrelas ao longo do tempo](#estrelas-ao-longo-do-tempo) -- [Colaboradores](#colaboradores) -- [Licença](#licença) -- [Inspiração](#inspiração) - -## Introdução - -O método tradicional de fornecer interfaces da Web para programas Go é por meio de um servidor da Web integrado. Wails oferece uma -abordagem: fornece a capacidade de agrupar o código Go e um front-end da Web em um único binário. As ferramentas são fornecidas para -que torne isso mais fácil para você lidando com a criação, compilação e agrupamento de projetos. Tudo o que você precisa fazer é ser criativo! - -## Recursos e funcionalidades - -- Use Go padrão para o back-end -- Use qualquer tecnologia de front-end com a qual você já esteja familiarizado para criar sua interface do usuário -- Crie rapidamente um front-end avançado para seus programas Go usando modelos pré-construídos -- Chame facilmente métodos Go com JavaScript -- Definições TypeScript geradas automaticamente para suas estruturas e métodos Go -- Diálogos e menus nativos -- Suporte nativo ao modo escuro/claro -- Suporta translucidez moderna e efeitos de "janela fosca" -- Sistema de eventos unificado entre Go e JavaScript -- Poderosa ferramenta cli para gerar e construir rapidamente seus projetos -- Multiplataforma -- Usa mecanismos de renderização nativos - _sem navegador incorporado_! - -### Plano de trabalho - -O plano de trabalho do projeto pode ser encontrado [aqui](https://github.com/wailsapp/wails/discussions/1484). Por favor consulte -isso antes de abrir um pedido de melhoria. - -## Iniciando - -As instruções de instalação estão no [site oficial](https://wails.io/docs/gettingstarted/installation). - -## Patrocinadores - -Este projeto é apoiado por estas simpáticas pessoas/empresas: - - -

- -

- -## Perguntas frequentes - -- Esta é uma alternativa ao Electron? - - Depende de seus requisitos. Ele foi projetado para tornar mais fácil para os programadores Go criar aplicações desktop - e adicionar um front-end aos seus aplicativos existentes. O Wails oferece elementos nativos, como menus - e diálogos, por isso pode ser considerada uma alternativa leve, se comparado ao Electron. - -- A quem se destina este projeto? - - Programadores Go que desejam agrupar um front-end HTML/JS/CSS com seus aplicativos, sem recorrer à criação de um - servidor e abrir um navegador para visualizá-lo. - -- Qual é o significado do nome? - - Quando vi o WebView, pensei "O que eu realmente quero é ferramentas para construir um aplicativo WebView, algo semelhante ao que Rails é para Ruby". Portanto, inicialmente era um jogo de palavras (WebView on Rails). Por acaso, também era um homófono do - Nome em inglês para o [país](https://en.wikipedia.org/wiki/Wales) de onde eu sou. Então ficou com esse nome. - -## Estrelas ao longo do tempo - -[![Star History Chart](https://api.star-history.com/svg?repos=wailsapp/wails&type=Date)](https://star-history.com/#wailsapp/wails&Date) - -## Colaboradores - -A lista de colaboradores está ficando grande demais para o arquivo readme! Todas as pessoas incríveis que contribuíram para o -projeto tem sua própria página [aqui](https://wails.io/credits#contributors). - -## Licença - -[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fwailsapp%2Fwails.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fwailsapp%2Fwails?ref=badge_large) - -## Inspiração - -Este projeto foi construído ouvindo esses álbuns: - -- [Manic Street Preachers - Resistance Is Futile](https://open.spotify.com/album/1R2rsEUqXjIvAbzM0yHrxA) -- [Manic Street Preachers - This Is My Truth, Tell Me Yours](https://open.spotify.com/album/4VzCL9kjhgGQeKCiojK1YN) -- [The Midnight - Endless Summer](https://open.spotify.com/album/4Krg8zvprquh7TVn9OxZn8) -- [Gary Newman - Savage (Songs from a Broken World)](https://open.spotify.com/album/3kMfsD07Q32HRWKRrpcexr) -- [Steve Vai - Passion & Warfare](https://open.spotify.com/album/0oL0OhrE2rYVns4IGj8h2m) -- [Ben Howard - Every Kingdom](https://open.spotify.com/album/1nJsbWm3Yy2DW1KIc1OKle) -- [Ben Howard - Noonday Dream](https://open.spotify.com/album/6astw05cTiXEc2OvyByaPs) -- [Adwaith - Melyn](https://open.spotify.com/album/2vBE40Rp60tl7rNqIZjaXM) -- [Gwidaith Hen Fran - Cedors Hen Wrach](https://open.spotify.com/album/3v2hrfNGINPLuDP0YDTOjm) -- [Metallica - Metallica](https://open.spotify.com/album/2Kh43m04B1UkVcpcRa1Zug) -- [Bloc Party - Silent Alarm](https://open.spotify.com/album/6SsIdN05HQg2GwYLfXuzLB) -- [Maxthor - Another World](https://open.spotify.com/album/3tklE2Fgw1hCIUstIwPBJF) -- [Alun Tan Lan - Y Distawrwydd](https://open.spotify.com/album/0c32OywcLpdJCWWMC6vB8v) diff --git a/README.ru.md b/README.ru.md deleted file mode 100644 index 76fa59d07..000000000 --- a/README.ru.md +++ /dev/null @@ -1,153 +0,0 @@ -

-
-

- -

- Собирайте Desktop приложения используя Go и Web технологии -
-
- - GitHub - - - - - - Go Reference - - - CodeFactor - - - - - - Awesome - - - Discord - -
- - Build - - - GitHub tag (latest SemVer pre-release) - -

- -
- - - -[English](README.md) · [简体中文](README.zh-Hans.md) · [日本語](README.ja.md) · -[한국어](README.ko.md) · [Español](README.es.md) · [Русский](README.ru.md) · [Francais](README.fr.md) · [Uzbek](README.uz.md) · [Deutsch](README.de.md) · -[Türkçe](README.tr.md) - - - -
- -## Содержание - -- [Содержание](#содержание) -- [Вступление](#вступление) -- [Особенности](#особенности) - - [Roadmap](#roadmap) -- [Быстрый старт](#быстрый-старт) -- [Спонсоры](#спонсоры) -- [FAQ](#faq) -- [График звёздочек](#график-звёздочек-репозитория-относительно-времени) -- [Контребьюторы](#контребьюторы) -- [Лицензия](#лицензия) -- [Вдохновение](#вдохновение) - -## Вступление - -Обычно, веб-интерфейсы для программ Go - это встроенный веб-сервер и веб-браузер. -У Walls другой подход: он оборачивает как код Go, так и веб-интерфейс в один бинарник (EXE файл). -Облегчает вам создание вашего приложения, управляя созданием, компиляцией и объединением проектов. -Все ограничивается лишь вашей фантазией! - -## Особенности - -- Использование Go для backend -- Поддержка любой frontend технологии, с которой вы уже знакомы для создания вашего UI -- Быстрое создание frontend для ваших программ, используя готовые шаблоны -- Очень лёгкий вызов функций Go из JavaScript -- Автогенерация TypeScript типов для Go структур и функций -- Нативные диалоги и меню -- Нативная поддержка тёмной и светлой темы -- Поддержка современных эффектов прозрачности и "матового окна" -- Единая система эвентов для Go и JavaScript -- Мощный CLI для быстрого создания ваших проектов -- Мультиплатформенность -- Использование нативного движка рендеринга - нет встроенному браузеру! - -### Roadmap - -Roadmap проекта вы можете найти [здесь](https://github.com/wailsapp/wails/discussions/1484). -Пожалуйста, проконсультируйтесь перед предложением улучшения. - -## Быстрый старт - -Инструкции по установке находятся на [официальном сайте](https://wails.io/docs/gettingstarted/installation). - -## Спонсоры - -Проект поддерживается этими добрыми людьми / компаниями: - - -

- -

- -## FAQ - -- Это альтернатива Electron? - - Зависит от ваших требований. Wails разработан для легкого создания Desktop приложений или - расширения интерфейсной части существующих приложений для программистов на Go. Wails действительно - предлагает встроенные элементы, такие как меню и диалоги, так что его можно считать облегченной альтернативой Electron. - -- Для кого предназначен этот проект? - - Для Golang программистов, которые хотят создавать приложения, используя HTML, JS и CSS, - без создания веб-сервера и открытия браузера для их просмотра. - -- Что это за название? - - Когда я увидел WebView, я подумал: "Что мне действительно нужно, так это инструменты для создания приложения WebView, - немного похожие на Rails для Ruby". Изначально это была игра слов (Webview on Rails). Просто так получилось, что это - также омофон английского названия для [Страны](https://en.wikipedia.org/wiki/Wales) от куда я родом. Так что это прижилось. - -## График звёздочек репозитория по времени - -[![График звёзд](https://api.star-history.com/svg?repos=wailsapp/wails&type=Date)](https://star-history.com/#wailsapp/wails&Date) - -## Контрибьюторы - -Список участников слишком велик для README! У всех замечательных людей, которые внесли свой вклад в этот -проект, есть своя [страничка](https://wails.io/credits#contributors). - -## Лицензия - -[![Статус FOSSA](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fwailsapp%2Fwails.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fwailsapp%2Fwails?ref=badge_large) - -## Вдохновение - -Этот проект был создан, в основном, под эти альбомы: - -- [Manic Street Preachers - Resistance Is Futile](https://open.spotify.com/album/1R2rsEUqXjIvAbzM0yHrxA) -- [Manic Street Preachers - This Is My Truth, Tell Me Yours](https://open.spotify.com/album/4VzCL9kjhgGQeKCiojK1YN) -- [The Midnight - Endless Summer](https://open.spotify.com/album/4Krg8zvprquh7TVn9OxZn8) -- [Gary Newman - Savage (Songs from a Broken World)](https://open.spotify.com/album/3kMfsD07Q32HRWKRrpcexr) -- [Steve Vai - Passion & Warfare](https://open.spotify.com/album/0oL0OhrE2rYVns4IGj8h2m) -- [Ben Howard - Every Kingdom](https://open.spotify.com/album/1nJsbWm3Yy2DW1KIc1OKle) -- [Ben Howard - Noonday Dream](https://open.spotify.com/album/6astw05cTiXEc2OvyByaPs) -- [Adwaith - Melyn](https://open.spotify.com/album/2vBE40Rp60tl7rNqIZjaXM) -- [Gwidaith Hen Fran - Cedors Hen Wrach](https://open.spotify.com/album/3v2hrfNGINPLuDP0YDTOjm) -- [Metallica - Metallica](https://open.spotify.com/album/2Kh43m04B1UkVcpcRa1Zug) -- [Bloc Party - Silent Alarm](https://open.spotify.com/album/6SsIdN05HQg2GwYLfXuzLB) -- [Maxthor - Another World](https://open.spotify.com/album/3tklE2Fgw1hCIUstIwPBJF) -- [Alun Tan Lan - Y Distawrwydd](https://open.spotify.com/album/0c32OywcLpdJCWWMC6vB8v) diff --git a/README.tr.md b/README.tr.md deleted file mode 100644 index e9b16ca76..000000000 --- a/README.tr.md +++ /dev/null @@ -1,156 +0,0 @@ -

-
-

- -

- Go ve Web Teknolojilerini kullanarak masaüstü uygulamaları oluşturun. -
-
- - GitHub - - - - - - Go Reference - - - CodeFactor - - - - - - Awesome - - - Discord - -
- - Build - - - GitHub tag (latest SemVer pre-release) - -

- -
- - - -[English](README.md) · [简体中文](README.zh-Hans.md) · [日本語](README.ja.md) · -[한국어](README.ko.md) · [Español](README.es.md) · [Português](README.pt-br.md) · -[Русский](README.ru.md) · [Francais](README.fr.md) · [Uzbek](README.uz.md) · -[Türkçe](README.tr.md) - - - -
- -## İçerik - -- [İçerik](#içerik) -- [Giriş](#giriş) -- [Özellikler](#özellikler) - - [Yol Haritası](#yol-haritası) -- [Başlarken](#başlarken) -- [Sponsorlar](#sponsorlar) -- [Sıkça sorulan sorular](#sıkça-sorulan-sorular) -- [Zaman içinda yıldızlayanlar](#zaman-içinde-yıldızlayanlar) -- [Katkıda bulunanlar](#katkıda-bulunanlar) -- [Lisans](#lisans) -- [İlham](#ilham) - -## Giriş - -Go programlarına web arayüzleri sağlamak için geleneksel yöntem, yerleşik bir web sunucusu kullanmaktır. Wails, farklı bir yaklaşım sunar: Hem Go kodunu hem de bir web ön yüzünü tek bir ikili dosyada paketleme yeteneği sağlar. Proje oluşturma, derleme ve paketleme işlemlerini kolaylaştıran araçlar sunar. Tek yapmanız gereken yaratıcı olmaktır! - -## Özellikler - -- Backend için standart Go kullanın -- Kullanıcı arayüzünüzü oluşturmak için zaten aşina olduğunuz herhangi bir frontend teknolojisini kullanın -- Hazır şablonlar kullanarak Go programlarınız için hızlıca zengin ön yüzler oluşturun -- Javascript'ten Go metodlarını kolayca çağırın -- Go yapı ve metodlarınız için otomatik oluşturulan Typescript tanımları -- Yerel Diyaloglar ve Menüler -- Yerel Karanlık / Aydınlık mod desteği -- Modern saydamlık ve "buzlu cam" efektlerini destekler -- Go ve Javascript arasında birleşik olay sistemi -- Projelerinizi hızlıca oluşturmak ve derlemek için güçlü bir komut satırı aracı -- Çoklu platform desteği -- Yerel render motorlarını kullanır - _gömülü tarayıcı yok_! - - -### Yol Haritesı - -Proje yol haritasına [buradan](https://github.com/wailsapp/wails/discussions/1484) ulaşabilirsiniz. Lütfen bir iyileştirme talebi oluşturmadan önce danışın. - - -## Başlarken - -Kurulum talimatları [resmi web sitesinde](https://wails.io/docs/gettingstarted/installation) bulunmaktadır. - - -## Sponsorlar - -Bu proje, aşağıdaki nazik insanlar / şirketler tarafından desteklenmektedir: - - -

- -

- -## Sıkça Sorulan Sorular - -- Bu Electron'a alternatif mi? - - Gereksinimlerinize bağlıdır. Go programcılarının hafif masaüstü uygulamaları yapmasını veya mevcut uygulamalarına bir ön yüz eklemelerini kolaylaştırmak için tasarlanmıştır. Wails, menüler ve diyaloglar gibi yerel öğeler sunduğundan, hafif bir Electron alternatifi olarak kabul edilebilir. - -- Bu proje kimlere yöneliktir? - - HTML/JS/CSS ön yüzünü uygulamalarıyla birlikte paketlemek isteyen, ancak bir sunucu oluşturup bir tarayıcı açmaya başvurmadan bunu yapmak isteyen Go programcıları için. - -- İsmin anlamı nedir? - - WebView'i gördüğümde, "Aslında istediğim şey, WebView uygulaması oluşturmak için araçlar, biraz Rails'in Ruby için olduğu gibi" diye düşündüm. Bu nedenle başlangıçta kelime oyunu (Rails üzerinde Webview) olarak ortaya çıktı. Ayrıca, benim geldiğim [ülkenin](https://en.wikipedia.org/wiki/Wales) İngilizce adıyla homofon olması tesadüf oldu. Bu yüzden bu isim kaldı. - - -## Zaman içinda yıldızlayanlar - - - - - - Star History Chart - - - -## Katkıda Bulunanlar - -Katkıda bulunanların listesi, README için çok büyük hale geldi! Bu projeye katkıda bulunan tüm harika insanların kendi sayfaları [burada](https://wails.io/credits#contributors) bulunmaktadır. - - -## Lisans - -[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fwailsapp%2Fwails.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fwailsapp%2Fwails?ref=badge_large) - -## İlham - -Bu proje esas olarak aşağıdaki albümler dinlenilerek kodlandı: - -- [Manic Street Preachers - Resistance Is Futile](https://open.spotify.com/album/1R2rsEUqXjIvAbzM0yHrxA) -- [Manic Street Preachers - This Is My Truth, Tell Me Yours](https://open.spotify.com/album/4VzCL9kjhgGQeKCiojK1YN) -- [The Midnight - Endless Summer](https://open.spotify.com/album/4Krg8zvprquh7TVn9OxZn8) -- [Gary Newman - Savage (Songs from a Broken World)](https://open.spotify.com/album/3kMfsD07Q32HRWKRrpcexr) -- [Steve Vai - Passion & Warfare](https://open.spotify.com/album/0oL0OhrE2rYVns4IGj8h2m) -- [Ben Howard - Every Kingdom](https://open.spotify.com/album/1nJsbWm3Yy2DW1KIc1OKle) -- [Ben Howard - Noonday Dream](https://open.spotify.com/album/6astw05cTiXEc2OvyByaPs) -- [Adwaith - Melyn](https://open.spotify.com/album/2vBE40Rp60tl7rNqIZjaXM) -- [Gwidaith Hen Fran - Cedors Hen Wrach](https://open.spotify.com/album/3v2hrfNGINPLuDP0YDTOjm) -- [Metallica - Metallica](https://open.spotify.com/album/2Kh43m04B1UkVcpcRa1Zug) -- [Bloc Party - Silent Alarm](https://open.spotify.com/album/6SsIdN05HQg2GwYLfXuzLB) -- [Maxthor - Another World](https://open.spotify.com/album/3tklE2Fgw1hCIUstIwPBJF) -- [Alun Tan Lan - Y Distawrwydd](https://open.spotify.com/album/0c32OywcLpdJCWWMC6vB8v) - diff --git a/README.uz.md b/README.uz.md deleted file mode 100644 index 807262405..000000000 --- a/README.uz.md +++ /dev/null @@ -1,159 +0,0 @@ -

-
-

- -

- Go va Web texnologiyalaridan foydalangan holda ish stoli ilovalarini yarating -
-
- - GitHub - - - - - - Go Reference - - - CodeFactor - - - - - - Awesome - - - Discord - -
- - Build - - - GitHub tag (latest SemVer pre-release) - -

- -
- - - -[English](README.md) · [简体中文](README.zh-Hans.md) · [日本語](README.ja.md) · -[한국어](README.ko.md) · [Español](README.es.md) · [Português](README.pt-br.md) · -[Русский](README.ru.md) · [Francais](README.fr.md) · [Uzbek](README.uz) · [Deutsch](README.de.md) · -[Türkçe](README.tr.md) - - - -
- -## Tarkib - -- [Tarkib](#tarkib) -- [Kirish](#kirish) -- [Xususiyatlari](#xususiyatlari) - - [Yo'l xaritasi](#yol-xaritasi) -- [Ishni boshlash](#ishni-boshlash) -- [Homiylar](#homiylar) -- [FAQ](#faq) -- [Vaqt o'tishi bilan yulduzlar](#vaqt-otishi-bilan-yulduzlar) -- [Ishtirokchilar](#homiylar) -- [Litsenziya](#litsenziya) -- [Ilhomlanish](#ilhomlanish) - -## Kirish - -Odatda, Go dasturlari uchun veb-interfeyslar o'rnatilgan veb-server va veb-brauzerdir. -Walls boshqacha yondashuvni qo'llaydi: u Go kodini ham, veb-interfeysni ham bitta ikkilik (e.g: EXE)fayliga o'raydi. -Loyihalarni yaratish, kompilyatsiya qilish va birlashtirishni boshqarish orqali ilovangizni yaratishni osonlashtiradi. -Hamma narsa faqat sizning tasavvuringiz bilan cheklangan! - -## Xususiyatlari - -- Backend uchun standart Go dan foydalaning -- UI yaratish uchun siz allaqachon tanish bo'lgan har qanday frontend texnologiyasidan foydalaning -- Oldindan tayyorlangan shablonlardan foydalanib, Go dasturlaringiz uchun tezda boy frontendlarni yarating -- Javascriptdan Go methodlarini osongina chaqiring -- Go struktura va methodlari uchun avtomatik yaratilgan Typescript ta'riflari -- Mahalliy Dialoglar va Menyular -- Mahalliy Dark / Light rejimini qo'llab-quvvatlash -- Zamonaviy shaffoflik va "muzli oyna" effektlarini qo'llab-quvvatlaydi -- Go va Javascript o'rtasidagi yagona hodisa tizimi -- Loyihalaringizni tezda yaratish va qurish uchun kuchli cli vositasi -- Ko'p platformali -- Mahalliy renderlash mexanizmlaridan foydalanadi - _o'rnatilgan brauzer yo'q_! - -### Yo'l xaritasi - -Loyihaning yoʻl xaritasini [bu yerdan](https://github.com/wailsapp/wails/discussions/1484) topish mumkin. Iltimos, maslahatlashing -Buni yaxshilash so'rovini ochishdan oldin. - -## Ishni boshlash - -O'rnatish bo'yicha ko'rsatmalar [Rasmiy veb saytda](https://wails.io/docs/gettingstarted/installation) mavjud. - -## Homiylar - -Ushbu loyiha quyidagi mehribon odamlar / kompaniyalar tomonidan qo'llab-quvvatlanadi: - - -

- -

- -## FAQ - -- Bu Elektronga muqobilmi? - - Sizning talablaringizga bog'liq. Bu Go dasturchilariga yengil ish stoli yaratishni osonlashtirish uchun yaratilgan - ilovalar yoki ularning mavjud ilovalariga frontend qo'shing. Wails menyular kabi mahalliy elementlarni taklif qiladi - va dialoglar, shuning uchun uni yengil elektron muqobili deb hisoblash mumkin. - -- Ushbu loyiha kimlar uchun? - - Server yaratmasdan va uni ko'rish uchun brauzerni ochmasdan, o'z ilovalari bilan HTML/JS/CSS orqali frontendini birlashtirmoqchi bo'lgan dasturchilar uchun. - -- Bu qanday nom? - - Men WebViewni ko'rganimda, men shunday deb o'yladim: "Menga WebView ilovasini yaratish uchun vositalar kerak. - biroz Rails for Rubyga o'xshaydi." Demak, dastlab bu so'zlar ustida o'yin edi (Railsda Webview). Shunday bo'ldi. - u men kelgan [Mamlakat](https://en.wikipedia.org/wiki/Wales)ning inglizcha nomining omofonidir. - -## Vaqt o'tishi bilan yulduzlar - - - - - - Yulduzlar tarixi jadvali - - - -## Ishtirokchilar - -Ishtirokchilar roʻyxati oʻqish uchun juda kattalashib bormoqda! Bunga hissa qo'shgan barcha ajoyib odamlarning -loyihada o'z sahifasi bor [bu yerga](https://wails.io/credits#contributors). - -## Litsenziya - -[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fwailsapp%2Fwails.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fwailsapp%2Fwails?ref=badge_large) - -## Ilhomlanish - -Ushbu loyiha asosan quyidagi albomlar uchun kodlangan: - -- [Manic Street Preachers - Resistance Is Futile](https://open.spotify.com/album/1R2rsEUqXjIvAbzM0yHrxA) -- [Manic Street Preachers - This Is My Truth, Tell Me Yours](https://open.spotify.com/album/4VzCL9kjhgGQeKCiojK1YN) -- [The Midnight - Endless Summer](https://open.spotify.com/album/4Krg8zvprquh7TVn9OxZn8) -- [Gary Newman - Savage (Songs from a Broken World)](https://open.spotify.com/album/3kMfsD07Q32HRWKRrpcexr) -- [Steve Vai - Passion & Warfare](https://open.spotify.com/album/0oL0OhrE2rYVns4IGj8h2m) -- [Ben Howard - Every Kingdom](https://open.spotify.com/album/1nJsbWm3Yy2DW1KIc1OKle) -- [Ben Howard - Noonday Dream](https://open.spotify.com/album/6astw05cTiXEc2OvyByaPs) -- [Adwaith - Melyn](https://open.spotify.com/album/2vBE40Rp60tl7rNqIZjaXM) -- [Gwidaith Hen Fran - Cedors Hen Wrach](https://open.spotify.com/album/3v2hrfNGINPLuDP0YDTOjm) -- [Metallica - Metallica](https://open.spotify.com/album/2Kh43m04B1UkVcpcRa1Zug) -- [Bloc Party - Silent Alarm](https://open.spotify.com/album/6SsIdN05HQg2GwYLfXuzLB) -- [Maxthor - Another World](https://open.spotify.com/album/3tklE2Fgw1hCIUstIwPBJF) -- [Alun Tan Lan - Y Distawrwydd](https://open.spotify.com/album/0c32OywcLpdJCWWMC6vB8v) diff --git a/README.zh-Hans.md b/README.zh-Hans.md index 4c09d0c45..fc310183e 100644 --- a/README.zh-Hans.md +++ b/README.zh-Hans.md @@ -1,102 +1,242 @@ -

Wails

-

-
+

-

- 使用 Go 和 Web 技术构建桌面应用程序。 -
-
- - GitHub - - - - - - Go Reference - - - CodeFactor - - - - - - Awesome - - - Discord - -
- - Build - - - GitHub tag (latest SemVer pre-release) - + 使用 Go 和 Web 技术构建桌面应用程序。

+ + + + CodeFactor + CodeFactor + + + Awesome + Release Pipelines

-
- - + -[English](README.md) · [简体中文](README.zh-Hans.md) · [日本語](README.ja.md) · -[한국어](README.ko.md) · [Español](README.es.md) · [Português](README.pt-br.md) · -[Русский](README.ru.md) · [Francais](README.fr.md) · [Uzbek](README.uz.md) · [Deutsch](README.de.md) · -[Türkçe](README.tr.md) +## 国际化 - - -
+[English](README.md) | 简体中文 + +向 Go 程序提供 Web 接口的传统方法是通过内置 Web 服务器。Wails 提供了一种不同的方法:它提供了将 Go 代码和 Web +前端都包装成单个二进制文件的能力。通过提供工具,可以很轻松的完成项目的创建、编译和打包。你所要做的就是发挥创意! + +官方文档可以在 [https://wails.app](https://wails.app) 中找到。 + +国内镜像站点 [https://wails.top](https://wails.top)。 + + ## 内容目录 -- [内容目录](#内容目录) -- [项目介绍](#项目介绍) -- [功能](#功能) - - [路线图](#路线图) -- [快速入门](#快速入门) -- [赞助商](#赞助商) -- [常见问题](#常见问题) -- [星星增长趋势](#星星增长趋势) -- [贡献者](#贡献者) -- [许可证](#许可证) -- [灵感](#灵感) +- [1. 国际化](#nav-1) +- [2. 内容目录](#nav-2) +- [3. 特征](#nav-3) +- [4. 赞助商](#nav-4) +- [5. 安装](#nav-5) + - [5.1 MacOS](#nav-5-1) + - [5.2 Linux](#nav-5-2) + - [5.2.1 Debian/Ubuntu](#nav-5-2-1) + - [5.2.2 Arch Linux / ArchLabs / Ctlos Linux](#nav-5-2-2) + - [5.2.3 Centos](#nav-5-2-3) + - [5.2.4 Fedora](#nav-5-2-4) + - [5.2.5 VoidLinux & VoidLinux-musl](#nav-5-2-5) + - [5.2.6 Gentoo](#nav-5-2-6) + - [5.3 Windows](#nav-5-3) +- [6. 安装](#nav-6) +- [7. 下一步](#nav-7) +- [8. 常见问题](#nav-8) +- [9. 贡献者](#nav-9) +- [10. 特别提及](#nav-10) +- [11. 许可协议](#nav-11) +- [12. 特别感谢](#nav-12) -## 项目介绍 + -为 Go 程序提供 Web 界面的传统方法是通过内置 Web 服务器。Wails 提供了一种不同的方法:它提供了将 Go 代码和 Web -前端一起打包成单个二进制文件的能力。通过提供的工具,可以很轻松的完成项目的创建、编译和打包。你所要做的就是发挥创造力! - -## 功能 +## 特征 - 后端使用标准 Go -- 使用您已经熟悉的任何前端技术来构建您的 UI -- 使用内置模板为您的 Go 程序快速创建丰富的前端 -- 从 Javascript 轻松调用 Go 方法 -- 为您的 Go 结构体和方法自动生成 Typescript 声明 -- 原生对话框和菜单 -- 支持现代半透明和“磨砂窗”效果 -- Go 和 Javascript 之间统一的事件系统 -- 强大的命令行工具,可快速生成和构建您的项目 -- 跨平台 -- 使用原生渲染引擎 - _没有嵌入浏览器_! +- 使用任意前端技术构建 UI 界面 +- 快速为您的 Go 应用生成 Vue、Vuetify、React 前端代码 +- 通过简单的绑定命令将 Go 方法暴露到前端 +- 使用原生渲染引擎 - 无嵌入式浏览器 +- 共享事件系统 +- 原生文件系统对话框 +- 强大的命令行工具 +- 跨多个平台 -### 路线图 - -项目路线图可在 [此处](https://github.com/wailsapp/wails/discussions/1484) 找到。在提出增强请求之前请查阅此内容。 - -## 快速入门 - -使用说明在 [官网](https://wails.io/zh-Hans/docs/gettingstarted/installation/)。 + ## 赞助商 这个项目由以下这些人或者公司支持: - + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +## 安装 + +Wails 使用 cgo 与原生渲染引擎结合,因此需要依赖一些平台的库以及 Go 的安装。基本要求是: + +- Go 1.16 +- npm + + + +### MacOS + +请确保已安装 xcode 命令行工具。这可以通过运行下面的命令来完成: + +`xcode-select --install` + + + +### Linux + + + +#### Debian/Ubuntu + +`sudo apt install libgtk-3-dev libwebkit2gtk-4.0-dev` + +_Debian: 8, 9, 10_ + +_Ubuntu: 16.04, 18.04, 19.04_ + +_也成功测试了: Zorin 15, Parrot 4.7, Linuxmint 19, Elementary 5, Kali, Neon_, Pop!\_OS + + + +#### Arch Linux / ArchLabs / Ctlos Linux + +`sudo pacman -S webkit2gtk gtk3` + +_也成功测试了: Manjaro & ArcoLinux_ + + + +#### Centos + +`sudo yum install webkitgtk3-devel gtk3-devel` + +_CentOS 6, 7_ + + + +#### Fedora + +`sudo yum install webkit2gtk3-devel gtk3-devel` + +_Fedora 29, 30_ + + + +#### VoidLinux & VoidLinux-musl + +`xbps-install gtk+3-devel webkit2gtk-devel` + + + +#### Gentoo + +`sudo emerge gtk+:3 webkit-gtk` + + + +### Windows + +Windows 需要 GCC 和相关工具。 建议从 [http://tdm-gcc.tdragon.net/download](http://tdm-gcc.tdragon.net/download) 下载, 安装完成,您就可以开始了。 + + + +## 安装 + +**确保 Go modules 是开启的:GO111MODULE=on 并且 go/bin 在您的 PATH 变量中。** + +安装很简单,运行以下命令: + +
+go get -u github.com/wailsapp/wails/cmd/wails
+
+ + + +## 下一步 + +建议在此时阅读 [https://wails.app](https://wails.app) 上面的文档. + + ## 常见问题 @@ -104,30 +244,76 @@ 取决于您的要求。它旨在使 Go 程序员可以轻松制作轻量级桌面应用程序或在其现有应用程序中添加前端。尽管 Wails 当前不提供对诸如菜单之类的原生元素的钩子,但将来可能会改变。 -- 这个项目针对的是哪些人? +- 这个项目针对的是谁? 希望将 HTML / JS / CSS 前端与其应用程序捆绑在一起的程序员,而不是借助创建服务并打开浏览器进行查看的方式。 - 名字怎么来的? 当我看到 WebView 时,我想"我真正想要的是围绕构建 WebView 应用程序工作,有点像 Rails 对于 Ruby"。因此,最初它是一个文字游戏(Webview on - Rails)。碰巧也是我来自的 [国家](https://en.wikipedia.org/wiki/Wales) 的英文名字的同音。所以就是它了。 + Rails)。碰巧也是我来自的 [国家](https://en.wikipedia.org/wiki/Wales) 的英文名字的同音。所以就是他了。 -## 星星增长趋势 - -[![星星增长趋势](https://api.star-history.com/svg?repos=wailsapp/wails&type=Date)](https://star-history.com/#wailsapp/wails&Date) + ## 贡献者 -贡献者列表对于 README 文件来说太大了!所有为这个项目做出贡献的了不起的人在[这里](https://wails.io/credits#contributors)都有自己的页面。 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -## 许可证 + -[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fwailsapp%2Fwails.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fwailsapp%2Fwails?ref=badge_large) +## 特别提及 -## 灵感 +如果没有以下人员,此项目或许永远不会存在: -项目灵感主要来自以下专辑: +- [Dustin Krysak](https://wiki.ubuntu.com/bashfulrobot) - 他的支持和反馈是巨大的。 +- [Serge Zaitsev](https://github.com/zserge) - Wails 窗口所使用的 [Webview](https://github.com/zserge/webview) 的作者。 +- [Byron](https://github.com/bh90210) - 有时,Byron 单枪匹马地保持这个项目活着。没有他令人难以置信的投入,我们永远不会得到 v1 。 + +This project was mainly coded to the following albums: - [Manic Street Preachers - Resistance Is Futile](https://open.spotify.com/album/1R2rsEUqXjIvAbzM0yHrxA) - [Manic Street Preachers - This Is My Truth, Tell Me Yours](https://open.spotify.com/album/4VzCL9kjhgGQeKCiojK1YN) @@ -142,3 +328,25 @@ - [Bloc Party - Silent Alarm](https://open.spotify.com/album/6SsIdN05HQg2GwYLfXuzLB) - [Maxthor - Another World](https://open.spotify.com/album/3tklE2Fgw1hCIUstIwPBJF) - [Alun Tan Lan - Y Distawrwydd](https://open.spotify.com/album/0c32OywcLpdJCWWMC6vB8v) + + + +## 许可协议 + +[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fwailsapp%2Fwails.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fwailsapp%2Fwails?ref=badge_large) + + + +## 特别感谢 + +

+
+ 非常感谢Pace对项目的赞助,并帮助将 Wails 移植到 Apple Silicon !

+ 如果您正在寻找一个强大并且快速和易于使用的项目管理工具,可以看看他们!

+

+ +

+ 特别感谢 JetBrains 向我们捐赠许可!

+ 请点击 logo 让他们知道你的感激之情!

+ +

diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index cb096f872..000000000 --- a/SECURITY.md +++ /dev/null @@ -1,38 +0,0 @@ -# Security Policy - -## Supported Versions - -| Version | Supported | -| ------- | ------------------ | -| 2.x.x | :white_check_mark: | -| 3.0.x-alpha | :x: | - - -## Reporting a Vulnerability - -If you believe you have found a security vulnerability in our project, we encourage you to let us know right away. -We will investigate all legitimate reports and do our best to quickly fix the problem. - -Before reporting though, please review our security policy below. - -### How to Report - -To report a security vulnerability, please use GitHub's [private vulnerability reporting](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability) feature. If possible, please include as much information as possible. -This may include steps to reproduce, impact of the vulnerability, and anything else you believe would help us understand the problem. -**Please do not include any sensitive or personal information in your report**. - -### What to Expect - -When you report a vulnerability, here's what you can expect: - -- **Acknowledgement**: We will acknowledge your email within 48 hours, and you'll receive a more detailed response to your email within 72 hours indicating the next steps in handling your report. - -- **Updates**: After the initial reply to your report, our team will keep you informed of the progress being made towards a fix and full announcement. These updates will be sent at least once a week. - -- **Confidentiality**: We will maintain strict confidentiality of your report until the security issue is resolved. - -- **Issue Resolution**: If the issue is confirmed, we will release a patch as soon as possible depending on complexity of the fix. - -- **Recognition**: We recognize and appreciate every individual who helps us identify and fix vulnerabilities in our project. While we do not currently have a bounty program, we would be happy to publicly acknowledge your responsible disclosure. - -We strive to make Wails safe for everyone, and we greatly appreciate the assistance of security researchers and users in helping us identify and fix vulnerabilities. Thank you for your contribution to the security of this project. diff --git a/Taskfile.yaml b/Taskfile.yaml deleted file mode 100644 index 7cc165825..000000000 --- a/Taskfile.yaml +++ /dev/null @@ -1,47 +0,0 @@ -# https://taskfile.dev - -version: "3" - -includes: - website: - taskfile: website - dir: website - - v2: - taskfile: v2 - dir: v2 - optional: true - v3: - taskfile: v3 - dir: v3 - optional: true - -tasks: - contributors:check: - cmds: - - npx -y all-contributors-cli check - - contributors:update: - cmds: - - go run v3/tasks/contribs/main.go - - contributors:build: - cmds: - - npx -y all-contributors-cli generate - - format:md: - cmds: - - npx prettier --write "**/*.md" - - format: - cmds: - - task: format:md - - format-all-md: - cmds: - - task: format:md - - task: website:format:md - - task: v2:format:md - # - task: v2:website:format - - task: v3:format:md - # - task: v3:website:format:md diff --git a/app.go b/app.go new file mode 100644 index 000000000..95a8a7e82 --- /dev/null +++ b/app.go @@ -0,0 +1,174 @@ +package wails + +import ( + "os" + "syscall" + + "github.com/syossan27/tebata" + "github.com/wailsapp/wails/cmd" + "github.com/wailsapp/wails/lib/binding" + "github.com/wailsapp/wails/lib/event" + "github.com/wailsapp/wails/lib/interfaces" + "github.com/wailsapp/wails/lib/ipc" + "github.com/wailsapp/wails/lib/logger" + "github.com/wailsapp/wails/lib/renderer" + wailsruntime "github.com/wailsapp/wails/runtime" +) + +// -------------------------------- Compile time Flags ------------------------------ + +// BuildMode indicates what mode we are in +var BuildMode = cmd.BuildModeProd + +// Runtime is the Go Runtime struct +type Runtime = wailsruntime.Runtime + +// Store is a state store used for syncing with +// the front end +type Store = wailsruntime.Store + +// CustomLogger is a specialised logger +type CustomLogger = logger.CustomLogger + +// ---------------------------------------------------------------------------------- + +// App defines the main application struct +type App struct { + config *AppConfig // The Application configuration object + cli *cmd.Cli // In debug mode, we have a cli + renderer interfaces.Renderer // The renderer is what we will render the app to + logLevel string // The log level of the app + ipc interfaces.IPCManager // Handles the IPC calls + log *logger.CustomLogger // Logger + bindingManager interfaces.BindingManager // Handles binding of Go code to renderer + eventManager interfaces.EventManager // Handles all the events + runtime interfaces.Runtime // The runtime object for registered structs +} + +// CreateApp creates the application window with the given configuration +// If none given, the defaults are used +func CreateApp(optionalConfig ...*AppConfig) *App { + var userConfig *AppConfig + if len(optionalConfig) > 0 { + userConfig = optionalConfig[0] + } + + result := &App{ + logLevel: "debug", + renderer: renderer.NewWebView(), + ipc: ipc.NewManager(), + bindingManager: binding.NewManager(), + eventManager: event.NewManager(), + log: logger.NewCustomLogger("App"), + } + + appconfig, err := newConfig(userConfig) + if err != nil { + result.log.Fatalf("Cannot use custom HTML: %s", err.Error()) + } + result.config = appconfig + + // Set up the CLI if not in release mode + if BuildMode != cmd.BuildModeProd { + result.cli = result.setupCli() + } else { + // Disable Inspector in release mode + result.config.DisableInspector = true + } + + // Platform specific init + platformInit() + + return result +} + +// Run the app +func (a *App) Run() error { + + if BuildMode != cmd.BuildModeProd { + return a.cli.Run() + } + + a.logLevel = "error" + err := a.start() + if err != nil { + a.log.Error(err.Error()) + } + return err +} + +func (a *App) start() error { + + // Set the log level + logger.SetLogLevel(a.logLevel) + + // Log starup + a.log.Info("Starting") + + // Check if we are to run in bridge mode + if BuildMode == cmd.BuildModeBridge { + a.renderer = renderer.NewBridge() + } + + // Initialise the renderer + err := a.renderer.Initialise(a.config, a.ipc, a.eventManager) + if err != nil { + return err + } + + // Start signal handler + t := tebata.New(os.Interrupt, os.Kill, syscall.SIGTERM, syscall.SIGINT, syscall.SIGKILL) + t.Reserve(func() { + a.log.Debug("SIGNAL CAUGHT! Starting Shutdown") + a.renderer.Close() + }) + + // Start event manager and give it our renderer + a.eventManager.Start(a.renderer) + + // Start the IPC Manager and give it the event manager and binding manager + a.ipc.Start(a.eventManager, a.bindingManager) + + // Create the runtime + a.runtime = wailsruntime.NewRuntime(a.eventManager, a.renderer) + + // Start binding manager and give it our renderer + err = a.bindingManager.Start(a.renderer, a.runtime) + if err != nil { + return err + } + + // Defer the shutdown + defer a.shutdown() + + // Run the renderer + err = a.renderer.Run() + if err != nil { + return err + } + + return nil +} + +// shutdown the app +func (a *App) shutdown() { + // Make sure this is only called once + a.log.Debug("Shutting down") + + // Shutdown Binding Manager + a.bindingManager.Shutdown() + + // Shutdown IPC Manager + a.ipc.Shutdown() + + // Shutdown Event Manager + a.eventManager.Shutdown() + + a.log.Debug("Cleanly Shutdown") +} + +// Bind allows the user to bind the given object +// with the application +func (a *App) Bind(object interface{}) { + a.bindingManager.Bind(object) +} diff --git a/app_other.go b/app_other.go new file mode 100644 index 000000000..9e0514350 --- /dev/null +++ b/app_other.go @@ -0,0 +1,8 @@ +//go:build linux || darwin || !windows +// +build linux darwin !windows + +package wails + +func platformInit() { + +} diff --git a/app_windows.go b/app_windows.go new file mode 100644 index 000000000..cf9472731 --- /dev/null +++ b/app_windows.go @@ -0,0 +1,28 @@ +//go:build windows || !linux || !darwin +// +build windows !linux !darwin + +package wails + +import ( + "fmt" + "log" + "syscall" +) + +func platformInit() { + err := SetProcessDPIAware() + if err != nil { + log.Fatalf(err.Error()) + } +} + +// SetProcessDPIAware via user32.dll +// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setprocessdpiaware +// Also, thanks Jack Mordaunt! https://github.com/wailsapp/wails/issues/293 +func SetProcessDPIAware() error { + status, r, err := syscall.NewLazyDLL("user32.dll").NewProc("SetProcessDPIAware").Call() + if status == 0 { + return fmt.Errorf("exit status %d: %v %v", status, r, err) + } + return nil +} diff --git a/assets/images/jetbrains-grayscale.png b/assets/images/jetbrains-grayscale.png deleted file mode 100644 index 513642dda..000000000 Binary files a/assets/images/jetbrains-grayscale.png and /dev/null differ diff --git a/assets/images/logo-universal.png b/assets/images/logo-universal.png deleted file mode 100644 index f60b2f43f..000000000 Binary files a/assets/images/logo-universal.png and /dev/null differ diff --git a/assets/images/pace.jpeg b/assets/images/pace.jpeg deleted file mode 100644 index 38db20c0a..000000000 Binary files a/assets/images/pace.jpeg and /dev/null differ diff --git a/assets/images/sponsors/silver-sponsor.png b/assets/images/sponsors/silver-sponsor.png deleted file mode 100644 index e81da100c..000000000 Binary files a/assets/images/sponsors/silver-sponsor.png and /dev/null differ diff --git a/cli.go b/cli.go new file mode 100644 index 000000000..1a26f68d9 --- /dev/null +++ b/cli.go @@ -0,0 +1,27 @@ +package wails + +import ( + "github.com/wailsapp/wails/cmd" +) + +// setupCli creates a new cli handler for the application +func (app *App) setupCli() *cmd.Cli { + + // Create a new cli + result := cmd.NewCli(app.config.Title, "Debug build") + result.Version(cmd.Version) + + // Setup cli to handle loglevel + result. + StringFlag("loglevel", "Sets the log level [debug|info|error|panic|fatal]. Default debug", &app.logLevel). + Action(app.start) + + // Banner + result.PreRun(func(cli *cmd.Cli) error { + log := cmd.NewLogger() + log.YellowUnderline(app.config.Title + " - Debug Build") + return nil + }) + + return result +} diff --git a/cmd/build.go b/cmd/build.go new file mode 100644 index 000000000..945fbfc78 --- /dev/null +++ b/cmd/build.go @@ -0,0 +1,10 @@ +package cmd + +const ( + // BuildModeProd indicates we are building for prod mode + BuildModeProd = "prod" + // BuildModeDebug indicates we are building for debug mode + BuildModeDebug = "debug" + // BuildModeBridge indicates we are building for bridge mode + BuildModeBridge = "bridge" +) diff --git a/cmd/cli.go b/cmd/cli.go new file mode 100644 index 000000000..d52a44513 --- /dev/null +++ b/cmd/cli.go @@ -0,0 +1,285 @@ +package cmd + +import ( + "flag" + "fmt" + "os" + "strings" +) + +// NewCli - Creates a new Cli application object +func NewCli(name, description string) *Cli { + result := &Cli{} + result.rootCommand = NewCommand(name, description, result, "") + result.log = NewLogger() + return result +} + +// Cli - The main application object +type Cli struct { + rootCommand *Command + defaultCommand *Command + preRunCommand func(*Cli) error + log *Logger +} + +// Version - Set the Application version string +func (c *Cli) Version(version string) { + c.rootCommand.AppVersion = version +} + +// PrintHelp - Prints the application's help +func (c *Cli) PrintHelp() { + c.rootCommand.PrintHelp() +} + +// Run - Runs the application with the given arguments +func (c *Cli) Run(args ...string) error { + if c.preRunCommand != nil { + err := c.preRunCommand(c) + if err != nil { + return err + } + } + if len(args) == 0 { + args = os.Args[1:] + } + return c.rootCommand.Run(args) +} + +// DefaultCommand - Sets the given command as the command to run when +// no other commands given +func (c *Cli) DefaultCommand(defaultCommand *Command) *Cli { + c.defaultCommand = defaultCommand + return c +} + +// Command - Adds a command to the application +func (c *Cli) Command(name, description string) *Command { + return c.rootCommand.Command(name, description) +} + +// PreRun - Calls the given function before running the specific command +func (c *Cli) PreRun(callback func(*Cli) error) { + c.preRunCommand = callback +} + +// BoolFlag - Adds a boolean flag to the root command +func (c *Cli) BoolFlag(name, description string, variable *bool) *Command { + c.rootCommand.BoolFlag(name, description, variable) + return c.rootCommand +} + +// StringFlag - Adds a string flag to the root command +func (c *Cli) StringFlag(name, description string, variable *string) *Command { + c.rootCommand.StringFlag(name, description, variable) + return c.rootCommand +} + +// Action represents a function that gets calls when the command is called by +// the user +type Action func() error + +// Command represents a command that may be run by the user +type Command struct { + Name string + CommandPath string + Shortdescription string + Longdescription string + AppVersion string + SubCommands []*Command + SubCommandsMap map[string]*Command + longestSubcommand int + ActionCallback Action + App *Cli + Flags *flag.FlagSet + flagCount int + log *Logger + helpFlag bool + hidden bool +} + +// NewCommand creates a new Command +func NewCommand(name string, description string, app *Cli, parentCommandPath string) *Command { + result := &Command{ + Name: name, + Shortdescription: description, + SubCommandsMap: make(map[string]*Command), + App: app, + log: NewLogger(), + hidden: false, + } + + // Set up command path + if parentCommandPath != "" { + result.CommandPath += parentCommandPath + " " + } + result.CommandPath += name + + // Set up flag set + result.Flags = flag.NewFlagSet(result.CommandPath, flag.ContinueOnError) + result.BoolFlag("help", "Get help on the '"+result.CommandPath+"' command.", &result.helpFlag) + + // result.Flags.Usage = result.PrintHelp + + return result +} + +// parseFlags parses the given flags +func (c *Command) parseFlags(args []string) error { + // Parse flags + tmp := os.Stderr + os.Stderr = nil + err := c.Flags.Parse(args) + os.Stderr = tmp + if err != nil { + fmt.Printf("Error: %s\n\n", err.Error()) + c.PrintHelp() + } + return err +} + +// Run - Runs the Command with the given arguments +func (c *Command) Run(args []string) error { + + // If we have arguments, process them + if len(args) > 0 { + // Check for subcommand + subcommand := c.SubCommandsMap[args[0]] + if subcommand != nil { + return subcommand.Run(args[1:]) + } + + // Parse flags + err := c.parseFlags(args) + if err != nil { + fmt.Printf("Error: %s\n\n", err.Error()) + c.PrintHelp() + return err + } + + // Help takes precedence + if c.helpFlag { + c.PrintHelp() + return nil + } + } + + // Do we have an action? + if c.ActionCallback != nil { + return c.ActionCallback() + } + + // If we haven't specified a subcommand + // check for an app level default command + if c.App.defaultCommand != nil { + // Prevent recursion! + if c.App.defaultCommand != c { + // only run default command if no args passed + if len(args) == 0 { + return c.App.defaultCommand.Run(args) + } + } + } + + // Nothing left we can do + c.PrintHelp() + + return nil +} + +// Action - Define an action from this command +func (c *Command) Action(callback Action) *Command { + c.ActionCallback = callback + return c +} + +// PrintHelp - Output the help text for this command +func (c *Command) PrintHelp() { + c.log.PrintBanner() + + commandTitle := c.CommandPath + if c.Shortdescription != "" { + commandTitle += " - " + c.Shortdescription + } + // Ignore root command + if c.CommandPath != c.Name { + c.log.Yellow(commandTitle) + } + if c.Longdescription != "" { + fmt.Println() + fmt.Println(c.Longdescription + "\n") + } + if len(c.SubCommands) > 0 { + c.log.White("Available commands:") + fmt.Println("") + for _, subcommand := range c.SubCommands { + if subcommand.isHidden() { + continue + } + spacer := strings.Repeat(" ", 3+c.longestSubcommand-len(subcommand.Name)) + isDefault := "" + if subcommand.isDefaultCommand() { + isDefault = "[default]" + } + fmt.Printf(" %s%s%s %s\n", subcommand.Name, spacer, subcommand.Shortdescription, isDefault) + } + fmt.Println("") + } + if c.flagCount > 0 { + c.log.White("Flags:") + fmt.Println() + c.Flags.SetOutput(os.Stdout) + c.Flags.PrintDefaults() + c.Flags.SetOutput(os.Stderr) + + } + fmt.Println() +} + +// isDefaultCommand returns true if called on the default command +func (c *Command) isDefaultCommand() bool { + return c.App.defaultCommand == c +} + +// isHidden returns true if the command is a hidden command +func (c *Command) isHidden() bool { + return c.hidden +} + +// Hidden hides the command from the Help system +func (c *Command) Hidden() { + c.hidden = true +} + +// Command - Defines a subcommand +func (c *Command) Command(name, description string) *Command { + result := NewCommand(name, description, c.App, c.CommandPath) + result.log = c.log + c.SubCommands = append(c.SubCommands, result) + c.SubCommandsMap[name] = result + if len(name) > c.longestSubcommand { + c.longestSubcommand = len(name) + } + return result +} + +// BoolFlag - Adds a boolean flag to the command +func (c *Command) BoolFlag(name, description string, variable *bool) *Command { + c.Flags.BoolVar(variable, name, *variable, description) + c.flagCount++ + return c +} + +// StringFlag - Adds a string flag to the command +func (c *Command) StringFlag(name, description string, variable *string) *Command { + c.Flags.StringVar(variable, name, *variable, description) + c.flagCount++ + return c +} + +// LongDescription - Sets the long description for the command +func (c *Command) LongDescription(Longdescription string) *Command { + c.Longdescription = Longdescription + return c +} diff --git a/cmd/fs.go b/cmd/fs.go new file mode 100644 index 000000000..0c39e2aea --- /dev/null +++ b/cmd/fs.go @@ -0,0 +1,251 @@ +package cmd + +import ( + "bytes" + "crypto/md5" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "log" + "os" + "path" + "path/filepath" + "runtime" + "strings" + + "github.com/leaanthony/slicer" +) + +// FSHelper - Wrapper struct for File System utility commands +type FSHelper struct { +} + +// NewFSHelper - Returns a new FSHelper +func NewFSHelper() *FSHelper { + result := &FSHelper{} + return result +} + +// DirExists - Returns true if the given path resolves to a directory on the filesystem +func (fs *FSHelper) DirExists(path string) bool { + fi, err := os.Lstat(path) + if err != nil { + return false + } + + return fi.Mode().IsDir() +} + +// FileExists returns a boolean value indicating whether +// the given file exists +func (fs *FSHelper) FileExists(path string) bool { + fi, err := os.Lstat(path) + if err != nil { + return false + } + + return fi.Mode().IsRegular() +} + +// FindFile returns the first occurrence of match inside path. +func (fs *FSHelper) FindFile(path, match string) (string, error) { + files, err := ioutil.ReadDir(path) + if err != nil { + return "", err + } + + for _, f := range files { + if !f.IsDir() && strings.Contains(f.Name(), match) { + return f.Name(), nil + } + } + + return "", fmt.Errorf("file not found") +} + +// CreateFile creates a file at the given filename location with the contents +// set to the given data. It will create intermediary directories if needed. +func (fs *FSHelper) CreateFile(filename string, data []byte) error { + // Ensure directory exists + fs.MkDirs(filepath.Dir(filename)) + return ioutil.WriteFile(filename, data, 0644) +} + +// MkDirs creates the given nested directories. +// Returns error on failure +func (fs *FSHelper) MkDirs(fullPath string, mode ...os.FileMode) error { + var perms os.FileMode + perms = 0700 + if len(mode) == 1 { + perms = mode[0] + } + return os.MkdirAll(fullPath, perms) +} + +// CopyFile from source to target +func (fs *FSHelper) CopyFile(source, target string) error { + s, err := os.Open(source) + if err != nil { + return err + } + defer s.Close() + d, err := os.Create(target) + if err != nil { + return err + } + if _, err := io.Copy(d, s); err != nil { + d.Close() + return err + } + return d.Close() +} + +// Cwd returns the current working directory +// Aborts on Failure +func (fs *FSHelper) Cwd() string { + cwd, err := os.Getwd() + if err != nil { + log.Fatal("Unable to get working directory!") + } + return cwd +} + +// RemoveFile removes the given filename +func (fs *FSHelper) RemoveFile(filename string) error { + return os.Remove(filename) +} + +// RemoveFiles removes the given filenames +func (fs *FSHelper) RemoveFiles(files []string, continueOnError bool) error { + for _, filename := range files { + err := os.Remove(filename) + if err != nil && !continueOnError { + return err + } + } + return nil +} + +// Dir holds information about a directory +type Dir struct { + localPath string + fullPath string +} + +// Directory creates a new Dir struct with the given directory path +func (fs *FSHelper) Directory(dir string) (*Dir, error) { + fullPath, err := filepath.Abs(dir) + return &Dir{fullPath: fullPath}, err +} + +// LocalDir creates a new Dir struct based on a path relative to the caller +func (fs *FSHelper) LocalDir(dir string) (*Dir, error) { + _, filename, _, _ := runtime.Caller(1) + fullPath, err := filepath.Abs(filepath.Join(path.Dir(filename), dir)) + return &Dir{ + localPath: dir, + fullPath: fullPath, + }, err +} + +// LoadRelativeFile loads the given file relative to the caller's directory +func (fs *FSHelper) LoadRelativeFile(relativePath string) ([]byte, error) { + _, filename, _, _ := runtime.Caller(0) + fullPath, err := filepath.Abs(filepath.Join(path.Dir(filename), relativePath)) + if err != nil { + return nil, err + } + return ioutil.ReadFile(fullPath) +} + +// GetSubdirs will return a list of FQPs to subdirectories in the given directory +func (d *Dir) GetSubdirs() (map[string]string, error) { + + // Read in the directory information + fileInfo, err := ioutil.ReadDir(d.fullPath) + if err != nil { + return nil, err + } + + // Allocate space for the list + subdirs := make(map[string]string) + + // Pull out the directories and store in the map as + // map["directoryName"] = "path/to/directoryName" + for _, file := range fileInfo { + if file.IsDir() { + subdirs[file.Name()] = filepath.Join(d.fullPath, file.Name()) + } + } + return subdirs, nil +} + +// GetAllFilenames returns all filename in and below this directory +func (d *Dir) GetAllFilenames() (*slicer.StringSlicer, error) { + result := slicer.String() + err := filepath.Walk(d.fullPath, func(dir string, info os.FileInfo, err error) error { + if dir == d.fullPath { + return nil + } + if err != nil { + return err + } + + // Don't copy template metadata + result.Add(dir) + + return nil + }) + return result, err +} + +// MkDir creates the given directory. +// Returns error on failure +func (fs *FSHelper) MkDir(dir string) error { + return os.Mkdir(dir, 0700) +} + +// SaveAsJSON saves the JSON representation of the given data to the given filename +func (fs *FSHelper) SaveAsJSON(data interface{}, filename string) error { + + var buf bytes.Buffer + e := json.NewEncoder(&buf) + e.SetEscapeHTML(false) + e.SetIndent("", " ") + e.Encode(data) + + err := ioutil.WriteFile(filename, buf.Bytes(), 0755) + if err != nil { + return err + } + return nil +} + +// LoadAsString will attempt to load the given file and return +// its contents as a string +func (fs *FSHelper) LoadAsString(filename string) (string, error) { + bytes, err := fs.LoadAsBytes(filename) + return string(bytes), err +} + +// LoadAsBytes returns the contents of the file as a byte slice +func (fs *FSHelper) LoadAsBytes(filename string) ([]byte, error) { + return ioutil.ReadFile(filename) +} + +// FileMD5 returns the md5sum of the given file +func (fs *FSHelper) FileMD5(filename string) (string, error) { + f, err := os.Open(filename) + if err != nil { + return "", err + } + defer f.Close() + + h := md5.New() + if _, err := io.Copy(h, f); err != nil { + return "", err + } + + return fmt.Sprintf("%x", h.Sum(nil)), nil +} diff --git a/cmd/github.go b/cmd/github.go new file mode 100644 index 000000000..c71c00c5b --- /dev/null +++ b/cmd/github.go @@ -0,0 +1,108 @@ +package cmd + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "sort" +) + +// GitHubHelper is a utility class for interacting with GitHub +type GitHubHelper struct { +} + +// NewGitHubHelper returns a new GitHub Helper +func NewGitHubHelper() *GitHubHelper { + return &GitHubHelper{} +} + +// GetVersionTags gets the list of tags on the Wails repo +// It returns a list of sorted tags in descending order +func (g *GitHubHelper) GetVersionTags() ([]*SemanticVersion, error) { + + result := []*SemanticVersion{} + var err error + + resp, err := http.Get("https://api.github.com/repos/wailsapp/wails/releases") + if err != nil { + return result, err + } + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return result, err + } + + data := []map[string]interface{}{} + err = json.Unmarshal(body, &data) + if err != nil { + return result, err + } + + // Convert tag data to Version structs + for _, tag := range data { + version := tag["name"].(string) + semver, err := NewSemanticVersion(version) + if err != nil { + return result, err + } + result = append(result, semver) + } + + // Reverse Sort + sort.Sort(sort.Reverse(SemverCollection(result))) + + return result, err +} + +// GetLatestStableRelease gets the latest stable release on GitHub +func (g *GitHubHelper) GetLatestStableRelease() (result *SemanticVersion, err error) { + + tags, err := g.GetVersionTags() + if err != nil { + return nil, err + } + + for _, tag := range tags { + if tag.IsRelease() { + return tag, nil + } + } + + return nil, fmt.Errorf("no release tag found") +} + +// GetLatestPreRelease gets the latest prerelease on GitHub +func (g *GitHubHelper) GetLatestPreRelease() (result *SemanticVersion, err error) { + + tags, err := g.GetVersionTags() + if err != nil { + return nil, err + } + + for _, tag := range tags { + if tag.IsPreRelease() { + return tag, nil + } + } + + return nil, fmt.Errorf("no prerelease tag found") +} + +// IsValidTag returns true if the given string is a valid tag +func (g *GitHubHelper) IsValidTag(tagVersion string) (bool, error) { + if tagVersion[0] == 'v' { + tagVersion = tagVersion[1:] + } + tags, err := g.GetVersionTags() + if err != nil { + return false, err + } + + for _, tag := range tags { + if tag.String() == tagVersion { + return true, nil + } + } + return false, nil +} diff --git a/cmd/gomod.go b/cmd/gomod.go new file mode 100644 index 000000000..a9ca7d93c --- /dev/null +++ b/cmd/gomod.go @@ -0,0 +1,78 @@ +package cmd + +import ( + "fmt" + "path/filepath" + "regexp" + + "github.com/Masterminds/semver" +) + +func GetWailsVersion() (*semver.Version, error) { + var FS = NewFSHelper() + var result *semver.Version + + // Load file + var err error + goModFile, err := filepath.Abs(filepath.Join(".", "go.mod")) + if err != nil { + return nil, fmt.Errorf("Unable to load go.mod at %s", goModFile) + } + goMod, err := FS.LoadAsString(goModFile) + if err != nil { + return nil, fmt.Errorf("Unable to load go.mod") + } + + // Find wails version + versionRegexp := regexp.MustCompile(`.*github.com/wailsapp/wails.*(v\d+.\d+.\d+(?:-pre\d+)?)`) + versions := versionRegexp.FindStringSubmatch(goMod) + + if len(versions) != 2 { + return nil, fmt.Errorf("Unable to determine Wails version") + } + + version := versions[1] + result, err = semver.NewVersion(version) + if err != nil { + return nil, fmt.Errorf("Unable to parse Wails version: %s", version) + } + return result, nil + +} + +func GetCurrentVersion() (*semver.Version, error) { + result, err := semver.NewVersion(Version) + if err != nil { + return nil, fmt.Errorf("Unable to parse Wails version: %s", Version) + } + return result, nil +} + +func GoModOutOfSync() (bool, error) { + gomodversion, err := GetWailsVersion() + if err != nil { + return true, err + } + currentVersion, err := GetCurrentVersion() + if err != nil { + return true, err + } + result := !currentVersion.Equal(gomodversion) + return result, nil +} + +func UpdateGoModVersion() error { + currentVersion, err := GetCurrentVersion() + if err != nil { + return err + } + currentVersionString := currentVersion.String() + + requireLine := "-require=github.com/wailsapp/wails@v" + currentVersionString + + // Issue: go mod edit -require=github.com/wailsapp/wails@1.0.2-pre5 + helper := NewProgramHelper() + command := []string{"go", "mod", "edit", requireLine} + return helper.RunCommandArray(command) + +} diff --git a/cmd/helpers.go b/cmd/helpers.go new file mode 100644 index 000000000..fdcad93a8 --- /dev/null +++ b/cmd/helpers.go @@ -0,0 +1,542 @@ +package cmd + +import ( + "fmt" + "os" + "os/exec" + "os/user" + "path/filepath" + "runtime" + "strconv" + "strings" + "time" + + "github.com/leaanthony/slicer" + "github.com/leaanthony/spinner" + wailsruntime "github.com/wailsapp/wails/runtime" +) + +const xgoVersion = "1.16.3" + +var fs = NewFSHelper() + +// ValidateFrontendConfig checks if the frontend config is valid +func ValidateFrontendConfig(projectOptions *ProjectOptions) error { + if projectOptions.FrontEnd.Dir == "" { + return fmt.Errorf("Frontend directory not set in project.json") + } + if projectOptions.FrontEnd.Build == "" { + return fmt.Errorf("Frontend build command not set in project.json") + } + if projectOptions.FrontEnd.Install == "" { + return fmt.Errorf("Frontend install command not set in project.json") + } + if projectOptions.FrontEnd.Bridge == "" { + return fmt.Errorf("Frontend bridge config not set in project.json") + } + + return nil +} + +// InstallGoDependencies will run go get in the current directory +func InstallGoDependencies(verbose bool) error { + var depSpinner *spinner.Spinner + if !verbose { + depSpinner = spinner.New("Ensuring Dependencies are up to date...") + depSpinner.SetSpinSpeed(50) + depSpinner.Start() + } + err := NewProgramHelper(verbose).RunCommand("go mod tidy") + if err != nil { + if !verbose { + depSpinner.Error() + } + return err + } + if !verbose { + depSpinner.Success() + } + return nil +} + +func InitializeCrossCompilation(verbose bool) error { + // Check Docker + if err := CheckIfInstalled("docker"); err != nil { + return err + } + + var packSpinner *spinner.Spinner + msg := fmt.Sprintf("Pulling wailsapp/xgo:%s docker image... (may take a while)", xgoVersion) + if !verbose { + packSpinner = spinner.New(msg) + packSpinner.SetSpinSpeed(50) + packSpinner.Start() + } else { + println(msg) + } + + err := NewProgramHelper(verbose).RunCommandArray([]string{"docker", + "pull", fmt.Sprintf("wailsapp/xgo:%s", xgoVersion)}) + + if err != nil { + if packSpinner != nil { + packSpinner.Error() + } + return err + } + if packSpinner != nil { + packSpinner.Success() + } + + return nil +} + +// BuildDocker builds the project using the cross compiling wailsapp/xgo: container +func BuildDocker(binaryName string, buildMode string, projectOptions *ProjectOptions) error { + var packSpinner *spinner.Spinner + if buildMode == BuildModeBridge { + return fmt.Errorf("you cant serve the application in cross-compilation") + } + + // Check build directory + buildDirectory := filepath.Join(fs.Cwd(), "build") + if !fs.DirExists(buildDirectory) { + err := fs.MkDir(buildDirectory) + if err != nil { + return err + } + } + + buildCommand := slicer.String() + userid := 1000 + currentUser, _ := user.Current() + if i, err := strconv.Atoi(currentUser.Uid); err == nil { + userid = i + } + for _, arg := range []string{ + "docker", + "run", + "--rm", + "-v", fmt.Sprintf("%s:/build", filepath.Join(fs.Cwd(), "build")), + "-v", fmt.Sprintf("%s:/source", fs.Cwd()), + "-e", fmt.Sprintf("LOCAL_USER_ID=%v", userid), + "-e", fmt.Sprintf("FLAG_TAGS=%s", projectOptions.Tags), + "-e", fmt.Sprintf("FLAG_LDFLAGS=%s", ldFlags(projectOptions, buildMode)), + "-e", "FLAG_V=false", + "-e", "FLAG_X=false", + "-e", "FLAG_RACE=false", + "-e", "FLAG_BUILDMODE=default", + "-e", "FLAG_TRIMPATH=false", + "-e", fmt.Sprintf("TARGETS=%s/%s", projectOptions.Platform, projectOptions.Architecture), + "-e", "GOPROXY=", + "-e", "GO111MODULE=on", + } { + buildCommand.Add(arg) + } + + if projectOptions.GoPath != "" { + buildCommand.Add("-v") + buildCommand.Add(fmt.Sprintf("%s:/go", projectOptions.GoPath)) + } + + buildCommand.Add(fmt.Sprintf("wailsapp/xgo:%s", xgoVersion)) + buildCommand.Add(".") + + compileMessage := fmt.Sprintf( + "Packing + Compiling project for %s/%s using docker image wailsapp/xgo:%s", + projectOptions.Platform, projectOptions.Architecture, xgoVersion) + + if buildMode == BuildModeDebug { + compileMessage += " (Debug Mode)" + } + + if !projectOptions.Verbose { + packSpinner = spinner.New(compileMessage + "...") + packSpinner.SetSpinSpeed(50) + packSpinner.Start() + } else { + println(compileMessage) + } + + err := NewProgramHelper(projectOptions.Verbose).RunCommandArray(buildCommand.AsSlice()) + if err != nil { + if packSpinner != nil { + packSpinner.Error() + } + return err + } + if packSpinner != nil { + packSpinner.Success() + } + + return nil +} + +// BuildNative builds on the target platform itself. +func BuildNative(binaryName string, forceRebuild bool, buildMode string, projectOptions *ProjectOptions) error { + + if err := CheckWindres(); err != nil { + return err + } + + compileMessage := "Packing + Compiling project" + + if buildMode == BuildModeDebug { + compileMessage += " (Debug Mode)" + } + + var packSpinner *spinner.Spinner + if !projectOptions.Verbose { + packSpinner = spinner.New(compileMessage + "...") + packSpinner.SetSpinSpeed(50) + packSpinner.Start() + } else { + println(compileMessage) + } + + buildCommand := slicer.String() + buildCommand.Add("go") + + buildCommand.Add("build") + + if binaryName != "" { + // Alter binary name based on OS + switch projectOptions.Platform { + case "windows": + if !strings.HasSuffix(binaryName, ".exe") { + binaryName += ".exe" + } + default: + if strings.HasSuffix(binaryName, ".exe") { + binaryName = strings.TrimSuffix(binaryName, ".exe") + } + } + buildCommand.Add("-o", filepath.Join("build", binaryName)) + } + + // If we are forcing a rebuild + if forceRebuild { + buildCommand.Add("-a") + } + + buildCommand.AddSlice([]string{"-ldflags", ldFlags(projectOptions, buildMode)}) + + if projectOptions.Tags != "" { + buildCommand.AddSlice([]string{"--tags", projectOptions.Tags}) + } + + if projectOptions.Verbose { + fmt.Printf("Command: %v\n", buildCommand.AsSlice()) + } + + err := NewProgramHelper(projectOptions.Verbose).RunCommandArray(buildCommand.AsSlice()) + if err != nil { + if packSpinner != nil { + packSpinner.Error() + } + return err + } + if packSpinner != nil { + packSpinner.Success() + } + + return nil +} + +// BuildApplication will attempt to build the project based on the given inputs +func BuildApplication(binaryName string, forceRebuild bool, buildMode string, packageApp bool, projectOptions *ProjectOptions) error { + var err error + + if projectOptions.CrossCompile { + if err := InitializeCrossCompilation(projectOptions.Verbose); err != nil { + return err + } + } + + helper := NewPackageHelper(projectOptions.Platform) + + // Generate windows resources + if projectOptions.Platform == "windows" { + if err := helper.PackageWindows(projectOptions, false); err != nil { + return err + } + } + + if projectOptions.CrossCompile { + err = BuildDocker(binaryName, buildMode, projectOptions) + } else { + err = BuildNative(binaryName, forceRebuild, buildMode, projectOptions) + } + if err != nil { + return err + } + + if packageApp { + err = PackageApplication(projectOptions) + if err != nil { + return err + } + } + + return nil +} + +// PackageApplication will attempt to package the application in a platform dependent way +func PackageApplication(projectOptions *ProjectOptions) error { + var packageSpinner *spinner.Spinner + if projectOptions.Verbose { + packageSpinner = spinner.New("Packaging application...") + packageSpinner.SetSpinSpeed(50) + packageSpinner.Start() + } + + err := NewPackageHelper(projectOptions.Platform).Package(projectOptions) + if err != nil { + if packageSpinner != nil { + packageSpinner.Error() + } + return err + } + if packageSpinner != nil { + packageSpinner.Success() + } + return nil +} + +// BuildFrontend runs the given build command +func BuildFrontend(projectOptions *ProjectOptions) error { + var buildFESpinner *spinner.Spinner + if !projectOptions.Verbose { + buildFESpinner = spinner.New("Building frontend...") + buildFESpinner.SetSpinSpeed(50) + buildFESpinner.Start() + } else { + println("Building frontend...") + } + err := NewProgramHelper(projectOptions.Verbose).RunCommand(projectOptions.FrontEnd.Build) + if err != nil { + if buildFESpinner != nil { + buildFESpinner.Error() + } + return err + } + if buildFESpinner != nil { + buildFESpinner.Success() + } + return nil +} + +// CheckWindres checks if Windres is installed and if not, aborts +func CheckWindres() (err error) { + if runtime.GOOS != "windows" { // FIXME: Handle windows cross-compile for windows! + return nil + } + programHelper := NewProgramHelper() + if !programHelper.IsInstalled("windres") { + return fmt.Errorf("windres not installed. It comes by default with mingw. Ensure you have installed mingw correctly") + } + return nil +} + +// CheckIfInstalled returns if application is installed +func CheckIfInstalled(application string) (err error) { + programHelper := NewProgramHelper() + if !programHelper.IsInstalled(application) { + return fmt.Errorf("%s not installed. Ensure you have installed %s correctly", application, application) + } + return nil +} + +// InstallFrontendDeps attempts to install the frontend dependencies based on the given options +func InstallFrontendDeps(projectDir string, projectOptions *ProjectOptions, forceRebuild bool, caller string) error { + + // Install frontend deps + err := os.Chdir(projectOptions.FrontEnd.Dir) + if err != nil { + return err + } + + // Check if frontend deps have been updated + var feSpinner *spinner.Spinner + if !projectOptions.Verbose { + feSpinner = spinner.New("Ensuring frontend dependencies are up to date (This may take a while)") + feSpinner.SetSpinSpeed(50) + feSpinner.Start() + } else { + println("Ensuring frontend dependencies are up to date (This may take a while)") + } + + requiresNPMInstall := true + + // Read in package.json MD5 + fs := NewFSHelper() + packageJSONMD5, err := fs.FileMD5("package.json") + if err != nil { + return err + } + + const md5sumFile = "package.json.md5" + + // If node_modules does not exist, force a rebuild. + nodeModulesPath, err := filepath.Abs(filepath.Join(".", "node_modules")) + if err != nil { + return err + } + if !fs.DirExists(nodeModulesPath) { + forceRebuild = true + } + + // If we aren't forcing the install and the md5sum file exists + if !forceRebuild && fs.FileExists(md5sumFile) { + // Yes - read contents + savedMD5sum, err := fs.LoadAsString(md5sumFile) + // File exists + if err == nil { + // Compare md5 + if savedMD5sum == packageJSONMD5 { + // Same - no need for reinstall + requiresNPMInstall = false + if feSpinner != nil { + feSpinner.Success("Skipped frontend dependencies (-f to force rebuild)") + } else { + println("Skipped frontend dependencies (-f to force rebuild)") + } + } + } + } + + // Md5 sum package.json + // Different? Build + if requiresNPMInstall || forceRebuild { + // Install dependencies + err = NewProgramHelper(projectOptions.Verbose).RunCommand(projectOptions.FrontEnd.Install) + if err != nil { + if feSpinner != nil { + feSpinner.Error() + } + return err + } + if feSpinner != nil { + feSpinner.Success() + } + + // Update md5sum file + err := os.WriteFile(md5sumFile, []byte(packageJSONMD5), 0644) + if err != nil { + return err + } + } + + // Install the runtime + if caller == "build" { + err = InstallProdRuntime(projectDir, projectOptions) + } else { + err = InstallBridge(projectDir, projectOptions) + } + if err != nil { + return err + } + + // Build frontend + err = BuildFrontend(projectOptions) + if err != nil { + return err + } + return nil +} + +// InstallBridge installs the relevant bridge javascript library +func InstallBridge(projectDir string, projectOptions *ProjectOptions) error { + bridgeFileTarget := filepath.Join(projectDir, projectOptions.FrontEnd.Dir, "node_modules", "@wailsapp", "runtime", "init.js") + err := fs.CreateFile(bridgeFileTarget, wailsruntime.BridgeJS) + return err +} + +// InstallProdRuntime installs the production runtime +func InstallProdRuntime(projectDir string, projectOptions *ProjectOptions) error { + bridgeFileTarget := filepath.Join(projectDir, projectOptions.FrontEnd.Dir, "node_modules", "@wailsapp", "runtime", "init.js") + err := fs.CreateFile(bridgeFileTarget, wailsruntime.InitJS) + return err +} + +// ServeProject attempts to serve up the current project so that it may be connected to +// via the Wails bridge +func ServeProject(projectOptions *ProjectOptions, logger *Logger) error { + go func() { + time.Sleep(2 * time.Second) + if projectOptions.Platform == "windows" { + logger.Yellow("*** Please note: Windows builds use mshtml which is only compatible with IE11. We strongly recommend only using IE11 when running 'wails serve'! For more information, please read https://wails.app/guides/windows/ ***") + } + logger.Green(">>>>> To connect, you will need to run '" + projectOptions.FrontEnd.Serve + "' in the '" + projectOptions.FrontEnd.Dir + "' directory <<<<<") + }() + location, err := filepath.Abs(filepath.Join("build", projectOptions.BinaryName)) + if err != nil { + return err + } + + logger.Yellow("Serving Application: " + location) + var args []string + if len(os.Args) > 2 { + foundArgSep := false + for index, arg := range os.Args[2:] { + if arg == "--" { + foundArgSep = true + continue + } + if foundArgSep { + args = os.Args[index:] + break + } + } + logger.Yellow("Passing arguments: %+v", args) + } + cmd := exec.Command(location, args...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + err = cmd.Run() + if err != nil { + return err + } + + return nil +} + +func ldFlags(po *ProjectOptions, buildMode string) string { + // Setup ld flags + ldflags := "-w -s " + if buildMode == BuildModeDebug { + ldflags = "" + } + + // Add windows flags + if po.Platform == "windows" && buildMode == BuildModeProd { + ldflags += "-H windowsgui " + } + + if po.UseFirebug { + ldflags += "-X github.com/wailsapp/wails/lib/renderer.UseFirebug=true " + } + + ldflags += "-X github.com/wailsapp/wails.BuildMode=" + buildMode + + // Add additional ldflags passed in via the `ldflags` cli flag + if len(po.LdFlags) > 0 { + ldflags += " " + po.LdFlags + } + + // If we wish to generate typescript + if po.typescriptDefsFilename != "" { + cwd, err := os.Getwd() + if err == nil { + filename := filepath.Join(cwd, po.FrontEnd.Dir, po.typescriptDefsFilename) + ldflags += " -X github.com/wailsapp/wails/lib/binding.typescriptDefinitionFilename=" + filename + } + } + return ldflags +} + +func getGitConfigValue(key string) (string, error) { + output, err := exec.Command("git", "config", "--get", "--null", key).Output() + // When using --null git appends a null character (\u0000) to the command output + return strings.TrimRight(string(output), "\u0000"), err +} diff --git a/cmd/linux.go b/cmd/linux.go new file mode 100644 index 000000000..902a75b46 --- /dev/null +++ b/cmd/linux.go @@ -0,0 +1,341 @@ +package cmd + +import ( + "fmt" + "io/ioutil" + "net/url" + "os" + "runtime" + "strings" + + "github.com/pkg/browser" +) + +// LinuxDistribution is of type int +type LinuxDistribution int + +const ( + // Unknown is the catch-all distro + Unknown LinuxDistribution = iota + // Debian distribution + Debian + // Ubuntu distribution + Ubuntu + // Arch linux distribution + Arch + // CentOS linux distribution + CentOS + // Fedora linux distribution + Fedora + // Gentoo distribution + Gentoo + // Zorin distribution + Zorin + // Parrot distribution + Parrot + // Linuxmint distribution + Linuxmint + // VoidLinux distribution + VoidLinux + // Elementary distribution + Elementary + // Kali distribution + Kali + // Neon distribution + Neon + // ArcoLinux distribution + ArcoLinux + // Manjaro distribution + Manjaro + // ManjaroARM distribution + ManjaroARM + // Deepin distribution + Deepin + // Raspbian distribution + Raspbian + // Tumbleweed (OpenSUSE) distribution + Tumbleweed + // Leap (OpenSUSE) distribution + Leap + // ArchLabs distribution + ArchLabs + // PopOS distribution + PopOS + // Solus distribution + Solus + // Ctlos Linux distribution + Ctlos + // EndeavourOS linux distribution + EndeavourOS + // Crux linux distribution + Crux + // RHEL distribution + RHEL + // NixOS distribution + NixOS + // Artix linux distribution + ArtixLinux + +) + +// DistroInfo contains all the information relating to a linux distribution +type DistroInfo struct { + Distribution LinuxDistribution + Name string + ID string + Description string + Release string +} + +// GetLinuxDistroInfo returns information about the running linux distribution +func GetLinuxDistroInfo() *DistroInfo { + result := &DistroInfo{ + Distribution: Unknown, + ID: "unknown", + Name: "Unknown", + } + _, err := os.Stat("/etc/os-release") + if !os.IsNotExist(err) { + osRelease, _ := ioutil.ReadFile("/etc/os-release") + result = parseOsRelease(string(osRelease)) + } + return result +} + +// parseOsRelease parses the given os-release data and returns +// a DistroInfo struct with the details +func parseOsRelease(osRelease string) *DistroInfo { + result := &DistroInfo{Distribution: Unknown} + + // Default value + osID := "unknown" + osNAME := "Unknown" + version := "" + + // Split into lines + lines := strings.Split(osRelease, "\n") + // Iterate lines + for _, line := range lines { + // Split each line by the equals char + splitLine := strings.SplitN(line, "=", 2) + // Check we have + if len(splitLine) != 2 { + continue + } + switch splitLine[0] { + case "ID": + osID = strings.ToLower(strings.Trim(splitLine[1], "\"")) + case "NAME": + osNAME = strings.Trim(splitLine[1], "\"") + case "VERSION_ID": + version = strings.Trim(splitLine[1], "\"") + } + } + + // Check distro name against list of distros + switch osID { + case "fedora": + result.Distribution = Fedora + case "centos": + result.Distribution = CentOS + case "rhel": + result.Distribution = RHEL + case "arch": + result.Distribution = Arch + case "archlabs": + result.Distribution = ArchLabs + case "ctlos": + result.Distribution = Ctlos + case "debian": + result.Distribution = Debian + case "ubuntu": + result.Distribution = Ubuntu + case "gentoo": + result.Distribution = Gentoo + case "zorin": + result.Distribution = Zorin + case "parrot": + result.Distribution = Parrot + case "linuxmint": + result.Distribution = Linuxmint + case "void": + result.Distribution = VoidLinux + case "elementary": + result.Distribution = Elementary + case "kali": + result.Distribution = Kali + case "neon": + result.Distribution = Neon + case "arcolinux": + result.Distribution = ArcoLinux + case "manjaro": + result.Distribution = Manjaro + case "manjaro-arm": + result.Distribution = ManjaroARM + case "deepin": + result.Distribution = Deepin + case "raspbian": + result.Distribution = Raspbian + case "opensuse-tumbleweed": + result.Distribution = Tumbleweed + case "opensuse-leap": + result.Distribution = Leap + case "pop": + result.Distribution = PopOS + case "solus": + result.Distribution = Solus + case "endeavouros": + result.Distribution = EndeavourOS + case "crux": + result.Distribution = Crux + case "nixos": + result.Distribution = NixOS + case "artix": + result.Distribution = ArtixLinux + default: + result.Distribution = Unknown + } + + result.Name = osNAME + result.ID = osID + result.Release = version + + return result +} + +// CheckPkgInstalled is all functions that use local programs to see if a package is installed +type CheckPkgInstalled func(string) (bool, error) + +// EqueryInstalled uses equery to see if a package is installed +func EqueryInstalled(packageName string) (bool, error) { + program := NewProgramHelper() + equery := program.FindProgram("equery") + if equery == nil { + return false, fmt.Errorf("cannont check dependencies: equery not found") + } + _, _, exitCode, _ := equery.Run("l", packageName) + return exitCode == 0, nil +} + +// DpkgInstalled uses dpkg to see if a package is installed +func DpkgInstalled(packageName string) (bool, error) { + program := NewProgramHelper() + dpkg := program.FindProgram("dpkg") + if dpkg == nil { + return false, fmt.Errorf("cannot check dependencies: dpkg not found") + } + _, _, exitCode, _ := dpkg.Run("-L", packageName) + return exitCode == 0, nil +} + +// EOpkgInstalled uses dpkg to see if a package is installed +func EOpkgInstalled(packageName string) (bool, error) { + program := NewProgramHelper() + eopkg := program.FindProgram("eopkg") + if eopkg == nil { + return false, fmt.Errorf("cannot check dependencies: eopkg not found") + } + stdout, _, _, _ := eopkg.Run("info", packageName) + return strings.HasPrefix(stdout, "Installed"), nil +} + +// PacmanInstalled uses pacman to see if a package is installed. +func PacmanInstalled(packageName string) (bool, error) { + program := NewProgramHelper() + pacman := program.FindProgram("pacman") + if pacman == nil { + return false, fmt.Errorf("cannot check dependencies: pacman not found") + } + _, _, exitCode, _ := pacman.Run("-Qs", packageName) + return exitCode == 0, nil +} + +// XbpsInstalled uses pacman to see if a package is installed. +func XbpsInstalled(packageName string) (bool, error) { + program := NewProgramHelper() + xbpsQuery := program.FindProgram("xbps-query") + if xbpsQuery == nil { + return false, fmt.Errorf("cannot check dependencies: xbps-query not found") + } + _, _, exitCode, _ := xbpsQuery.Run("-S", packageName) + return exitCode == 0, nil +} + +// RpmInstalled uses rpm to see if a package is installed +func RpmInstalled(packageName string) (bool, error) { + program := NewProgramHelper() + rpm := program.FindProgram("rpm") + if rpm == nil { + return false, fmt.Errorf("cannot check dependencies: rpm not found") + } + _, _, exitCode, _ := rpm.Run("--query", packageName) + return exitCode == 0, nil +} + +// PrtGetInstalled uses prt-get to see if a package is installed +func PrtGetInstalled(packageName string) (bool, error) { + program := NewProgramHelper() + prtget := program.FindProgram("prt-get") + if prtget == nil { + return false, fmt.Errorf("cannot check dependencies: prt-get not found") + } + _, _, exitCode, _ := prtget.Run("isinst", packageName) + return exitCode == 0, nil +} + +// NixEnvInstalled uses nix-env to see if a package is installed +func NixEnvInstalled(packageName string) (bool, error) { + program := NewProgramHelper() + nixEnv := program.FindProgram("nix-env") + if nixEnv == nil { + return false, fmt.Errorf("cannot check dependencies: nix-env not found") + } + packageName = strings.ReplaceAll(packageName, "+", `\+`) + _, _, exitCode, _ := nixEnv.Run("-q", packageName) + return exitCode == 0, nil +} + +// RequestSupportForDistribution promts the user to submit a request to support their +// currently unsupported distribution +func RequestSupportForDistribution(distroInfo *DistroInfo) error { + var logger = NewLogger() + defaultError := fmt.Errorf("unable to check libraries on distribution '%s'", distroInfo.Name) + + logger.Yellow("Distribution '%s' is not currently supported, but we would love to!", distroInfo.Name) + q := fmt.Sprintf("Would you like to submit a request to support distribution '%s'?", distroInfo.Name) + result := Prompt(q, "yes") + if strings.ToLower(result) != "yes" { + return defaultError + } + + title := fmt.Sprintf("Support Distribution '%s'", distroInfo.Name) + + var str strings.Builder + + gomodule, exists := os.LookupEnv("GO111MODULE") + if !exists { + gomodule = "(Not Set)" + } + + str.WriteString("\n| Name | Value |\n| ----- | ----- |\n") + str.WriteString(fmt.Sprintf("| Wails Version | %s |\n", Version)) + str.WriteString(fmt.Sprintf("| Go Version | %s |\n", runtime.Version())) + str.WriteString(fmt.Sprintf("| Platform | %s |\n", runtime.GOOS)) + str.WriteString(fmt.Sprintf("| Arch | %s |\n", runtime.GOARCH)) + str.WriteString(fmt.Sprintf("| GO111MODULE | %s |\n", gomodule)) + str.WriteString(fmt.Sprintf("| Distribution ID | %s |\n", distroInfo.ID)) + str.WriteString(fmt.Sprintf("| Distribution Name | %s |\n", distroInfo.Name)) + str.WriteString(fmt.Sprintf("| Distribution Version | %s |\n", distroInfo.Release)) + + body := fmt.Sprintf("**Description**\nDistribution '%s' is currently unsupported.\n\n**Further Information**\n\n%s\n\n*Please add any extra information here, EG: libraries that are needed to make the distribution work, or commands to install them*", distroInfo.ID, str.String()) + fullURL := "https://github.com/wailsapp/wails/issues/new?" + params := "title=" + title + "&body=" + body + + fmt.Println("Opening browser to file request.") + browser.OpenURL(fullURL + url.PathEscape(params)) + result = Prompt("We have a guide for adding support for your distribution. Would you like to view it?", "yes") + if strings.ToLower(result) == "yes" { + browser.OpenURL("https://wails.app/guides/distro/") + } + return nil +} diff --git a/cmd/linux_test.go b/cmd/linux_test.go new file mode 100644 index 000000000..73f7eec43 --- /dev/null +++ b/cmd/linux_test.go @@ -0,0 +1,46 @@ +package cmd + +import "testing" + +func TestUbuntuDetection(t *testing.T) { + osrelease := ` +NAME="Ubuntu" +VERSION="18.04.2 LTS (Bionic Beaver)" +ID=ubuntu +ID_LIKE=debian +PRETTY_NAME="Ubuntu 18.04.2 LTS" +VERSION_ID="18.04" +HOME_URL="https://www.ubuntu.com/" +SUPPORT_URL="https://help.ubuntu.com/" +BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/" +PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy" +VERSION_CODENAME=bionic +UBUNTU_CODENAME=bionic +` + + result := parseOsRelease(osrelease) + if result.Distribution != Ubuntu { + t.Errorf("expected 'Ubuntu' ID but got '%d'", result.Distribution) + } +} + +func TestTumbleweedDetection(t *testing.T) { + osrelease := ` +NAME="openSUSE Tumbleweed" +# VERSION="20200414" +ID="opensuse-tumbleweed" +ID_LIKE="opensuse suse" +VERSION_ID="20200414" +PRETTY_NAME="openSUSE Tumbleweed" +ANSI_COLOR="0;32" +CPE_NAME="cpe:/o:opensuse:tumbleweed:20200414" +BUG_REPORT_URL="https://bugs.opensuse.org" +HOME_URL="https://www.opensuse.org/" +LOGO="distributor-logo" +` + + result := parseOsRelease(osrelease) + if result.Distribution != Tumbleweed { + t.Errorf("expected 'Tumbleweed' ID but got '%d'", result.Distribution) + } +} diff --git a/cmd/linuxdb.go b/cmd/linuxdb.go new file mode 100644 index 000000000..fbea6b686 --- /dev/null +++ b/cmd/linuxdb.go @@ -0,0 +1,93 @@ +package cmd + +import ( + "log" + + "gopkg.in/yaml.v3" +) + +// LinuxDB is the database for linux distribution data. +type LinuxDB struct { + Distributions map[string]*Distribution `yaml:"distributions"` +} + +// Distribution holds the os-release ID and a map of releases. +type Distribution struct { + ID string `yaml:"id"` + Releases map[string]*Release `yaml:"releases"` +} + +// GetRelease attempts to return the specific Release information +// for the given release name. If there is no specific match, the +// default release data is returned. +func (d *Distribution) GetRelease(version string) *Release { + result := d.Releases[version] + if result == nil { + result = d.Releases["default"] + } + return result +} + +// Release holds the name and version of the release as given by +// os-release. Programs is a slice of dependant programs required +// to be present on the local installation for Wails to function. +// Libraries is a slice of libraries that must be present for Wails +// applications to compile. +type Release struct { + Name string `yaml:"name"` + Version string `yaml:"version"` + GccVersionCommand string `yaml:"gccversioncommand"` + Programs []*Prerequisite `yaml:"programs"` + Libraries []*Prerequisite `yaml:"libraries"` +} + +// Prerequisite is a simple struct containing a program/library name +// plus the distribution specific help text indicating how to install +// it. +type Prerequisite struct { + Name string `yaml:"name"` + Help string `yaml:"help,omitempty"` +} + +// Load will load the given filename from disk and attempt to +// import the data into the LinuxDB. +func (l *LinuxDB) Load(filename string) error { + if fs.FileExists(filename) { + data, err := fs.LoadAsBytes(filename) + if err != nil { + return err + } + return l.ImportData(data) + } + return nil +} + +// ImportData will unmarshal the given YAML formatted data +// into the LinuxDB +func (l *LinuxDB) ImportData(data []byte) error { + return yaml.Unmarshal(data, l) +} + +// GetDistro returns the Distribution information for the +// given distribution name. If the distribution is not supported, +// nil is returned. +func (l *LinuxDB) GetDistro(distro string) *Distribution { + return l.Distributions[distro] +} + +// NewLinuxDB creates a new LinuxDB instance from the bundled +// linuxdb.yaml file. +func NewLinuxDB() *LinuxDB { + data, err := fs.LoadRelativeFile("./linuxdb.yaml") + if err != nil { + log.Fatal("Could not load linuxdb.yaml") + } + result := LinuxDB{ + Distributions: make(map[string]*Distribution), + } + err = result.ImportData(data) + if err != nil { + log.Fatal(err) + } + return &result +} diff --git a/cmd/linuxdb.yaml b/cmd/linuxdb.yaml new file mode 100644 index 000000000..64628a5ea --- /dev/null +++ b/cmd/linuxdb.yaml @@ -0,0 +1,375 @@ +--- +distributions: + debian: + id: debian + releases: + default: + name: Debian + version: default + gccversioncommand: &gccdumpversion -dumpversion + programs: &debiandefaultprograms + - name: gcc + help: Please install with `sudo apt-get install build-essential` and try again + - name: pkg-config + help: Please install with `sudo apt-get install pkg-config` and try again + - name: npm + help: Please install with `curl -sL https://deb.nodesource.com/setup_12.x | sudo bash - && sudo apt-get install -y nodejs` and try again + libraries: &debiandefaultlibraries + - name: libgtk-3-dev + help: Please install with `sudo apt-get install libgtk-3-dev` and try again + - name: libwebkit2gtk-4.0-dev + help: Please install with `sudo apt-get install libwebkit2gtk-4.0-dev` and try again + ubuntu: + id: ubuntu + releases: + default: + version: default + name: Ubuntu + gccversioncommand: &gccdumpfullversion -dumpfullversion + programs: *debiandefaultprograms + libraries: *debiandefaultlibraries + pop: + id: pop + releases: + default: + version: default + name: Pop!_OS + gccversioncommand: &gccdumpfullversion -dumpfullversion + programs: *debiandefaultprograms + libraries: *debiandefaultlibraries + kali: + id: kali + releases: + default: + version: default + name: Kali GNU/Linux + gccversioncommand: *gccdumpfullversion + programs: *debiandefaultprograms + libraries: *debiandefaultlibraries + parrot: + id: parrot + releases: + default: + version: default + name: Parrot GNU/Linux + gccversioncommand: *gccdumpversion + programs: *debiandefaultprograms + libraries: *debiandefaultlibraries + zorin: + id: zorin + releases: + default: + version: default + name: Zorin + gccversioncommand: *gccdumpversion + programs: *debiandefaultprograms + libraries: *debiandefaultlibraries + linuxmint: + id: linuxmint + releases: + default: + version: default + name: Linux Mint + gccversioncommand: *gccdumpversion + programs: *debiandefaultprograms + libraries: *debiandefaultlibraries + elementary: + id: elementary + releases: + default: + version: default + name: elementary OS + gccversioncommand: *gccdumpfullversion + programs: *debiandefaultprograms + libraries: *debiandefaultlibraries + neon: + id: neon + releases: + default: + version: default + name: KDE neon + gccversioncommand: *gccdumpfullversion + programs: *debiandefaultprograms + libraries: *debiandefaultlibraries + deepin: + id: deepin + releases: + default: + version: default + name: Deepin + gccversioncommand: *gccdumpfullversion + programs: *debiandefaultprograms + libraries: *debiandefaultlibraries + void: + id: void + releases: + default: + version: default + name: VoidLinux + gccversioncommand: *gccdumpversion + programs: + - name: gcc + help: Please install with `xbps-install base-devel` and try again + - name: pkg-config + help: Please install with `xbps-install pkg-config` and try again + - name: npm + help: Please install with `xbps-install nodejs` and try again + libraries: + - name: gtk+3-devel + help: Please install with `xbps-install gtk+3-devel` and try again + - name: webkit2gtk-devel + help: Please install with `xbps-install webkit2gtk-devel` and try again + centos: + id: centos + releases: + default: + version: default + name: CentOS Linux + gccversioncommand: *gccdumpversion + programs: + - name: gcc + help: Please install with `sudo yum install gcc-c++ make` and try again + - name: pkg-config + help: Please install with `sudo yum install pkgconf-pkg-config` and try again + - name: npm + help: Please install with `sudo yum install epel-release && sudo yum install nodejs` and try again + libraries: + - name: gtk3-devel + help: Please install with `sudo yum install gtk3-devel` and try again + - name: webkitgtk3-devel + help: Please install with `sudo yum install webkitgtk3-devel` and try again + rhel: + id: rhel + releases: + default: + version: default + name: Red Hat Enterprise Linux + gccversioncommand: *gccdumpversion + programs: + - name: gcc + help: Please install with `sudo yum install gcc-c++ make` and try again + - name: pkg-config + help: Please install with `sudo yum install pkgconf-pkg-config` and try again + - name: npm + help: Please install with `sudo yum install epel-release && sudo yum install nodejs` and try again + libraries: + - name: gtk3-devel + help: Please install with `sudo yum install gtk3-devel` and try again + - name: webkitgtk3-devel + help: Please install with `sudo yum install webkitgtk3-devel` and try again + fedora: + id: fedora + releases: + default: + version: default + name: Fedora + gccversioncommand: *gccdumpfullversion + programs: + - name: gcc + help: Please install with `sudo yum install gcc-c++ make` and try again + - name: pkg-config + help: Please install with `sudo yum install pkgconf-pkg-config` and try again + - name: npm + help: Please install `sudo yum install nodejs` and try again + libraries: + - name: gtk3-devel + help: Please install with `sudo yum install gtk3-devel` and try again + - name: webkit2gtk3-devel + help: Please install with `sudo yum install webkit2gtk3-devel` and try again + arch: + id: arch + releases: + default: + version: default + name: Arch Linux + gccversioncommand: *gccdumpversion + programs: &archdefaultprograms + - name: gcc + help: Please install with `sudo pacman -S gcc` and try again + - name: pkgconf + help: Please install with `sudo pacman -S pkgconf` and try again + - name: npm + help: Please install with `sudo pacman -S npm` and try again + libraries: &archdefaultlibraries + - name: gtk3 + help: Please install with `sudo pacman -S gtk3` and try again + - name: webkit2gtk + help: Please install with `sudo pacman -S webkit2gtk` and try again + arcolinux: + id: arcolinux + releases: + default: + version: default + name: ArcoLinux + gccversioncommand: *gccdumpversion + programs: *archdefaultprograms + libraries: *archdefaultlibraries + archlabs: + id: archlabs + releases: + default: + version: default + name: ArchLabs + gccversioncommand: *gccdumpversion + programs: *archdefaultprograms + libraries: *archdefaultlibraries + artix: + id: artix + releases: + default: + version: default + name: Artix Linux + gccversioncommand: *gccdumpversion + programs: *archdefaultprograms + libraries: *archdefaultlibraries + ctlos: + id: ctlos + releases: + default: + version: default + name: Ctlos Linux + gccversioncommand: *gccdumpversion + programs: *archdefaultprograms + libraries: *archdefaultlibraries + endeavouros: + id: endeavouros + releases: + default: + version: default + name: EndeavourOS + gccversioncommand: *gccdumpversion + programs: *archdefaultprograms + libraries: *archdefaultlibraries + manjaro: + id: manjaro + releases: + default: + version: default + name: Manjaro Linux + gccversioncommand: *gccdumpversion + programs: *archdefaultprograms + libraries: *archdefaultlibraries + manjaro-arm: + id: manjaro-arm + releases: + default: + version: default + name: Manjaro-ARM + gccversioncommand: *gccdumpversion + programs: *archdefaultprograms + libraries: *archdefaultlibraries + gentoo: + id: gentoo + releases: + default: + version: default + name: Gentoo + gccversioncommand: *gccdumpversion + programs: + - name: gcc + help: Please install using your system's package manager + - name: pkg-config + help: Please install using your system's package manager + - name: npm + help: Please install using your system's package manager + libraries: + - name: gtk+:3 + help: Please install with `sudo emerge gtk+:3` and try again + - name: webkit-gtk + help: Please install with `sudo emerge webkit-gtk` and try again + + raspbian: + id: raspbian + releases: + default: + version: default + name: Raspbian + gccversioncommand: *gccdumpfullversion + programs: *debiandefaultprograms + libraries: *debiandefaultlibraries + solus: + id: solus + releases: + default: + version: default + name: Solus + gccversioncommand: *gccdumpfullversion + programs: &solusdefaultprograms + - name: gcc + help: Please install with `sudo eopkg it -c system.devel` and try again + - name: pkg-config + help: Please install with `sudo eopkg it -c system.devel` and try again + - name: npm + help: Please install with `sudo eopkg it nodejs` and try again + libraries: &solusdefaultlibraries + - name: libgtk-3-devel + help: Please install with `sudo eopkg it libgtk-3-devel` and try again + - name: libwebkit-gtk-devel + help: Please install with `sudo eopkg it libwebkit-gtk-devel` and try again + + opensuse-tumbleweed: + id: opensuse-tumbleweed + releases: + default: + version: default + name: openSUSE Tumbleweed + gccversioncommand: *gccdumpfullversion + programs: &opensusedefaultprograms + - name: gcc + help: Please install with `sudo zypper in gcc-c++` and try again + - name: pkg-config + help: Please install with `sudo zypper in pkgconf-pkg-config` and try again + - name: npm + help: Please install `sudo zypper in nodejs` and try again + libraries: &opensusedefaultlibraries + - name: gtk3-devel + help: Please install with `sudo zypper in gtk3-devel` and try again + - name: webkit2gtk3-devel + help: Please install with `sudo zypper in webkit2gtk3-devel` and try again + opensuse-leap: + id: opensuse-leap + releases: + default: + version: default + name: openSUSE Leap + gccversioncommand: *gccdumpfullversion + programs: *opensusedefaultprograms + libraries: *opensusedefaultlibraries + crux: + id: crux + releases: + default: + version: default + name: Crux Linux + gccversioncommand: *gccdumpversion + programs: + - name: gcc + help: Please install with `sudo prt-get depinst gcc-c++ make` and try again + - name: pkg-config + help: Please install with `sudo prt-get depinst pkg-config` and try again + - name: npm + help: Please install with `sudo prt-get depinst nodejs` and try again + libraries: + - name: gtk3 + help: Please install with `sudo prt-get depinst gtk3` and try again + - name: webkitgtk + help: Please install with `sudo prt-get depinst webkitgtk` and try again + nixos: + id: nixos + releases: + default: + version: default + name: NixOS + gccversioncommand: *gccdumpversion + programs: + - name: gcc + help: Please install with `nix-env -iA nixos.gcc` + - name: pkg-config + help: Please install with `nix-env -iA nixos.pkg-config` + - name: npm + help: Please install with `nix-env -iA nixos.nodejs` + libraries: + - name: gtk+3 + help: Please install with `nix-env -iA nixos.gtk3` + - name: webkitgtk + help: Please install with `nix-env -iA nixos.nodePackages.webkitgtk` diff --git a/cmd/linuxdb_test.go b/cmd/linuxdb_test.go new file mode 100644 index 000000000..795a010d2 --- /dev/null +++ b/cmd/linuxdb_test.go @@ -0,0 +1,81 @@ +package cmd + +import "testing" + +func TestNewLinuxDB(t *testing.T) { + _ = NewLinuxDB() +} + +func TestKnownDistro(t *testing.T) { + var linuxDB = NewLinuxDB() + result := linuxDB.GetDistro("ubuntu") + if result == nil { + t.Error("Cannot get distro 'ubuntu'") + } +} + +func TestUnknownDistro(t *testing.T) { + var linuxDB = NewLinuxDB() + result := linuxDB.GetDistro("unknown") + if result != nil { + t.Error("Should get nil for distribution 'unknown'") + } +} + +func TestDefaultRelease(t *testing.T) { + var linuxDB = NewLinuxDB() + result := linuxDB.GetDistro("ubuntu") + if result == nil { + t.Error("Cannot get distro 'ubuntu'") + } + + release := result.GetRelease("default") + if release == nil { + t.Error("Cannot get release 'default' for distro 'ubuntu'") + } +} + +func TestUnknownRelease(t *testing.T) { + var linuxDB = NewLinuxDB() + result := linuxDB.GetDistro("ubuntu") + if result == nil { + t.Error("Cannot get distro 'ubuntu'") + } + + release := result.GetRelease("16.04") + if release == nil { + t.Error("Failed to get release 'default' for unknown release version '16.04'") + } + + if release.Version != "default" { + t.Errorf("Got version '%s' instead of 'default' for unknown release version '16.04'", result.ID) + } +} + +func TestGetPrerequisites(t *testing.T) { + var linuxDB = NewLinuxDB() + result := linuxDB.GetDistro("debian") + if result == nil { + t.Error("Cannot get distro 'debian'") + } + + release := result.GetRelease("default") + if release == nil { + t.Error("Failed to get release 'default' for unknown release version '16.04'") + } + + if release.Version != "default" { + t.Errorf("Got version '%s' instead of 'default' for unknown release version '16.04'", result.ID) + } + + if release.Name != "Debian" { + t.Errorf("Got Release Name '%s' instead of 'debian' for unknown release version '16.04'", release.Name) + } + + if len(release.Programs) != 3 { + t.Errorf("Expected %d programs for unknown release version '16.04'", len(release.Programs)) + } + if len(release.Libraries) != 2 { + t.Errorf("Expected %d libraries for unknown release version '16.04'", len(release.Libraries)) + } +} diff --git a/cmd/log.go b/cmd/log.go new file mode 100644 index 000000000..416383935 --- /dev/null +++ b/cmd/log.go @@ -0,0 +1,130 @@ +package cmd + +import ( + "fmt" + "strings" + + "github.com/fatih/color" +) + +// Logger struct +type Logger struct { + errorOnly bool +} + +// NewLogger creates a new logger! +func NewLogger() *Logger { + return &Logger{errorOnly: false} +} + +// SetErrorOnly ensures that only errors are logged out +func (l *Logger) SetErrorOnly(errorOnly bool) { + l.errorOnly = errorOnly +} + +// Yellow - Outputs yellow text +func (l *Logger) Yellow(format string, a ...interface{}) { + if l.errorOnly { + return + } + color.New(color.FgHiYellow).PrintfFunc()(format+"\n", a...) +} + +// Yellowf - Outputs yellow text without the newline +func (l *Logger) Yellowf(format string, a ...interface{}) { + if l.errorOnly { + return + } + + color.New(color.FgHiYellow).PrintfFunc()(format, a...) +} + +// Green - Outputs Green text +func (l *Logger) Green(format string, a ...interface{}) { + if l.errorOnly { + return + } + + color.New(color.FgHiGreen).PrintfFunc()(format+"\n", a...) +} + +// White - Outputs White text +func (l *Logger) White(format string, a ...interface{}) { + if l.errorOnly { + return + } + + color.New(color.FgHiWhite).PrintfFunc()(format+"\n", a...) +} + +// WhiteUnderline - Outputs White text with underline +func (l *Logger) WhiteUnderline(format string, a ...interface{}) { + if l.errorOnly { + return + } + + l.White(format, a...) + l.White(l.underline(format)) +} + +// YellowUnderline - Outputs Yellow text with underline +func (l *Logger) YellowUnderline(format string, a ...interface{}) { + if l.errorOnly { + return + } + + l.Yellow(format, a...) + l.Yellow(l.underline(format)) +} + +// underline returns a string of a line, the length of the message given to it +func (l *Logger) underline(message string) string { + if l.errorOnly { + return "" + } + + return strings.Repeat("-", len(message)) +} + +// Red - Outputs Red text +func (l *Logger) Red(format string, a ...interface{}) { + if l.errorOnly { + return + } + + color.New(color.FgHiRed).PrintfFunc()(format+"\n", a...) +} + +// Error - Outputs an Error message +func (l *Logger) Error(format string, a ...interface{}) { + color.New(color.FgHiRed).PrintfFunc()("Error: "+format+"\n", a...) +} + +// PrintSmallBanner prints a condensed banner +func (l *Logger) PrintSmallBanner(message ...string) { + yellow := color.New(color.FgYellow).SprintFunc() + red := color.New(color.FgRed).SprintFunc() + msg := "" + if len(message) > 0 { + msg = " - " + message[0] + } + fmt.Printf("%s %s%s\n", yellow("Wails"), red(Version), msg) +} + +// PrintBanner prints the Wails banner before running commands +func (l *Logger) PrintBanner() error { + banner1 := ` _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ ` + "`" + `/ / / ___/ +| |/ |/ / /_/ / / (__ ) ` + banner2 := `|__/|__/\__,_/_/_/____/ ` + + l.Yellowf(banner1) + l.Red(Version) + l.Yellowf(banner2) + l.Green("https://wails.app") + l.White("The lightweight framework for web-like apps") + fmt.Println() + + return nil +} diff --git a/cmd/package.go b/cmd/package.go new file mode 100644 index 000000000..8b213462a --- /dev/null +++ b/cmd/package.go @@ -0,0 +1,426 @@ +package cmd + +import ( + "bufio" + "bytes" + "encoding/binary" + "fmt" + "image" + "image/png" + "io/ioutil" + "os" + "path" + "path/filepath" + "runtime" + "strings" + "text/template" + "time" + + "github.com/jackmordaunt/icns" + "golang.org/x/image/draw" +) + +// PackageHelper helps with the 'wails package' command +type PackageHelper struct { + platform string + fs *FSHelper + log *Logger + system *SystemHelper +} + +// NewPackageHelper creates a new PackageHelper! +func NewPackageHelper(platform string) *PackageHelper { + return &PackageHelper{ + platform: platform, + fs: NewFSHelper(), + log: NewLogger(), + system: NewSystemHelper(), + } +} + +type plistData struct { + Title string + Exe string + PackageID string + Version string + Author string + Date string +} + +func newPlistData(title, exe, packageID, version, author string) *plistData { + now := time.Now().Format(time.RFC822) + return &plistData{ + Title: title, + Exe: exe, + Version: version, + PackageID: packageID, + Author: author, + Date: now, + } +} + +type windowsIcoHeader struct { + _ uint16 + imageType uint16 + imageCount uint16 +} + +type windowsIcoDescriptor struct { + width uint8 + height uint8 + colours uint8 + _ uint8 + planes uint16 + bpp uint16 + size uint32 + offset uint32 +} + +type windowsIcoContainer struct { + Header windowsIcoDescriptor + Data []byte +} + +func generateWindowsIcon(pngFilename string, iconfile string) error { + sizes := []int{256, 128, 64, 48, 32, 16} + + pngfile, err := os.Open(pngFilename) + if err != nil { + return err + } + defer pngfile.Close() + + pngdata, err := png.Decode(pngfile) + if err != nil { + return err + } + + icons := []windowsIcoContainer{} + + for _, size := range sizes { + rect := image.Rect(0, 0, int(size), int(size)) + rawdata := image.NewRGBA(rect) + scale := draw.CatmullRom + scale.Scale(rawdata, rect, pngdata, pngdata.Bounds(), draw.Over, nil) + + icondata := new(bytes.Buffer) + writer := bufio.NewWriter(icondata) + err = png.Encode(writer, rawdata) + if err != nil { + return err + } + writer.Flush() + + imgSize := size + if imgSize >= 256 { + imgSize = 0 + } + + data := icondata.Bytes() + + icn := windowsIcoContainer{ + Header: windowsIcoDescriptor{ + width: uint8(imgSize), + height: uint8(imgSize), + planes: 1, + bpp: 32, + size: uint32(len(data)), + }, + Data: data, + } + icons = append(icons, icn) + } + + outfile, err := os.Create(iconfile) + if err != nil { + return err + } + defer outfile.Close() + + ico := windowsIcoHeader{ + imageType: 1, + imageCount: uint16(len(sizes)), + } + err = binary.Write(outfile, binary.LittleEndian, ico) + if err != nil { + return err + } + + offset := uint32(6 + 16*len(sizes)) + for _, icon := range icons { + icon.Header.offset = offset + err = binary.Write(outfile, binary.LittleEndian, icon.Header) + if err != nil { + return err + } + offset += icon.Header.size + } + for _, icon := range icons { + _, err = outfile.Write(icon.Data) + if err != nil { + return err + } + } + return nil +} + +func defaultString(val string, defaultVal string) string { + if val != "" { + return val + } + return defaultVal +} + +func (b *PackageHelper) getPackageFileBaseDir() string { + // Calculate template base dir + _, filename, _, _ := runtime.Caller(1) + return filepath.Join(path.Dir(filename), "packages", b.platform) +} + +// Package the application into a platform specific package +func (b *PackageHelper) Package(po *ProjectOptions) error { + switch b.platform { + case "darwin": + return b.packageOSX(po) + case "windows": + return b.PackageWindows(po, true) + case "linux": + return b.packageLinux(po) + default: + return fmt.Errorf("platform '%s' not supported for bundling yet", b.platform) + } +} + +func (b *PackageHelper) packageLinux(po *ProjectOptions) error { + return nil +} + +// Package the application for OSX +func (b *PackageHelper) packageOSX(po *ProjectOptions) error { + build := path.Join(b.fs.Cwd(), "build") + + system := NewSystemHelper() + config, err := system.LoadConfig() + if err != nil { + return err + } + + name := defaultString(po.Name, "WailsTest") + exe := defaultString(po.BinaryName, name) + version := defaultString(po.Version, "0.1.0") + author := defaultString(config.Name, "Anonymous") + packageID := strings.Join([]string{"wails", name, version}, ".") + plistData := newPlistData(name, exe, packageID, version, author) + appname := po.Name + ".app" + plistFilename := path.Join(build, appname, "Contents", "Info.plist") + customPlist := path.Join(b.fs.Cwd(), "info.plist") + + // Check binary exists + source := path.Join(build, exe) + if po.CrossCompile == true { + file, err := b.fs.FindFile(build, "darwin") + if err != nil { + return err + } + source = path.Join(build, file) + } + + if !b.fs.FileExists(source) { + // We need to build! + return fmt.Errorf("Target '%s' not available. Has it been compiled yet?", source) + } + // Remove the existing package + os.RemoveAll(appname) + + // Create directories + exeDir := path.Join(build, appname, "/Contents/MacOS") + b.fs.MkDirs(exeDir, 0755) + resourceDir := path.Join(build, appname, "/Contents/Resources") + b.fs.MkDirs(resourceDir, 0755) + + // Do we have a custom plist in the project directory? + if !fs.FileExists(customPlist) { + + // No - create a new plist from our defaults + tmpl := template.New("infoPlist") + plistFile := filepath.Join(b.getPackageFileBaseDir(), "info.plist") + infoPlist, err := ioutil.ReadFile(plistFile) + if err != nil { + return err + } + tmpl.Parse(string(infoPlist)) + + // Write the template to a buffer + var tpl bytes.Buffer + err = tmpl.Execute(&tpl, plistData) + if err != nil { + return err + } + + // Save to the package + err = ioutil.WriteFile(plistFilename, tpl.Bytes(), 0644) + if err != nil { + return err + } + + // Also write to project directory for customisation + err = ioutil.WriteFile(customPlist, tpl.Bytes(), 0644) + if err != nil { + return err + } + } else { + // Yes - we have a plist. Copy it to the package verbatim + err = fs.CopyFile(customPlist, plistFilename) + if err != nil { + return err + } + } + + // Copy executable + target := path.Join(exeDir, exe) + err = b.fs.CopyFile(source, target) + if err != nil { + return err + } + + err = os.Chmod(target, 0755) + if err != nil { + return err + } + err = b.packageIconOSX(resourceDir) + return err +} + +// CleanWindows removes any windows related files found in the directory +func (b *PackageHelper) CleanWindows(po *ProjectOptions) { + pdir := b.fs.Cwd() + basename := strings.TrimSuffix(po.BinaryName, ".exe") + exts := []string{".ico", ".exe.manifest", ".rc", "-res.syso"} + rsrcs := []string{} + for _, ext := range exts { + rsrcs = append(rsrcs, filepath.Join(pdir, basename+ext)) + } + b.fs.RemoveFiles(rsrcs, true) +} + +// PackageWindows packages the application for windows platforms +func (b *PackageHelper) PackageWindows(po *ProjectOptions, cleanUp bool) error { + outputDir := b.fs.Cwd() + basename := strings.TrimSuffix(po.BinaryName, ".exe") + + // Copy default icon if needed + icon, err := b.copyIcon() + if err != nil { + return err + } + + // Generate icon from PNG + err = generateWindowsIcon(icon, basename+".ico") + if err != nil { + return err + } + + // Copy manifest + tgtManifestFile := filepath.Join(outputDir, basename+".exe.manifest") + if !b.fs.FileExists(tgtManifestFile) { + srcManifestfile := filepath.Join(b.getPackageFileBaseDir(), "wails.exe.manifest") + err := b.fs.CopyFile(srcManifestfile, tgtManifestFile) + if err != nil { + return err + } + } + + // Copy rc file + tgtRCFile := filepath.Join(outputDir, basename+".rc") + if !b.fs.FileExists(tgtRCFile) { + srcRCfile := filepath.Join(b.getPackageFileBaseDir(), "wails.rc") + rcfilebytes, err := ioutil.ReadFile(srcRCfile) + if err != nil { + return err + } + rcfiledata := strings.Replace(string(rcfilebytes), "$NAME$", basename, -1) + err = ioutil.WriteFile(tgtRCFile, []byte(rcfiledata), 0755) + if err != nil { + return err + } + } + + // Build syso + sysofile := filepath.Join(outputDir, basename+"-res.syso") + + // cross-compile + if b.platform != runtime.GOOS { + args := []string{ + "docker", "run", "--rm", + "-v", outputDir + ":/build", + "--entrypoint", "/bin/sh", + "wailsapp/xgo:1.16.3", + "-c", "/usr/bin/x86_64-w64-mingw32-windres -o /build/" + basename + "-res.syso /build/" + basename + ".rc", + } + if err := NewProgramHelper().RunCommandArray(args); err != nil { + return err + } + } else { + batfile, err := fs.LocalDir(".") + if err != nil { + return err + } + + windresBatFile := filepath.Join(batfile.fullPath, "windres.bat") + windresCommand := []string{windresBatFile, sysofile, tgtRCFile} + err = NewProgramHelper().RunCommandArray(windresCommand) + if err != nil { + return err + } + } + return nil +} + +func (b *PackageHelper) copyIcon() (string, error) { + + // TODO: Read this from project.json + const appIconFilename = "appicon.png" + srcIcon := path.Join(b.fs.Cwd(), appIconFilename) + + // Check if appicon.png exists + if !b.fs.FileExists(srcIcon) { + + // Install default icon + iconfile := filepath.Join(b.getPackageFileBaseDir(), "icon.png") + iconData, err := ioutil.ReadFile(iconfile) + if err != nil { + return "", err + } + err = ioutil.WriteFile(srcIcon, iconData, 0644) + if err != nil { + return "", err + } + } + return srcIcon, nil +} + +func (b *PackageHelper) packageIconOSX(resourceDir string) error { + + srcIcon, err := b.copyIcon() + if err != nil { + return err + } + tgtBundle := path.Join(resourceDir, "iconfile.icns") + imageFile, err := os.Open(srcIcon) + if err != nil { + return err + } + defer imageFile.Close() + srcImg, _, err := image.Decode(imageFile) + if err != nil { + return err + + } + dest, err := os.Create(tgtBundle) + if err != nil { + return err + + } + defer dest.Close() + return icns.Encode(dest, srcImg) +} diff --git a/cmd/packages/darwin/icon.png b/cmd/packages/darwin/icon.png new file mode 100644 index 000000000..9f22be34b Binary files /dev/null and b/cmd/packages/darwin/icon.png differ diff --git a/cmd/packages/darwin/info.plist b/cmd/packages/darwin/info.plist new file mode 100644 index 000000000..c7289870f --- /dev/null +++ b/cmd/packages/darwin/info.plist @@ -0,0 +1,12 @@ + + + CFBundlePackageTypeAPPL + CFBundleName{{.Title}} + CFBundleExecutable{{.Exe}} + CFBundleIdentifier{{.PackageID}} + CFBundleVersion{{.Version}} + CFBundleGetInfoStringBuilt by {{.Author}} at {{.Date}} using Wails (https://wails.app) + CFBundleShortVersionString{{.Version}} + CFBundleIconFileiconfile + NSHighResolutionCapabletrue + \ No newline at end of file diff --git a/cmd/packages/windows/icon.png b/cmd/packages/windows/icon.png new file mode 100644 index 000000000..9f22be34b Binary files /dev/null and b/cmd/packages/windows/icon.png differ diff --git a/cmd/packages/windows/wails.exe.manifest b/cmd/packages/windows/wails.exe.manifest new file mode 100644 index 000000000..b236d268f --- /dev/null +++ b/cmd/packages/windows/wails.exe.manifest @@ -0,0 +1,12 @@ + + + + + + + true/pm + permonitorv2,permonitor + true + + + \ No newline at end of file diff --git a/cmd/packages/windows/wails.ico b/cmd/packages/windows/wails.ico new file mode 100644 index 000000000..9b62ac5b4 Binary files /dev/null and b/cmd/packages/windows/wails.ico differ diff --git a/cmd/packages/windows/wails.rc b/cmd/packages/windows/wails.rc new file mode 100644 index 000000000..633bd214a --- /dev/null +++ b/cmd/packages/windows/wails.rc @@ -0,0 +1,2 @@ +100 ICON "$NAME$.ico" +110 24 "$NAME$.exe.manifest" \ No newline at end of file diff --git a/cmd/prerequisites.go b/cmd/prerequisites.go new file mode 100644 index 000000000..3f88ae8ce --- /dev/null +++ b/cmd/prerequisites.go @@ -0,0 +1,100 @@ +package cmd + +import ( + "fmt" + "runtime" +) + +func newPrerequisite(name, help string) *Prerequisite { + return &Prerequisite{Name: name, Help: help} +} + +// Prerequisites is a list of things required to use Wails +type Prerequisites []*Prerequisite + +// Add given prereq object to list +func (p *Prerequisites) Add(prereq *Prerequisite) { + *p = append(*p, prereq) +} + +// GetRequiredPrograms returns a list of programs required for the platform +func GetRequiredPrograms() (*Prerequisites, error) { + switch runtime.GOOS { + case "darwin": + return getRequiredProgramsOSX(), nil + case "linux": + return getRequiredProgramsLinux(), nil + case "windows": + return getRequiredProgramsWindows(), nil + default: + return nil, fmt.Errorf("platform '%s' not supported at this time", runtime.GOOS) + } +} + +func getRequiredProgramsOSX() *Prerequisites { + result := &Prerequisites{} + result.Add(newPrerequisite("clang", "Please install with `xcode-select --install` and try again")) + result.Add(newPrerequisite("npm", "Please install from https://nodejs.org/en/download/ and try again")) + return result +} + +func getRequiredProgramsLinux() *Prerequisites { + result := &Prerequisites{} + distroInfo := GetLinuxDistroInfo() + if distroInfo.Distribution != Unknown { + var linuxDB = NewLinuxDB() + distro := linuxDB.GetDistro(distroInfo.ID) + release := distro.GetRelease(distroInfo.Release) + for _, program := range release.Programs { + result.Add(program) + } + } + return result +} + +// TODO: Test this on Windows +func getRequiredProgramsWindows() *Prerequisites { + result := &Prerequisites{} + result.Add(newPrerequisite("gcc", "Please install gcc from here and try again: http://tdm-gcc.tdragon.net/download. You will need to add the bin directory to your path, EG: C:\\TDM-GCC-64\\bin\\")) + result.Add(newPrerequisite("npm", "Please install node/npm from here and try again: https://nodejs.org/en/download/")) + return result +} + +// GetRequiredLibraries returns a list of libraries (packages) required for the platform +func GetRequiredLibraries() (*Prerequisites, error) { + switch runtime.GOOS { + case "darwin": + return getRequiredLibrariesOSX() + case "linux": + return getRequiredLibrariesLinux() + case "windows": + return getRequiredLibrariesWindows() + default: + return nil, fmt.Errorf("platform '%s' not supported at this time", runtime.GOOS) + } +} + +func getRequiredLibrariesOSX() (*Prerequisites, error) { + result := &Prerequisites{} + return result, nil +} + +func getRequiredLibrariesLinux() (*Prerequisites, error) { + result := &Prerequisites{} + // The Linux Distribution DB + distroInfo := GetLinuxDistroInfo() + if distroInfo.Distribution != Unknown { + var linuxDB = NewLinuxDB() + distro := linuxDB.GetDistro(distroInfo.ID) + release := distro.GetRelease(distroInfo.Release) + for _, library := range release.Libraries { + result.Add(library) + } + } + return result, nil +} + +func getRequiredLibrariesWindows() (*Prerequisites, error) { + result := &Prerequisites{} + return result, nil +} diff --git a/cmd/program.go b/cmd/program.go new file mode 100644 index 000000000..733bd51a7 --- /dev/null +++ b/cmd/program.go @@ -0,0 +1,162 @@ +package cmd + +import ( + "bytes" + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + "syscall" +) + +// ProgramHelper - Utility functions around installed applications +type ProgramHelper struct { + shell *ShellHelper + verbose bool +} + +// NewProgramHelper - Creates a new ProgramHelper +func NewProgramHelper(verbose ...bool) *ProgramHelper { + result := &ProgramHelper{ + shell: NewShellHelper(), + } + if len(verbose) > 0 { + result.verbose = verbose[0] + if result.verbose { + result.shell.SetVerbose() + } + } + return result +} + +// IsInstalled tries to determine if the given binary name is installed +func (p *ProgramHelper) IsInstalled(programName string) bool { + _, err := exec.LookPath(programName) + return err == nil +} + +// Program - A struct to define an installed application/binary +type Program struct { + Name string `json:"name"` + Path string `json:"path"` + verbose bool +} + +// FindProgram attempts to find the given program on the system.FindProgram +// Returns a struct with the name and path to the program +func (p *ProgramHelper) FindProgram(programName string) *Program { + path, err := exec.LookPath(programName) + if err != nil { + return nil + } + path, err = filepath.Abs(path) + if err != nil { + return nil + } + return &Program{ + Name: programName, + Path: path, + verbose: p.verbose, + } +} + +// GetFullPathToBinary returns the full path the the current binary +func (p *Program) GetFullPathToBinary() (string, error) { + return filepath.Abs(p.Path) +} + +// Run will execute the program with the given parameters +// Returns stdout + stderr as strings and an error if one occurred +func (p *Program) Run(vars ...string) (stdout, stderr string, exitCode int, err error) { + command, err := p.GetFullPathToBinary() + if err != nil { + return "", "", 1, err + } + cmd := exec.Command(command, vars...) + if !p.verbose { + var stdo, stde bytes.Buffer + cmd.Stdout = &stdo + cmd.Stderr = &stde + err = cmd.Run() + stdout = string(stdo.Bytes()) + stderr = string(stde.Bytes()) + } else { + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + err = cmd.Run() + } + + // https://stackoverflow.com/questions/10385551/get-exit-code-go + if err != nil { + // try to get the exit code + if exitError, ok := err.(*exec.ExitError); ok { + ws := exitError.Sys().(syscall.WaitStatus) + exitCode = ws.ExitStatus() + } else { + exitCode = 1 + if stderr == "" { + stderr = err.Error() + } + } + } else { + // success, exitCode should be 0 if go is ok + ws := cmd.ProcessState.Sys().(syscall.WaitStatus) + exitCode = ws.ExitStatus() + } + return +} + +// InstallGoPackage installs the given Go package +func (p *ProgramHelper) InstallGoPackage(packageName string) error { + args := strings.Split("get "+packageName, " ") + _, stderr, err := p.shell.Run("go", args...) + if err != nil { + fmt.Println(stderr) + } + return err +} + +// InstallNPMPackage installs the given npm package +func (p *ProgramHelper) InstallNPMPackage(packageName string, save bool) error { + args := strings.Split("install "+packageName, " ") + if save { + args = append(args, "--save") + } + _, stderr, err := p.shell.Run("npm", args...) + if err != nil { + fmt.Println(stderr) + } + return err +} + +// RunCommand runs the given command +func (p *ProgramHelper) RunCommand(command string) error { + args := strings.Split(command, " ") + return p.RunCommandArray(args) +} + +// RunCommandArray runs the command specified in the array +func (p *ProgramHelper) RunCommandArray(args []string, dir ...string) error { + programCommand := args[0] + // TODO: Run FindProgram here and get the full path to the exe + program, err := exec.LookPath(programCommand) + if err != nil { + fmt.Printf("ERROR: Looks like '%s' isn't installed. Please install and try again.", programCommand) + return err + } + + args = args[1:] + var stderr string + var stdout string + if len(dir) > 0 { + stdout, stderr, err = p.shell.RunInDirectory(dir[0], program, args...) + } else { + stdout, stderr, err = p.shell.Run(program, args...) + } + if err != nil { + fmt.Println(stderr) + fmt.Println(stdout) + } + return err +} diff --git a/cmd/project.go b/cmd/project.go new file mode 100644 index 000000000..efe772579 --- /dev/null +++ b/cmd/project.go @@ -0,0 +1,407 @@ +package cmd + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "runtime" + "sort" + "strings" + + "github.com/leaanthony/slicer" +) + +// PackageManager indicates different package managers +type PackageManager int + +const ( + // UNKNOWN package manager + UNKNOWN PackageManager = iota + // NPM package manager + NPM + // YARN package manager + YARN +) + +type author struct { + Name string `json:"name"` + Email string `json:"email"` +} + +type frontend struct { + Dir string `json:"dir"` + Install string `json:"install"` + Build string `json:"build"` + Bridge string `json:"bridge"` + Serve string `json:"serve"` +} + +type framework struct { + Name string `json:"name"` + BuildTag string `json:"buildtag"` + Options map[string]string `json:"options,omitempty"` +} + +// ProjectHelper is a helper struct for managing projects +type ProjectHelper struct { + log *Logger + system *SystemHelper + templates *TemplateHelper +} + +// NewProjectHelper creates a new Project helper struct +func NewProjectHelper() *ProjectHelper { + return &ProjectHelper{ + log: NewLogger(), + system: NewSystemHelper(), + templates: NewTemplateHelper(), + } +} + +// GenerateProject generates a new project using the options given +func (ph *ProjectHelper) GenerateProject(projectOptions *ProjectOptions) error { + + // Calculate project path + projectPath, err := filepath.Abs(projectOptions.OutputDirectory) + if err != nil { + return err + } + + _ = projectPath + + if fs.DirExists(projectPath) { + return fmt.Errorf("directory '%s' already exists", projectPath) + } + + // Create project directory + err = fs.MkDir(projectPath) + if err != nil { + return err + } + + // Create and save project config + err = projectOptions.WriteProjectConfig() + if err != nil { + return err + } + + err = ph.templates.InstallTemplate(projectPath, projectOptions) + if err != nil { + return err + } + + // // If we are on windows, dump a windows_resource.json + // if runtime.GOOS == "windows" { + // ph.GenerateWindowsResourceConfig(projectOptions) + // } + + return nil +} + +// // GenerateWindowsResourceConfig generates the default windows resource file +// func (ph *ProjectHelper) GenerateWindowsResourceConfig(po *ProjectOptions) { + +// fmt.Println(buffer.String()) + +// // vi.Build() +// // vi.Walk() +// // err := vi.WriteSyso(outPath, runtime.GOARCH) +// } + +// LoadProjectConfig loads the project config from the given directory +func (ph *ProjectHelper) LoadProjectConfig(dir string) (*ProjectOptions, error) { + po := ph.NewProjectOptions() + err := po.LoadConfig(dir) + return po, err +} + +// NewProjectOptions creates a new default set of project options +func (ph *ProjectHelper) NewProjectOptions() *ProjectOptions { + result := ProjectOptions{ + Name: "", + Description: "Enter your project description", + Version: "0.1.0", + BinaryName: "", + system: ph.system, + log: ph.log, + templates: ph.templates, + Author: &author{}, + } + + // Populate system config + config, err := ph.system.LoadConfig() + if err == nil { + result.Author.Name = config.Name + result.Author.Email = config.Email + } + + return &result +} + +// ProjectOptions holds all the options available for a project +type ProjectOptions struct { + Name string `json:"name"` + Description string `json:"description"` + Author *author `json:"author,omitempty"` + Version string `json:"version"` + OutputDirectory string `json:"-"` + UseDefaults bool `json:"-"` + Template string `json:"-"` + BinaryName string `json:"binaryname"` + FrontEnd *frontend `json:"frontend,omitempty"` + Tags string `json:"tags"` + NPMProjectName string `json:"-"` + system *SystemHelper + log *Logger + templates *TemplateHelper + selectedTemplate *TemplateDetails + WailsVersion string + typescriptDefsFilename string + Verbose bool `json:"-"` + CrossCompile bool + Platform string + Architecture string + LdFlags string + GoPath string + UseFirebug bool + + // Supported platforms + Platforms []string `json:"platforms,omitempty"` +} + +// PlatformSupported returns true if the template is supported +// on the current platform +func (po *ProjectOptions) PlatformSupported() bool { + + // Default is all platforms supported + if len(po.Platforms) == 0 { + return true + } + + // Check that the platform is in the list + platformsSupported := slicer.String(po.Platforms) + return platformsSupported.Contains(runtime.GOOS) +} + +// Defaults sets the default project template +func (po *ProjectOptions) Defaults() { + po.Template = "vuebasic" + po.WailsVersion = Version +} + +// SetTypescriptDefsFilename indicates that we want to generate typescript bindings to the given file +func (po *ProjectOptions) SetTypescriptDefsFilename(filename string) { + po.typescriptDefsFilename = filename +} + +// GetNPMBinaryName returns the type of package manager used by the project +func (po *ProjectOptions) GetNPMBinaryName() (PackageManager, error) { + if po.FrontEnd == nil { + return UNKNOWN, fmt.Errorf("No frontend specified in project options") + } + + if strings.Index(po.FrontEnd.Install, "npm") > -1 { + return NPM, nil + } + + if strings.Index(po.FrontEnd.Install, "yarn") > -1 { + return YARN, nil + } + + return UNKNOWN, nil +} + +// PromptForInputs asks the user to input project details +func (po *ProjectOptions) PromptForInputs() error { + + processProjectName(po) + + processBinaryName(po) + + err := processOutputDirectory(po) + if err != nil { + return err + } + + // Process Templates + templateList := slicer.Interface() + options := slicer.String() + templateDetails, err := po.templates.GetTemplateDetails() + if err != nil { + return err + } + + if po.Template != "" { + // Check template is valid if given + if templateDetails[po.Template] == nil { + keys := make([]string, 0, len(templateDetails)) + for k := range templateDetails { + keys = append(keys, k) + } + return fmt.Errorf("invalid template name '%s'. Valid options: %s", po.Template, strings.Join(keys, ", ")) + } + po.selectedTemplate = templateDetails[po.Template] + } else { + + keys := make([]string, 0) + for k := range templateDetails { + keys = append(keys, k) + } + sort.Strings(keys) + for _, k := range keys { + templateDetail := templateDetails[k] + templateList.Add(templateDetail) + if !templateDetail.Metadata.PlatformSupported() { + templateDetail.Metadata.Name = "* " + templateDetail.Metadata.Name + } + options.Add(fmt.Sprintf("%s - %s", templateDetail.Metadata.Name, templateDetail.Metadata.ShortDescription)) + } + + templateIndex := 0 + + if len(options.AsSlice()) > 1 { + templateIndex = PromptSelection("Please select a template (* means unsupported on current platform)", options.AsSlice(), 0) + } + + if len(templateList.AsSlice()) == 0 { + return fmt.Errorf("aborting: no templates found") + } + + // After selection do this.... + po.selectedTemplate = templateList.AsSlice()[templateIndex].(*TemplateDetails) + } + + po.selectedTemplate.Metadata.Name = strings.TrimPrefix(po.selectedTemplate.Metadata.Name, "* ") + if !po.selectedTemplate.Metadata.PlatformSupported() { + println("WARNING: This template is unsupported on this platform!") + } + fmt.Println("Template: " + po.selectedTemplate.Metadata.Name) + + // Setup NPM Project name + po.NPMProjectName = strings.ToLower(strings.Replace(po.Name, " ", "_", -1)) + + // Fix template name + po.Template = strings.Split(po.selectedTemplate.Path, string(os.PathSeparator))[0] + + // // Populate template details + templateMetadata := po.selectedTemplate.Metadata + + err = processTemplateMetadata(templateMetadata, po) + if err != nil { + return err + } + + return nil +} + +// WriteProjectConfig writes the project configuration into +// the project directory +func (po *ProjectOptions) WriteProjectConfig() error { + targetDir, err := filepath.Abs(po.OutputDirectory) + if err != nil { + return err + } + + targetFile := filepath.Join(targetDir, "project.json") + filedata, err := json.MarshalIndent(po, "", " ") + if err != nil { + return err + } + + return ioutil.WriteFile(targetFile, filedata, 0600) +} + +// LoadConfig loads the project configuration file from the +// given directory +func (po *ProjectOptions) LoadConfig(projectDir string) error { + targetFile := filepath.Join(projectDir, "project.json") + rawBytes, err := ioutil.ReadFile(targetFile) + if err != nil { + return err + } + return json.Unmarshal(rawBytes, po) +} + +func computeBinaryName(projectName string) string { + if projectName == "" { + return "" + } + var binaryNameComputed = strings.ToLower(projectName) + binaryNameComputed = strings.Replace(binaryNameComputed, " ", "-", -1) + binaryNameComputed = strings.Replace(binaryNameComputed, string(filepath.Separator), "-", -1) + binaryNameComputed = strings.Replace(binaryNameComputed, ":", "-", -1) + return binaryNameComputed +} + +func processOutputDirectory(po *ProjectOptions) error { + // po.OutputDirectory + if po.OutputDirectory == "" { + po.OutputDirectory = PromptRequired("Project directory name", computeBinaryName(po.Name)) + } + projectPath, err := filepath.Abs(po.OutputDirectory) + if err != nil { + return err + } + + if NewFSHelper().DirExists(projectPath) { + return fmt.Errorf("directory '%s' already exists", projectPath) + } + + fmt.Println("Project Directory: " + po.OutputDirectory) + return nil +} + +func processProjectName(po *ProjectOptions) { + if po.Name == "" { + po.Name = Prompt("The name of the project", "My Project") + } + fmt.Println("Project Name: " + po.Name) +} + +func processBinaryName(po *ProjectOptions) { + if po.BinaryName == "" { + var binaryNameComputed = computeBinaryName(po.Name) + po.BinaryName = Prompt("The output binary name", binaryNameComputed) + } + fmt.Println("Output binary Name: " + po.BinaryName) +} + +func processTemplateMetadata(templateMetadata *TemplateMetadata, po *ProjectOptions) error { + if templateMetadata.FrontendDir != "" { + po.FrontEnd = &frontend{} + po.FrontEnd.Dir = templateMetadata.FrontendDir + } + if templateMetadata.Install != "" { + if po.FrontEnd == nil { + return fmt.Errorf("install set in template metadata but not frontenddir") + } + po.FrontEnd.Install = templateMetadata.Install + } + if templateMetadata.Build != "" { + if po.FrontEnd == nil { + return fmt.Errorf("build set in template metadata but not frontenddir") + } + po.FrontEnd.Build = templateMetadata.Build + } + + if templateMetadata.Bridge != "" { + if po.FrontEnd == nil { + return fmt.Errorf("bridge set in template metadata but not frontenddir") + } + po.FrontEnd.Bridge = templateMetadata.Bridge + } + + if templateMetadata.Serve != "" { + if po.FrontEnd == nil { + return fmt.Errorf("serve set in template metadata but not frontenddir") + } + po.FrontEnd.Serve = templateMetadata.Serve + } + + // Save platforms + po.Platforms = templateMetadata.Platforms + + return nil +} diff --git a/cmd/prompt.go b/cmd/prompt.go new file mode 100644 index 000000000..dac324fe4 --- /dev/null +++ b/cmd/prompt.go @@ -0,0 +1,80 @@ +package cmd + +import ( + "bufio" + "fmt" + "os" + "strconv" + "strings" +) + +// Prompt asks the user for a value +func Prompt(question string, defaultValue ...string) string { + var answer string + + if len(defaultValue) > 0 { + answer = defaultValue[0] + question = fmt.Sprintf("%s (%s)", question, answer) + } + fmt.Printf(question + ": ") + reader := bufio.NewReader(os.Stdin) + input, _ := reader.ReadString('\n') + input = strings.TrimSpace(input) + + if input != "" { + answer = input + } + + return answer +} + +// PromptRequired calls Prompt repeatedly until a value is given +func PromptRequired(question string, defaultValue ...string) string { + for { + result := Prompt(question, defaultValue...) + if result != "" { + return result + } + } +} + +// PromptSelection asks the user to choose an option +func PromptSelection(question string, options []string, optionalDefaultValue ...int) int { + + defaultValue := -1 + message := "Please choose an option" + fmt.Println(question + ":") + + if len(optionalDefaultValue) > 0 { + defaultValue = optionalDefaultValue[0] + 1 + message = fmt.Sprintf("%s [%d]", message, defaultValue) + } + + for index, option := range options { + fmt.Printf(" %d: %s\n", index+1, option) + } + + selectedValue := -1 + + for { + choice := Prompt(message) + if choice == "" && defaultValue > -1 { + selectedValue = defaultValue - 1 + break + } + + // index + number, err := strconv.Atoi(choice) + if err == nil { + if number > 0 && number <= len(options) { + selectedValue = number - 1 + break + } else { + continue + } + } + + } + + return selectedValue +} diff --git a/cmd/semver.go b/cmd/semver.go new file mode 100644 index 000000000..ab9405292 --- /dev/null +++ b/cmd/semver.go @@ -0,0 +1,106 @@ +package cmd + +import ( + "fmt" + + "github.com/Masterminds/semver" +) + +// SemanticVersion is a struct containing a semantic version +type SemanticVersion struct { + Version *semver.Version +} + +// NewSemanticVersion creates a new SemanticVersion object with the given version string +func NewSemanticVersion(version string) (*SemanticVersion, error) { + semverVersion, err := semver.NewVersion(version) + if err != nil { + return nil, err + } + return &SemanticVersion{ + Version: semverVersion, + }, nil +} + +// IsRelease returns true if it's a release version +func (s *SemanticVersion) IsRelease() bool { + // Limit to v1 + if s.Version.Major() != 1 { + return false + } + return len(s.Version.Prerelease()) == 0 && len(s.Version.Metadata()) == 0 +} + +// IsPreRelease returns true if it's a prerelease version +func (s *SemanticVersion) IsPreRelease() bool { + // Limit to v1 + if s.Version.Major() != 1 { + return false + } + return len(s.Version.Prerelease()) > 0 +} + +func (s *SemanticVersion) String() string { + return s.Version.String() +} + +// IsGreaterThan returns true if this version is greater than the given version +func (s *SemanticVersion) IsGreaterThan(version *SemanticVersion) (bool, error) { + // Set up new constraint + constraint, err := semver.NewConstraint("> " + version.Version.String()) + if err != nil { + return false, err + } + + // Check if the desired one is greater than the requested on + success, msgs := constraint.Validate(s.Version) + if !success { + return false, msgs[0] + } + return true, nil +} + +// IsGreaterThanOrEqual returns true if this version is greater than or equal the given version +func (s *SemanticVersion) IsGreaterThanOrEqual(version *SemanticVersion) (bool, error) { + // Set up new constraint + constraint, err := semver.NewConstraint(">= " + version.Version.String()) + if err != nil { + return false, err + } + + // Check if the desired one is greater than the requested on + success, msgs := constraint.Validate(s.Version) + if !success { + return false, msgs[0] + } + return true, nil +} + +// MainVersion returns the main version of any version+prerelease+metadata +// EG: MainVersion("1.2.3-pre") => "1.2.3" +func (s *SemanticVersion) MainVersion() *SemanticVersion { + mainVersion := fmt.Sprintf("%d.%d.%d", s.Version.Major(), s.Version.Minor(), s.Version.Patch()) + result, _ := NewSemanticVersion(mainVersion) + return result +} + +// SemverCollection is a collection of SemanticVersion objects +type SemverCollection []*SemanticVersion + +// Len returns the length of a collection. The number of Version instances +// on the slice. +func (c SemverCollection) Len() int { + return len(c) +} + +// Less is needed for the sort interface to compare two Version objects on the +// slice. If checks if one is less than the other. +func (c SemverCollection) Less(i, j int) bool { + return c[i].Version.LessThan(c[j].Version) +} + +// Swap is needed for the sort interface to replace the Version objects +// at two different positions in the slice. +func (c SemverCollection) Swap(i, j int) { + c[i], c[j] = c[j], c[i] +} diff --git a/cmd/semver_test.go b/cmd/semver_test.go new file mode 100644 index 000000000..54261b6f7 --- /dev/null +++ b/cmd/semver_test.go @@ -0,0 +1,65 @@ +package cmd + +import ( + "testing" +) + +func TestSemanticVersion_IsPreRelease(t *testing.T) { + tests := []struct { + name string + version string + want bool + }{ + {"v1.6.7-pre0", "v1.6.7-pre0", true}, + {"v2.6.7+pre0", "v2.6.7+pre0", false}, + {"v2.6.7", "v2.6.7", false}, + {"v2.0.0+alpha.1", "v2.0.0+alpha.1", false}, + {"v2.0.0-alpha.1", "v2.0.0-alpha.1", false}, + {"v1.6.7", "v1.6.7", false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + semanticversion, err := NewSemanticVersion(tt.version) + if err != nil { + t.Errorf("Invalid semantic version: %s", semanticversion) + return + } + s := &SemanticVersion{ + Version: semanticversion.Version, + } + if got := s.IsPreRelease(); got != tt.want { + t.Errorf("IsPreRelease() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestSemanticVersion_IsRelease(t *testing.T) { + tests := []struct { + name string + version string + want bool + }{ + {"v1.6.7", "v1.6.7", true}, + {"v2.6.7-pre0", "v2.6.7-pre0", false}, + {"v2.6.7", "v2.6.7", false}, + {"v2.6.7+release", "v2.6.7+release", false}, + {"v2.0.0-alpha.1", "v2.0.0-alpha.1", false}, + {"v1.6.7-pre0", "v1.6.7-pre0", false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + semanticversion, err := NewSemanticVersion(tt.version) + if err != nil { + t.Errorf("Invalid semantic version: %s", semanticversion) + return + } + s := &SemanticVersion{ + Version: semanticversion.Version, + } + if got := s.IsRelease(); got != tt.want { + t.Errorf("IsRelease() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/cmd/shell.go b/cmd/shell.go new file mode 100644 index 000000000..53c227de0 --- /dev/null +++ b/cmd/shell.go @@ -0,0 +1,61 @@ +package cmd + +import ( + "bytes" + "os" + "os/exec" +) + +// ShellHelper helps with Shell commands +type ShellHelper struct { + verbose bool +} + +// NewShellHelper creates a new ShellHelper! +func NewShellHelper() *ShellHelper { + return &ShellHelper{} +} + +// SetVerbose sets the verbose flag +func (sh *ShellHelper) SetVerbose() { + sh.verbose = true +} + +// Run the given command +func (sh *ShellHelper) Run(command string, vars ...string) (stdout, stderr string, err error) { + cmd := exec.Command(command, vars...) + cmd.Env = append(os.Environ(), "GO111MODULE=on") + if !sh.verbose { + var stdo, stde bytes.Buffer + cmd.Stdout = &stdo + cmd.Stderr = &stde + err = cmd.Run() + stdout = string(stdo.Bytes()) + stderr = string(stde.Bytes()) + } else { + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + err = cmd.Run() + } + return +} + +// RunInDirectory runs the given command in the given directory +func (sh *ShellHelper) RunInDirectory(dir string, command string, vars ...string) (stdout, stderr string, err error) { + cmd := exec.Command(command, vars...) + cmd.Dir = dir + cmd.Env = append(os.Environ(), "GO111MODULE=on") + if !sh.verbose { + var stdo, stde bytes.Buffer + cmd.Stdout = &stdo + cmd.Stderr = &stde + err = cmd.Run() + stdout = string(stdo.Bytes()) + stderr = string(stde.Bytes()) + } else { + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + err = cmd.Run() + } + return +} diff --git a/cmd/system.go b/cmd/system.go new file mode 100644 index 000000000..49e4f760f --- /dev/null +++ b/cmd/system.go @@ -0,0 +1,318 @@ +package cmd + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "log" + "os" + "path/filepath" + "runtime" + "strconv" + "time" +) + +// SystemHelper - Defines everything related to the system +type SystemHelper struct { + log *Logger + fs *FSHelper + configFilename string + homeDir string + wailsSystemDir string + wailsSystemConfig string +} + +// NewSystemHelper - Creates a new System Helper +func NewSystemHelper() *SystemHelper { + result := &SystemHelper{ + fs: NewFSHelper(), + log: NewLogger(), + configFilename: "wails.json", + } + result.setSystemDirs() + return result +} + +// Internal +// setSystemDirs calculates the system directories it is interested in +func (s *SystemHelper) setSystemDirs() { + var err error + s.homeDir, err = os.UserHomeDir() + if err != nil { + log.Fatal("Cannot find home directory! Please file a bug report!") + } + + // TODO: A better config system + s.wailsSystemDir = filepath.Join(s.homeDir, ".wails") + s.wailsSystemConfig = filepath.Join(s.wailsSystemDir, s.configFilename) +} + +// ConfigFileExists - Returns true if it does! +func (s *SystemHelper) ConfigFileExists() bool { + return s.fs.FileExists(s.wailsSystemConfig) +} + +// SystemDirExists - Returns true if it does! +func (s *SystemHelper) systemDirExists() bool { + return s.fs.DirExists(s.wailsSystemDir) +} + +// LoadConfig attempts to load the Wails system config +func (s *SystemHelper) LoadConfig() (*SystemConfig, error) { + return NewSystemConfig(s.wailsSystemConfig) +} + +// ConfigFileIsValid checks if the config file is valid +func (s *SystemHelper) ConfigFileIsValid() bool { + _, err := NewSystemConfig(s.wailsSystemConfig) + return err == nil +} + +// GetAuthor returns a formatted string of the user's name and email +func (s *SystemHelper) GetAuthor() (string, error) { + var config *SystemConfig + config, err := s.LoadConfig() + if err != nil { + return "", err + } + + return fmt.Sprintf("%s <%s>", config.Name, config.Email), nil +} + +// BackupConfig attempts to backup the system config file +func (s *SystemHelper) BackupConfig() (string, error) { + now := strconv.FormatInt(time.Now().UTC().UnixNano(), 10) + backupFilename := s.wailsSystemConfig + "." + now + err := s.fs.CopyFile(s.wailsSystemConfig, backupFilename) + if err != nil { + return "", err + } + return backupFilename, nil +} + +func (s *SystemHelper) setup() error { + + systemConfig := make(map[string]string) + + // Try to load current values - ignore errors + config, _ := s.LoadConfig() + + if config.Name != "" { + systemConfig["name"] = PromptRequired("What is your name", config.Name) + } else if n, err := getGitConfigValue("user.name"); err == nil && n != "" { + systemConfig["name"] = PromptRequired("What is your name", n) + } else { + systemConfig["name"] = PromptRequired("What is your name") + } + + if config.Email != "" { + systemConfig["email"] = PromptRequired("What is your email address", config.Email) + } else if e, err := getGitConfigValue("user.email"); err == nil && e != "" { + systemConfig["email"] = PromptRequired("What is your email address", e) + } else { + systemConfig["email"] = PromptRequired("What is your email address") + } + + // Create the directory + err := s.fs.MkDirs(s.wailsSystemDir) + if err != nil { + return err + } + + // Save + configData, err := json.Marshal(&systemConfig) + if err != nil { + return err + } + err = ioutil.WriteFile(s.wailsSystemConfig, configData, 0755) + if err != nil { + return err + } + fmt.Println() + s.log.White("Wails config saved to: " + s.wailsSystemConfig) + s.log.White("Feel free to customise these settings.") + fmt.Println() + + return nil +} + +const introText = ` +Wails is a lightweight framework for creating web-like desktop apps in Go. +I'll need to ask you a few questions so I can fill in your project templates and then I will try and see if you have the correct dependencies installed. If you don't have the right tools installed, I'll try and suggest how to install them. +` + +// CheckInitialised checks if the system has been set up +// and if not, runs setup +func (s *SystemHelper) CheckInitialised() error { + if !s.systemDirExists() { + s.log.Yellow("System not initialised. Running setup.") + return s.setup() + } + return nil +} + +// Initialise attempts to set up the Wails system. +// An error is returns if there is a problem +func (s *SystemHelper) Initialise() error { + + // System dir doesn't exist + if !s.systemDirExists() { + s.log.Green("Welcome to Wails!") + s.log.Green(introText) + return s.setup() + } + + // Config doesn't exist + if !s.ConfigFileExists() { + s.log.Green("Looks like the system config is missing.") + s.log.Green("To get you back on track, I'll need to ask you a few things...") + return s.setup() + } + + // Config exists but isn't valid. + if !s.ConfigFileIsValid() { + s.log.Green("Looks like the system config got corrupted.") + backupFile, err := s.BackupConfig() + if err != nil { + s.log.Green("I tried to backup your config file but got this error: %s", err.Error()) + } else { + s.log.Green("Just in case you needed it, I backed up your config file here: %s", backupFile) + } + s.log.Green("To get you back on track, I'll need to ask you a few things...") + return s.setup() + } + + return s.setup() +} + +// SystemConfig - Defines system wide configuration data +type SystemConfig struct { + Name string `json:"name"` + Email string `json:"email"` +} + +// NewSystemConfig - Creates a new SystemConfig helper object +func NewSystemConfig(filename string) (*SystemConfig, error) { + result := &SystemConfig{} + err := result.load(filename) + return result, err +} + +// Save - Saves the system config to the given filename +func (sc *SystemConfig) Save(filename string) error { + // Convert config to JSON string + theJSON, err := json.MarshalIndent(sc, "", " ") + if err != nil { + return err + } + + // Write it out to the config file + return ioutil.WriteFile(filename, theJSON, 0644) +} + +func (sc *SystemConfig) load(filename string) error { + configData, err := ioutil.ReadFile(filename) + if err != nil { + return err + } + // Load and unmarshall! + err = json.Unmarshal(configData, &sc) + if err != nil { + return err + } + return nil +} + +// CheckDependenciesSilent checks for dependencies but +// only outputs if there's an error +func CheckDependenciesSilent(logger *Logger) (bool, error) { + logger.SetErrorOnly(true) + result, err := CheckDependencies(logger) + logger.SetErrorOnly(false) + return result, err +} + +// CheckDependencies will look for Wails dependencies on the system +// Errors are reported in error and the bool return value is whether +// the dependencies are all installed. +func CheckDependencies(logger *Logger) (bool, error) { + + switch runtime.GOOS { + case "darwin": + logger.Yellow("Detected Platform: OSX") + case "windows": + logger.Yellow("Detected Platform: Windows") + case "linux": + logger.Yellow("Detected Platform: Linux") + default: + return false, fmt.Errorf("Platform %s is currently not supported", runtime.GOOS) + } + + logger.Yellow("Checking for prerequisites...") + // Check we have a cgo capable environment + + requiredPrograms, err := GetRequiredPrograms() + if err != nil { + return false, nil + } + errors := false + programHelper := NewProgramHelper() + for _, program := range *requiredPrograms { + bin := programHelper.FindProgram(program.Name) + if bin == nil { + errors = true + logger.Error("Program '%s' not found. %s", program.Name, program.Help) + } else { + logger.Green("Program '%s' found: %s", program.Name, bin.Path) + } + } + + // Linux has library deps + if runtime.GOOS == "linux" { + // Check library prerequisites + requiredLibraries, err := GetRequiredLibraries() + if err != nil { + return false, err + } + + var libraryChecker CheckPkgInstalled + distroInfo := GetLinuxDistroInfo() + + switch distroInfo.Distribution { + case Ubuntu, Debian, Zorin, Parrot, Linuxmint, Elementary, Kali, Neon, Deepin, Raspbian, PopOS: + libraryChecker = DpkgInstalled + case Arch, ArcoLinux, ArchLabs, Ctlos, Manjaro, ManjaroARM, EndeavourOS, ArtixLinux: + libraryChecker = PacmanInstalled + case CentOS, Fedora, Tumbleweed, Leap, RHEL: + libraryChecker = RpmInstalled + case Gentoo: + libraryChecker = EqueryInstalled + case VoidLinux: + libraryChecker = XbpsInstalled + case Solus: + libraryChecker = EOpkgInstalled + case Crux: + libraryChecker = PrtGetInstalled + case NixOS: + libraryChecker = NixEnvInstalled + default: + return false, RequestSupportForDistribution(distroInfo) + } + + for _, library := range *requiredLibraries { + installed, err := libraryChecker(library.Name) + if err != nil { + return false, err + } + if !installed { + errors = true + logger.Error("Library '%s' not found. %s", library.Name, library.Help) + } else { + logger.Green("Library '%s' installed.", library.Name) + } + } + } + logger.White("") + + return !errors, err +} diff --git a/cmd/templates.go b/cmd/templates.go new file mode 100644 index 000000000..fe1c68d24 --- /dev/null +++ b/cmd/templates.go @@ -0,0 +1,270 @@ +package cmd + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "path/filepath" + "runtime" + "strings" + "text/template" + + "github.com/kennygrant/sanitize" + "github.com/leaanthony/slicer" +) + +// TemplateMetadata holds all the metadata for a Wails template +type TemplateMetadata struct { + Name string `json:"name"` + Version string `json:"version"` + ShortDescription string `json:"shortdescription"` + Description string `json:"description"` + Install string `json:"install"` + Build string `json:"build"` + Author string `json:"author"` + Created string `json:"created"` + FrontendDir string `json:"frontenddir"` + Serve string `json:"serve"` + Bridge string `json:"bridge"` + WailsDir string `json:"wailsdir"` + TemplateDependencies []*TemplateDependency `json:"dependencies,omitempty"` + + // List of platforms that this template is supported on. + // No value means all platforms. A platform name is the same string + // as `runtime.GOOS` will return, eg: "darwin". NOTE: This is + // case sensitive. + Platforms []string `json:"platforms,omitempty"` +} + +// PlatformSupported returns true if this template supports the +// currently running platform +func (m *TemplateMetadata) PlatformSupported() bool { + + // Default is all platforms supported + if len(m.Platforms) == 0 { + return true + } + + // Check that the platform is in the list + platformsSupported := slicer.String(m.Platforms) + return platformsSupported.Contains(runtime.GOOS) +} + +// TemplateDependency defines a binary dependency for the template +// EG: ng for angular +type TemplateDependency struct { + Bin string `json:"bin"` + Help string `json:"help"` +} + +// TemplateDetails holds information about a specific template +type TemplateDetails struct { + Name string + Path string + Metadata *TemplateMetadata + fs *FSHelper +} + +// TemplateHelper is a utility object to help with processing templates +type TemplateHelper struct { + templateDir *Dir + fs *FSHelper + metadataFilename string +} + +// NewTemplateHelper creates a new template helper +func NewTemplateHelper() *TemplateHelper { + + templateDir, err := fs.LocalDir("./templates") + if err != nil { + log.Fatal("Unable to find the template directory. Please reinstall Wails.") + } + + return &TemplateHelper{ + templateDir: templateDir, + metadataFilename: "template.json", + } +} + +// IsValidTemplate returns true if the given template name resides on disk +func (t *TemplateHelper) IsValidTemplate(templateName string) bool { + pathToTemplate := filepath.Join(t.templateDir.fullPath, templateName) + return t.fs.DirExists(pathToTemplate) +} + +// SanitizeFilename sanitizes the given string to make a valid filename +func (t *TemplateHelper) SanitizeFilename(name string) string { + return sanitize.Name(name) +} + +// CreateNewTemplate creates a new template based on the given directory name and string +func (t *TemplateHelper) CreateNewTemplate(dirname string, details *TemplateMetadata) (string, error) { + + // Check if this template has already been created + if t.IsValidTemplate(dirname) { + return "", fmt.Errorf("cannot create template in directory '%s' - already exists", dirname) + } + + targetDir := filepath.Join(t.templateDir.fullPath, dirname) + err := t.fs.MkDir(targetDir) + if err != nil { + return "", err + } + targetMetadata := filepath.Join(targetDir, t.metadataFilename) + err = t.fs.SaveAsJSON(details, targetMetadata) + + return targetDir, err +} + +// LoadMetadata loads the template's 'metadata.json' file +func (t *TemplateHelper) LoadMetadata(dir string) (*TemplateMetadata, error) { + templateFile := filepath.Join(dir, t.metadataFilename) + result := &TemplateMetadata{} + if !t.fs.FileExists(templateFile) { + return nil, nil + } + rawJSON, err := ioutil.ReadFile(templateFile) + if err != nil { + return nil, err + } + err = json.Unmarshal(rawJSON, &result) + return result, err +} + +// GetTemplateDetails returns a map of Template structs containing details +// of the found templates +func (t *TemplateHelper) GetTemplateDetails() (map[string]*TemplateDetails, error) { + + // Get the subdirectory details + templateDirs, err := t.templateDir.GetSubdirs() + if err != nil { + return nil, err + } + + result := make(map[string]*TemplateDetails) + + for name, dir := range templateDirs { + result[name] = &TemplateDetails{ + Path: dir, + } + metadata, err := t.LoadMetadata(dir) + if err != nil { + return nil, err + } + + result[name].Metadata = metadata + if metadata.Name != "" { + result[name].Name = metadata.Name + } else { + // Ignore bad templates? + result[name] = nil + } + } + + return result, nil +} + +// GetTemplateFilenames returns all the filenames of the given template +func (t *TemplateHelper) GetTemplateFilenames(template *TemplateDetails) (*slicer.StringSlicer, error) { + + // Get the subdirectory details + templateDir, err := t.fs.Directory(template.Path) + if err != nil { + return nil, err + } + return templateDir.GetAllFilenames() +} + +// InstallTemplate installs the template given in the project options to the +// project path given +func (t *TemplateHelper) InstallTemplate(projectPath string, projectOptions *ProjectOptions) error { + + // Check dependencies before installing + dependencies := projectOptions.selectedTemplate.Metadata.TemplateDependencies + if dependencies != nil { + programHelper := NewProgramHelper() + logger := NewLogger() + errors := []string{} + for _, dep := range dependencies { + program := programHelper.FindProgram(dep.Bin) + if program == nil { + errors = append(errors, dep.Help) + } + } + if len(errors) > 0 { + mainError := "template dependencies not installed" + if len(errors) == 1 { + mainError = errors[0] + } else { + for _, error := range errors { + logger.Red(error) + } + } + return fmt.Errorf(mainError) + } + } + + // Get template files + templateFilenames, err := t.GetTemplateFilenames(projectOptions.selectedTemplate) + if err != nil { + return err + } + + templatePath := projectOptions.selectedTemplate.Path + + // Save the version + projectOptions.WailsVersion = Version + + templateJSONFilename := filepath.Join(templatePath, t.metadataFilename) + + templateFiles := templateFilenames.Filter(func(filename string) bool { + filename = filepath.FromSlash(filename) + return strings.HasPrefix(filename, templatePath) && filename != templateJSONFilename + }) + + templateFiles.Each(func(templateFile string) { + + // Setup filenames + relativeFilename := strings.TrimPrefix(templateFile, templatePath)[1:] + targetFilename, err := filepath.Abs(filepath.Join(projectOptions.OutputDirectory, relativeFilename)) + if err != nil { + return + } + filedata, err := t.fs.LoadAsBytes(templateFile) + if err != nil { + return + } + + // If file is a template, process it + if strings.HasSuffix(templateFile, ".template") { + templateData := string(filedata) + tmpl := template.New(templateFile) + tmpl.Parse(templateData) + var tpl bytes.Buffer + err = tmpl.Execute(&tpl, projectOptions) + if err != nil { + return + } + + // Remove template suffix + targetFilename = strings.TrimSuffix(targetFilename, ".template") + + // Set the filedata to the template result + filedata = tpl.Bytes() + } + + // Normal file, just copy it + err = fs.CreateFile(targetFilename, filedata) + if err != nil { + return + } + }) + + if err != nil { + return err + } + + return nil +} diff --git a/cmd/templates/angular-template/frontend/.editorconfig b/cmd/templates/angular-template/frontend/.editorconfig new file mode 100644 index 000000000..e89330a61 --- /dev/null +++ b/cmd/templates/angular-template/frontend/.editorconfig @@ -0,0 +1,13 @@ +# Editor configuration, see https://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +max_line_length = off +trim_trailing_whitespace = false diff --git a/cmd/templates/angular-template/frontend/.gitignore b/cmd/templates/angular-template/frontend/.gitignore new file mode 100644 index 000000000..2d5d82ccd --- /dev/null +++ b/cmd/templates/angular-template/frontend/.gitignore @@ -0,0 +1,47 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# compiled output +/dist +/tmp +/out-tsc +# Only exists if Bazel was run +/bazel-out + +# dependencies +/node_modules + +# profiling files +chrome-profiler-events.json +speed-measure-plugin.json + +# IDEs and editors +/.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history/* + +# misc +/.sass-cache +/connect.lock +/coverage +/libpeerconnection.log +npm-debug.log +yarn-error.log +testem.log +/typings + +# System Files +.DS_Store +Thumbs.db +.editorcinfig diff --git a/cmd/templates/angular-template/frontend/README.md b/cmd/templates/angular-template/frontend/README.md new file mode 100644 index 000000000..f5aa03f4c --- /dev/null +++ b/cmd/templates/angular-template/frontend/README.md @@ -0,0 +1,27 @@ +# MyApp + +This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.0.3. + +## Development server + +Run `npx ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. + +## Code scaffolding + +Run `npx ng generate component component-name` to generate a new component. You can also use `npx ng generate directive|pipe|service|class|guard|interface|enum|module`. + +## Build + +Run `npx ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. + +## Running unit tests + +Run `npx ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). + +## Running end-to-end tests + +Run `npx ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). + +## Further help + +To get more help on the Angular CLI use `npx ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). diff --git a/cmd/templates/angular-template/frontend/angular.json b/cmd/templates/angular-template/frontend/angular.json new file mode 100644 index 000000000..73d12e71f --- /dev/null +++ b/cmd/templates/angular-template/frontend/angular.json @@ -0,0 +1,121 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "my-app": { + "projectType": "application", + "schematics": {}, + "root": "", + "sourceRoot": "src", + "prefix": "app", + "architect": { + "build": { + "builder": "ngx-build-plus:browser", + "options": { + "outputPath": "dist/my-app", + "index": "src/index.html", + "main": "src/main.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "tsconfig.app.json", + "aot": false, + "assets": [ + "src/favicon.ico", + "src/assets" + ], + "styles": [ + "src/styles.css" + ], + "scripts": [] + }, + "configurations": { + "production": { + "fileReplacements": [ + { + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.prod.ts" + } + ], + "optimization": true, + "outputHashing": "all", + "sourceMap": false, + "extractCss": true, + "namedChunks": false, + "aot": true, + "extractLicenses": true, + "vendorChunk": false, + "buildOptimizer": true, + "budgets": [ + { + "type": "initial", + "maximumWarning": "2mb", + "maximumError": "5mb" + } + ] + } + } + }, + "serve": { + "builder": "ngx-build-plus:dev-server", + "options": { + "browserTarget": "my-app:build" + }, + "configurations": { + "production": { + "browserTarget": "my-app:build:production" + } + } + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "my-app:build" + } + }, + "test": { + "builder": "ngx-build-plus:karma", + "options": { + "main": "src/test.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "tsconfig.spec.json", + "karmaConfig": "karma.conf.js", + "assets": [ + "src/favicon.ico", + "src/assets" + ], + "styles": [ + "src/styles.css" + ], + "scripts": [] + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "tsconfig.app.json", + "tsconfig.spec.json", + "e2e/tsconfig.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + }, + "e2e": { + "builder": "@angular-devkit/build-angular:protractor", + "options": { + "protractorConfig": "e2e/protractor.conf.js", + "devServerTarget": "my-app:serve" + }, + "configurations": { + "production": { + "devServerTarget": "my-app:serve:production" + } + } + } + } + } + }, + "defaultProject": "my-app" +} \ No newline at end of file diff --git a/cmd/templates/angular-template/frontend/browserslist b/cmd/templates/angular-template/frontend/browserslist new file mode 100644 index 000000000..3cb56d100 --- /dev/null +++ b/cmd/templates/angular-template/frontend/browserslist @@ -0,0 +1,12 @@ +# This file is used by the build system to adjust CSS and JS output to support the specified browsers below. +# For additional information regarding the format and rule options, please see: +# https://github.com/browserslist/browserslist#queries + +# You can see what browsers were selected by your queries by running: +# npx browserslist + +> 0.5% +last 2 versions +Firefox ESR +not dead +IE 9-11 # For IE 9-11 support, remove 'not'. diff --git a/cmd/templates/angular-template/frontend/e2e/protractor.conf.js b/cmd/templates/angular-template/frontend/e2e/protractor.conf.js new file mode 100644 index 000000000..73e4e6806 --- /dev/null +++ b/cmd/templates/angular-template/frontend/e2e/protractor.conf.js @@ -0,0 +1,32 @@ +// @ts-check +// Protractor configuration file, see link for more information +// https://github.com/angular/protractor/blob/master/lib/config.ts + +const { SpecReporter } = require('jasmine-spec-reporter'); + +/** + * @type { import("protractor").Config } + */ +exports.config = { + allScriptsTimeout: 11000, + specs: [ + './src/**/*.e2e-spec.ts' + ], + capabilities: { + 'browserName': 'chrome' + }, + directConnect: true, + baseUrl: 'http://localhost:4200/', + framework: 'jasmine', + jasmineNodeOpts: { + showColors: true, + defaultTimeoutInterval: 30000, + print: function() {} + }, + onPrepare() { + require('ts-node').register({ + project: require('path').join(__dirname, './tsconfig.json') + }); + jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); + } +}; \ No newline at end of file diff --git a/cmd/templates/angular-template/frontend/e2e/src/app.e2e-spec.ts b/cmd/templates/angular-template/frontend/e2e/src/app.e2e-spec.ts new file mode 100644 index 000000000..3b79f7c47 --- /dev/null +++ b/cmd/templates/angular-template/frontend/e2e/src/app.e2e-spec.ts @@ -0,0 +1,23 @@ +import { AppPage } from './app.po'; +import { browser, logging } from 'protractor'; + +describe('workspace-project App', () => { + let page: AppPage; + + beforeEach(() => { + page = new AppPage(); + }); + + it('should display welcome message', () => { + page.navigateTo(); + expect(page.getTitleText()).toEqual('Welcome to my-app!'); + }); + + afterEach(async () => { + // Assert that there are no errors emitted from the browser + const logs = await browser.manage().logs().get(logging.Type.BROWSER); + expect(logs).not.toContain(jasmine.objectContaining({ + level: logging.Level.SEVERE, + } as logging.Entry)); + }); +}); diff --git a/cmd/templates/angular-template/frontend/e2e/src/app.po.ts b/cmd/templates/angular-template/frontend/e2e/src/app.po.ts new file mode 100644 index 000000000..5776aa9eb --- /dev/null +++ b/cmd/templates/angular-template/frontend/e2e/src/app.po.ts @@ -0,0 +1,11 @@ +import { browser, by, element } from 'protractor'; + +export class AppPage { + navigateTo() { + return browser.get(browser.baseUrl) as Promise; + } + + getTitleText() { + return element(by.css('app-root h1')).getText() as Promise; + } +} diff --git a/cmd/templates/angular-template/frontend/e2e/tsconfig.json b/cmd/templates/angular-template/frontend/e2e/tsconfig.json new file mode 100644 index 000000000..39b800f78 --- /dev/null +++ b/cmd/templates/angular-template/frontend/e2e/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/e2e", + "module": "commonjs", + "target": "es5", + "types": [ + "jasmine", + "jasminewd2", + "node" + ] + } +} diff --git a/cmd/templates/angular-template/frontend/karma.conf.js b/cmd/templates/angular-template/frontend/karma.conf.js new file mode 100644 index 000000000..b0d5cbe01 --- /dev/null +++ b/cmd/templates/angular-template/frontend/karma.conf.js @@ -0,0 +1,32 @@ +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage-istanbul-reporter'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + coverageIstanbulReporter: { + dir: require('path').join(__dirname, './coverage/my-app'), + reports: ['html', 'lcovonly', 'text-summary'], + fixWebpackSourcePaths: true + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false, + restartOnFileChange: true + }); +}; diff --git a/cmd/templates/angular-template/frontend/package.json.template b/cmd/templates/angular-template/frontend/package.json.template new file mode 100644 index 000000000..ee5c0d053 --- /dev/null +++ b/cmd/templates/angular-template/frontend/package.json.template @@ -0,0 +1,52 @@ +{ + "name": "my-app", + "version": "0.0.0", + "scripts": { + "ng": "npx ng", + "serve": "npx ng serve --poll=2000 --host=0.0.0.0", + "build": "npx ng build --single-bundle true --output-hashing none --prod --bundle-styles false", + "test": "npx ng test", + "lint": "npx ng lint", + "e2e": "npx ng e2e" + }, + "private": true, + "dependencies": { + "@angular/animations": "^8.0.2", + "@angular/cdk": "^8.0.1", + "@angular/common": "~8.0.1", + "@angular/compiler": "~8.0.1", + "@angular/core": "~8.0.1", + "@angular/forms": "~8.0.1", + "@angular/material": "^8.0.1", + "@angular/platform-browser": "~8.0.1", + "@angular/platform-browser-dynamic": "~8.0.1", + "@angular/router": "~8.0.1", + "@wailsapp/runtime": "^1.0.0", + "core-js": "^3.4.4", + "ngx-build-plus": "^8.0.3", + "rxjs": "~6.4.0", + "tslib": "^1.9.0", + "zone.js": "~0.9.1" + }, + "devDependencies": { + "@angular-devkit/build-angular": "~0.800.0", + "@angular/cli": "~8.0.3", + "@angular/compiler-cli": "~8.0.1", + "@angular/language-service": "~8.0.1", + "@types/node": "~8.9.4", + "@types/jasmine": "~3.3.8", + "@types/jasminewd2": "~2.0.3", + "codelyzer": "^5.0.0", + "jasmine-core": "~3.4.0", + "jasmine-spec-reporter": "~4.2.1", + "karma": "~4.1.0", + "karma-chrome-launcher": "~2.2.0", + "karma-coverage-istanbul-reporter": "~2.0.1", + "karma-jasmine": "~2.0.1", + "karma-jasmine-html-reporter": "^1.4.0", + "protractor": "~5.4.0", + "ts-node": "~7.0.0", + "tslint": "~5.15.0", + "typescript": "~3.4.3" + } +} diff --git a/cmd/templates/angular-template/frontend/src/app/app-routing.module.ts b/cmd/templates/angular-template/frontend/src/app/app-routing.module.ts new file mode 100644 index 000000000..249a14a5c --- /dev/null +++ b/cmd/templates/angular-template/frontend/src/app/app-routing.module.ts @@ -0,0 +1,13 @@ +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; + +const routes: Routes = []; + +@NgModule({ + imports: [ + RouterModule.forRoot(routes,{useHash:true}) + ], + exports: [RouterModule] +}) + +export class AppRoutingModule { } diff --git a/v2/pkg/templates/generate/assets/common/frontend/dist/gitkeep b/cmd/templates/angular-template/frontend/src/app/app.component.css similarity index 100% rename from v2/pkg/templates/generate/assets/common/frontend/dist/gitkeep rename to cmd/templates/angular-template/frontend/src/app/app.component.css diff --git a/cmd/templates/angular-template/frontend/src/app/app.component.html b/cmd/templates/angular-template/frontend/src/app/app.component.html new file mode 100644 index 000000000..4a0437517 --- /dev/null +++ b/cmd/templates/angular-template/frontend/src/app/app.component.html @@ -0,0 +1,14 @@ + +
+

+ Welcome to {{ title }}! +

+ Angular Logo + +
+ +

{{clickMessage}}

+
+ + diff --git a/cmd/templates/angular-template/frontend/src/app/app.component.spec.ts b/cmd/templates/angular-template/frontend/src/app/app.component.spec.ts new file mode 100644 index 000000000..3fe58ce0f --- /dev/null +++ b/cmd/templates/angular-template/frontend/src/app/app.component.spec.ts @@ -0,0 +1,35 @@ +import { TestBed, async } from '@angular/core/testing'; +import { RouterTestingModule } from '@angular/router/testing'; +import { AppComponent } from './app.component'; + +describe('AppComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + RouterTestingModule + ], + declarations: [ + AppComponent + ], + }).compileComponents(); + })); + + it('should create the app', () => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.debugElement.componentInstance; + expect(app).toBeTruthy(); + }); + + it(`should have as title 'my-app'`, () => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.debugElement.componentInstance; + expect(app.title).toEqual('my-app'); + }); + + it('should render title in a h1 tag', () => { + const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); + const compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelector('h1').textContent).toContain('Welcome to my-app!'); + }); +}); diff --git a/cmd/templates/angular-template/frontend/src/app/app.component.ts b/cmd/templates/angular-template/frontend/src/app/app.component.ts new file mode 100644 index 000000000..e91b91686 --- /dev/null +++ b/cmd/templates/angular-template/frontend/src/app/app.component.ts @@ -0,0 +1,19 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: '[id="app"]', + templateUrl: './app.component.html', + styleUrls: ['./app.component.css'] +}) +export class AppComponent { + title = 'my-app'; + + clickMessage = ''; + + onClickMe() { + // @ts-ignore + window.backend.basic().then(result => + this.clickMessage = result + ); + } +} diff --git a/cmd/templates/angular-template/frontend/src/app/app.module.ts b/cmd/templates/angular-template/frontend/src/app/app.module.ts new file mode 100644 index 000000000..4c082cefe --- /dev/null +++ b/cmd/templates/angular-template/frontend/src/app/app.module.ts @@ -0,0 +1,20 @@ +import { BrowserModule } from '@angular/platform-browser'; +import { NgModule } from '@angular/core'; + +import { AppRoutingModule } from './app-routing.module'; +import { AppComponent } from './app.component'; + +import { APP_BASE_HREF } from '@angular/common'; + +@NgModule({ + declarations: [ + AppComponent + ], + imports: [ + BrowserModule, + AppRoutingModule + ], + providers: [{provide: APP_BASE_HREF, useValue : '/' }], + bootstrap: [AppComponent] +}) +export class AppModule { } diff --git a/v2/pkg/templates/generate/assets/preact/frontend/dist/gitkeep b/cmd/templates/angular-template/frontend/src/assets/.gitkeep similarity index 100% rename from v2/pkg/templates/generate/assets/preact/frontend/dist/gitkeep rename to cmd/templates/angular-template/frontend/src/assets/.gitkeep diff --git a/cmd/templates/angular-template/frontend/src/environments/environment.prod.ts b/cmd/templates/angular-template/frontend/src/environments/environment.prod.ts new file mode 100644 index 000000000..3612073bc --- /dev/null +++ b/cmd/templates/angular-template/frontend/src/environments/environment.prod.ts @@ -0,0 +1,3 @@ +export const environment = { + production: true +}; diff --git a/cmd/templates/angular-template/frontend/src/environments/environment.ts b/cmd/templates/angular-template/frontend/src/environments/environment.ts new file mode 100644 index 000000000..7b4f817ad --- /dev/null +++ b/cmd/templates/angular-template/frontend/src/environments/environment.ts @@ -0,0 +1,16 @@ +// This file can be replaced during build by using the `fileReplacements` array. +// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. +// The list of file replacements can be found in `angular.json`. + +export const environment = { + production: false +}; + +/* + * For easier debugging in development mode, you can import the following file + * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. + * + * This import should be commented out in production mode because it will have a negative impact + * on performance if an error is thrown. + */ +// import 'zone.js/dist/zone-error'; // Included with Angular CLI. diff --git a/cmd/templates/angular-template/frontend/src/favicon.ico b/cmd/templates/angular-template/frontend/src/favicon.ico new file mode 100644 index 000000000..8081c7cea Binary files /dev/null and b/cmd/templates/angular-template/frontend/src/favicon.ico differ diff --git a/cmd/templates/angular-template/frontend/src/index.html.template b/cmd/templates/angular-template/frontend/src/index.html.template new file mode 100644 index 000000000..df56c4116 --- /dev/null +++ b/cmd/templates/angular-template/frontend/src/index.html.template @@ -0,0 +1,14 @@ + + + + +my-app + + + + + + +
+ + diff --git a/cmd/templates/angular-template/frontend/src/main.ts b/cmd/templates/angular-template/frontend/src/main.ts new file mode 100644 index 000000000..49f44bfbd --- /dev/null +++ b/cmd/templates/angular-template/frontend/src/main.ts @@ -0,0 +1,19 @@ +import 'core-js/stable'; +import { enableProdMode } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; +import { environment } from './environments/environment'; + +import 'zone.js' + +import * as Wails from '@wailsapp/runtime'; + +if (environment.production) { + enableProdMode(); +} + +Wails.Init(() => { + platformBrowserDynamic().bootstrapModule(AppModule) + .catch(err => console.error(err)); +}); diff --git a/cmd/templates/angular-template/frontend/src/polyfills.ts b/cmd/templates/angular-template/frontend/src/polyfills.ts new file mode 100644 index 000000000..22a5df87d --- /dev/null +++ b/cmd/templates/angular-template/frontend/src/polyfills.ts @@ -0,0 +1,63 @@ +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), + * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. + * + * Learn more in https://angular.io/guide/browser-support + */ + +/*************************************************************************************************** + * BROWSER POLYFILLS + */ + +/** IE10 and IE11 requires the following for NgClass support on SVG elements */ +// import 'classlist.js'; // Run `npm install --save classlist.js`. + +/** + * Web Animations `@angular/platform-browser/animations` + * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. + * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). + */ +// import 'web-animations-js'; // Run `npm install --save web-animations-js`. + +/** + * By default, zone.js will patch all possible macroTask and DomEvents + * user can disable parts of macroTask/DomEvents patch by setting following flags + * because those flags need to be set before `zone.js` being loaded, and webpack + * will put import in the top of bundle, so user need to create a separate file + * in this directory (for example: zone-flags.ts), and put the following flags + * into that file, and then add the following code before importing zone.js. + * import './zone-flags.ts'; + * + * The flags allowed in zone-flags.ts are listed here. + * + * The following flags will work for all browsers. + * + * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame + * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick + * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames + * + * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js + * with the following flag, it will bypass `zone.js` patch for IE/Edge + * + * (window as any).__Zone_enable_cross_context_check = true; + * + */ + +/*************************************************************************************************** + * Zone JS is required by default for Angular itself. + */ +//import 'zone.js/dist/zone'; // Included with Angular CLI. + + +/*************************************************************************************************** + * APPLICATION IMPORTS + */ diff --git a/cmd/templates/angular-template/frontend/src/styles.css b/cmd/templates/angular-template/frontend/src/styles.css new file mode 100644 index 000000000..4cf0ed8d1 --- /dev/null +++ b/cmd/templates/angular-template/frontend/src/styles.css @@ -0,0 +1,24 @@ +/* You can add global styles to this file, and also import other style files */ +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", + "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + + background-color: #282c34; +} + +p { + color: white +} + +h1 { + color: white +} + +button { + background-color: white; + color: black; +} diff --git a/cmd/templates/angular-template/frontend/src/test.ts b/cmd/templates/angular-template/frontend/src/test.ts new file mode 100644 index 000000000..16317897b --- /dev/null +++ b/cmd/templates/angular-template/frontend/src/test.ts @@ -0,0 +1,20 @@ +// This file is required by karma.conf.js and loads recursively all the .spec and framework files + +import 'zone.js/dist/zone-testing'; +import { getTestBed } from '@angular/core/testing'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting +} from '@angular/platform-browser-dynamic/testing'; + +declare const require: any; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment( + BrowserDynamicTestingModule, + platformBrowserDynamicTesting() +); +// Then we find all the tests. +const context = require.context('./', true, /\.spec\.ts$/); +// And load the modules. +context.keys().map(context); diff --git a/cmd/templates/angular-template/frontend/tsconfig.app.json b/cmd/templates/angular-template/frontend/tsconfig.app.json new file mode 100644 index 000000000..31f8397ac --- /dev/null +++ b/cmd/templates/angular-template/frontend/tsconfig.app.json @@ -0,0 +1,14 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/app", + "types": [] + }, + "include": [ + "src/**/*.ts" + ], + "exclude": [ + "src/test.ts", + "src/**/*.spec.ts" + ] +} diff --git a/cmd/templates/angular-template/frontend/tsconfig.json b/cmd/templates/angular-template/frontend/tsconfig.json new file mode 100644 index 000000000..16195ad5f --- /dev/null +++ b/cmd/templates/angular-template/frontend/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "baseUrl": "./", + "outDir": "./dist/out-tsc", + "sourceMap": true, + "declaration": false, + "downlevelIteration": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "module": "esnext", + "moduleResolution": "node", + "importHelpers": true, + "target": "es5", + "typeRoots": [ + "node_modules/@types" + ], + "lib": [ + "es2018", + "dom" + ] + } +} \ No newline at end of file diff --git a/cmd/templates/angular-template/frontend/tsconfig.spec.json b/cmd/templates/angular-template/frontend/tsconfig.spec.json new file mode 100644 index 000000000..6400fde7d --- /dev/null +++ b/cmd/templates/angular-template/frontend/tsconfig.spec.json @@ -0,0 +1,18 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/spec", + "types": [ + "jasmine", + "node" + ] + }, + "files": [ + "src/test.ts", + "src/polyfills.ts" + ], + "include": [ + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} diff --git a/cmd/templates/angular-template/frontend/tslint.json b/cmd/templates/angular-template/frontend/tslint.json new file mode 100644 index 000000000..188bd78d3 --- /dev/null +++ b/cmd/templates/angular-template/frontend/tslint.json @@ -0,0 +1,92 @@ +{ + "extends": "tslint:recommended", + "rules": { + "array-type": false, + "arrow-parens": false, + "deprecation": { + "severity": "warn" + }, + "component-class-suffix": true, + "contextual-lifecycle": true, + "directive-class-suffix": true, + "directive-selector": [ + true, + "attribute", + "app", + "camelCase" + ], + "component-selector": [ + true, + "element", + "app", + "kebab-case" + ], + "import-blacklist": [ + true, + "rxjs/Rx" + ], + "interface-name": false, + "max-classes-per-file": false, + "max-line-length": [ + true, + 140 + ], + "member-access": false, + "member-ordering": [ + true, + { + "order": [ + "static-field", + "instance-field", + "static-method", + "instance-method" + ] + } + ], + "no-consecutive-blank-lines": false, + "no-console": [ + true, + "debug", + "info", + "time", + "timeEnd", + "trace" + ], + "no-empty": false, + "no-inferrable-types": [ + true, + "ignore-params" + ], + "no-non-null-assertion": true, + "no-redundant-jsdoc": true, + "no-switch-case-fall-through": true, + "no-use-before-declare": true, + "no-var-requires": false, + "object-literal-key-quotes": [ + true, + "as-needed" + ], + "object-literal-sort-keys": false, + "ordered-imports": false, + "quotemark": [ + true, + "single" + ], + "trailing-comma": false, + "no-conflicting-lifecycle": true, + "no-host-metadata-property": true, + "no-input-rename": true, + "no-inputs-metadata-property": true, + "no-output-native": true, + "no-output-on-prefix": true, + "no-output-rename": true, + "no-outputs-metadata-property": true, + "template-banana-in-box": true, + "template-no-negated-async": true, + "use-lifecycle-interface": true, + "use-pipe-transform-interface": true + }, + "rulesDirectory": [ + "codelyzer" + ] +} \ No newline at end of file diff --git a/cmd/templates/angular-template/go.mod.template b/cmd/templates/angular-template/go.mod.template new file mode 100644 index 000000000..780381065 --- /dev/null +++ b/cmd/templates/angular-template/go.mod.template @@ -0,0 +1,5 @@ +module {{.BinaryName}} + +require ( + github.com/wailsapp/wails {{.WailsVersion}} +) \ No newline at end of file diff --git a/cmd/templates/angular-template/main.go.template b/cmd/templates/angular-template/main.go.template new file mode 100644 index 000000000..9f2ae4f3f --- /dev/null +++ b/cmd/templates/angular-template/main.go.template @@ -0,0 +1,30 @@ +package main + +import ( + _ "embed" + "github.com/wailsapp/wails" +) + +func basic() string { + return "World!" +} + +//go:embed frontend/dist/my-app/main.js +var js string + +//go:embed frontend/dist/my-app/styles.css +var css string + +func main() { + + app := wails.CreateApp(&wails.AppConfig{ + Width: 1024, + Height: 768, + Title: "{{.Name}}", + JS: js, + CSS: css, + Colour: "#131313", + }) + app.Bind(basic) + app.Run() +} diff --git a/cmd/templates/angular-template/template.json b/cmd/templates/angular-template/template.json new file mode 100644 index 000000000..c2b258328 --- /dev/null +++ b/cmd/templates/angular-template/template.json @@ -0,0 +1,20 @@ +{ + "name": "Angular", + "version": "1.0.0", + "shortdescription": "Angular 8 template (Requires node 10.8+)", + "description": "Angular projects w/ @angular/cli - Note: in order to reach the cli use npx like this: npx ng", + "dependencies": [ + { + "bin": "npx", + "help": "This template requires 'npx'. Please install with 'npm install -g npx'" + } + ], + "install": "npm install", + "build": "npx ng build --single-bundle true --output-hashing none --prod --bundle-styles false", + "author": "bh90210 ", + "created": "2019-06-15 18:23:48.666414555 +0300 EEST m=+223.934866008", + "frontenddir": "frontend", + "serve": "npm run serve", + "bridge": "src", + "wailsdir": "" +} \ No newline at end of file diff --git a/cmd/templates/create-react-app/.jshint b/cmd/templates/create-react-app/.jshint new file mode 100644 index 000000000..0557edf11 --- /dev/null +++ b/cmd/templates/create-react-app/.jshint @@ -0,0 +1,3 @@ +{ + "esversion": 6 +} \ No newline at end of file diff --git a/cmd/templates/create-react-app/frontend/.gitignore b/cmd/templates/create-react-app/frontend/.gitignore new file mode 100644 index 000000000..4d29575de --- /dev/null +++ b/cmd/templates/create-react-app/frontend/.gitignore @@ -0,0 +1,23 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/cmd/templates/create-react-app/frontend/README.md b/cmd/templates/create-react-app/frontend/README.md new file mode 100644 index 000000000..9d9614c4f --- /dev/null +++ b/cmd/templates/create-react-app/frontend/README.md @@ -0,0 +1,68 @@ +This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). + +## Available Scripts + +In the project directory, you can run: + +### `npm start` + +Runs the app in the development mode.
+Open [http://localhost:3000](http://localhost:3000) to view it in the browser. + +The page will reload if you make edits.
+You will also see any lint errors in the console. + +### `npm test` + +Launches the test runner in the interactive watch mode.
+See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. + +### `npm run build` + +Builds the app for production to the `build` folder.
+It correctly bundles React in production mode and optimizes the build for the best performance. + +The build is minified and the filenames include the hashes.
+Your app is ready to be deployed! + +See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. + +### `npm run eject` + +**Note: this is a one-way operation. Once you `eject`, you can’t go back!** + +If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. + +Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. + +You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. + +## Learn More + +You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). + +To learn React, check out the [React documentation](https://reactjs.org/). + +### Code Splitting + +This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting + +### Analyzing the Bundle Size + +This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size + +### Making a Progressive Web App + +This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app + +### Advanced Configuration + +This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration + +### Deployment + +This section has moved here: https://facebook.github.io/create-react-app/docs/deployment + +### `npm run build` fails to minify + +This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify diff --git a/cmd/templates/create-react-app/frontend/package.json.template b/cmd/templates/create-react-app/frontend/package.json.template new file mode 100644 index 000000000..a940d3d17 --- /dev/null +++ b/cmd/templates/create-react-app/frontend/package.json.template @@ -0,0 +1,35 @@ +{ + "name": "{{.NPMProjectName}}", + "author": "{{.Author.Name}}<{{.Author.Email}}>", + "version": "0.1.0", + "private": true, + "dependencies": { + "core-js": "^3.6.4", + "react": "^16.13.1", + "react-dom": "^16.13.1", + "wails-react-scripts": "3.0.1-2", + "react-modal": "3.11.2", + "@wailsapp/runtime": "^1.0.10" + }, + "scripts": { + "serve": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject" + }, + "eslintConfig": { + "extends": "react-app" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} diff --git a/cmd/templates/create-react-app/frontend/public/favicon.ico b/cmd/templates/create-react-app/frontend/public/favicon.ico new file mode 100644 index 000000000..bcd5dfd67 Binary files /dev/null and b/cmd/templates/create-react-app/frontend/public/favicon.ico differ diff --git a/cmd/templates/create-react-app/frontend/public/index.html b/cmd/templates/create-react-app/frontend/public/index.html new file mode 100644 index 000000000..4bf3c2570 --- /dev/null +++ b/cmd/templates/create-react-app/frontend/public/index.html @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + React App + + + + +
+ + + + \ No newline at end of file diff --git a/cmd/templates/create-react-app/frontend/public/logo192.png b/cmd/templates/create-react-app/frontend/public/logo192.png new file mode 100644 index 000000000..c11e5883f Binary files /dev/null and b/cmd/templates/create-react-app/frontend/public/logo192.png differ diff --git a/cmd/templates/create-react-app/frontend/public/logo512.png b/cmd/templates/create-react-app/frontend/public/logo512.png new file mode 100644 index 000000000..564d5c188 Binary files /dev/null and b/cmd/templates/create-react-app/frontend/public/logo512.png differ diff --git a/cmd/templates/create-react-app/frontend/public/manifest.json b/cmd/templates/create-react-app/frontend/public/manifest.json new file mode 100644 index 000000000..080d6c77a --- /dev/null +++ b/cmd/templates/create-react-app/frontend/public/manifest.json @@ -0,0 +1,25 @@ +{ + "short_name": "React App", + "name": "Create React App Sample", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + }, + { + "src": "logo192.png", + "type": "image/png", + "sizes": "192x192" + }, + { + "src": "logo512.png", + "type": "image/png", + "sizes": "512x512" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/cmd/templates/create-react-app/frontend/public/robots.txt b/cmd/templates/create-react-app/frontend/public/robots.txt new file mode 100644 index 000000000..e9e57dc4d --- /dev/null +++ b/cmd/templates/create-react-app/frontend/public/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: diff --git a/cmd/templates/create-react-app/frontend/src/App.css b/cmd/templates/create-react-app/frontend/src/App.css new file mode 100644 index 000000000..74b5e0534 --- /dev/null +++ b/cmd/templates/create-react-app/frontend/src/App.css @@ -0,0 +1,38 @@ +.App { + text-align: center; +} + +.App-logo { + height: 40vmin; + pointer-events: none; +} + +@media (prefers-reduced-motion: no-preference) { + .App-logo { + animation: App-logo-spin infinite 20s linear; + } +} + +.App-header { + background-color: #282c34; + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); + color: white; +} + +.App-link { + color: #61dafb; +} + +@keyframes App-logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} diff --git a/cmd/templates/create-react-app/frontend/src/App.js b/cmd/templates/create-react-app/frontend/src/App.js new file mode 100644 index 000000000..3c6bc564c --- /dev/null +++ b/cmd/templates/create-react-app/frontend/src/App.js @@ -0,0 +1,21 @@ +import React from 'react'; +import logo from './logo.png'; +import './App.css'; +import HelloWorld from './components/HelloWorld'; + +function App() { + return ( +
+
+ logo +

+ Welcome to your new wails/react project. +

+ + +
+
+ ); +} + +export default App; diff --git a/cmd/templates/create-react-app/frontend/src/App.test.js b/cmd/templates/create-react-app/frontend/src/App.test.js new file mode 100644 index 000000000..a754b201b --- /dev/null +++ b/cmd/templates/create-react-app/frontend/src/App.test.js @@ -0,0 +1,9 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App'; + +it('renders without crashing', () => { + const div = document.createElement('div'); + ReactDOM.render(, div); + ReactDOM.unmountComponentAtNode(div); +}); diff --git a/cmd/templates/create-react-app/frontend/src/components/HelloWorld.js b/cmd/templates/create-react-app/frontend/src/components/HelloWorld.js new file mode 100644 index 000000000..26be1aea1 --- /dev/null +++ b/cmd/templates/create-react-app/frontend/src/components/HelloWorld.js @@ -0,0 +1,35 @@ +import React, { useState } from 'react'; +import Modal from 'react-modal'; + +function HelloWorld() { + const [showModal, setShowModal] = useState(false); + const [result, setResult] = useState(null); + + const handleOpenModal = () => { + setShowModal(true); + + window.backend.basic().then((result) => setResult(result)); + }; + + const handleCloseModal = () => { + setShowModal(false); + }; + + return ( +
+ + +

{result}

+ +
+
+ ); +} + +export default HelloWorld; diff --git a/cmd/templates/create-react-app/frontend/src/index.css b/cmd/templates/create-react-app/frontend/src/index.css new file mode 100644 index 000000000..4a1df4db7 --- /dev/null +++ b/cmd/templates/create-react-app/frontend/src/index.css @@ -0,0 +1,13 @@ +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", + "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", + monospace; +} diff --git a/cmd/templates/create-react-app/frontend/src/index.js b/cmd/templates/create-react-app/frontend/src/index.js new file mode 100644 index 000000000..4e64f604e --- /dev/null +++ b/cmd/templates/create-react-app/frontend/src/index.js @@ -0,0 +1,22 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import 'core-js/stable'; +import './index.css'; +import App from './App'; +import * as serviceWorker from './serviceWorker'; + +import * as Wails from '@wailsapp/runtime'; + +Wails.Init(() => { + ReactDOM.render( + + + , + document.getElementById("app") + ); +}); + +// If you want your app to work offline and load faster, you can change +// unregister() to register() below. Note this comes with some pitfalls. +// Learn more about service workers: https://bit.ly/CRA-PWA +serviceWorker.unregister(); diff --git a/cmd/templates/create-react-app/frontend/src/logo.png b/cmd/templates/create-react-app/frontend/src/logo.png new file mode 100644 index 000000000..31fc8249c Binary files /dev/null and b/cmd/templates/create-react-app/frontend/src/logo.png differ diff --git a/cmd/templates/create-react-app/frontend/src/serviceWorker.js b/cmd/templates/create-react-app/frontend/src/serviceWorker.js new file mode 100644 index 000000000..f8c7e50c2 --- /dev/null +++ b/cmd/templates/create-react-app/frontend/src/serviceWorker.js @@ -0,0 +1,135 @@ +// This optional code is used to register a service worker. +// register() is not called by default. + +// This lets the app load faster on subsequent visits in production, and gives +// it offline capabilities. However, it also means that developers (and users) +// will only see deployed updates on subsequent visits to a page, after all the +// existing tabs open on the page have been closed, since previously cached +// resources are updated in the background. + +// To learn more about the benefits of this model and instructions on how to +// opt-in, read https://bit.ly/CRA-PWA + +const isLocalhost = Boolean( + window.location.hostname === 'localhost' || + // [::1] is the IPv6 localhost address. + window.location.hostname === '[::1]' || + // 127.0.0.1/8 is considered localhost for IPv4. + window.location.hostname.match( + /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ + ) +); + +export function register(config) { + if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { + // The URL constructor is available in all browsers that support SW. + const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); + if (publicUrl.origin !== window.location.origin) { + // Our service worker won't work if PUBLIC_URL is on a different origin + // from what our page is served on. This might happen if a CDN is used to + // serve assets; see https://github.com/facebook/create-react-app/issues/2374 + return; + } + + window.addEventListener('load', () => { + const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; + + if (isLocalhost) { + // This is running on localhost. Let's check if a service worker still exists or not. + checkValidServiceWorker(swUrl, config); + + // Add some additional logging to localhost, pointing developers to the + // service worker/PWA documentation. + navigator.serviceWorker.ready.then(() => { + console.log( + 'This web app is being served cache-first by a service ' + + 'worker. To learn more, visit https://bit.ly/CRA-PWA' + ); + }); + } else { + // Is not localhost. Just register service worker + registerValidSW(swUrl, config); + } + }); + } +} + +function registerValidSW(swUrl, config) { + navigator.serviceWorker + .register(swUrl) + .then(registration => { + registration.onupdatefound = () => { + const installingWorker = registration.installing; + if (installingWorker == null) { + return; + } + installingWorker.onstatechange = () => { + if (installingWorker.state === 'installed') { + if (navigator.serviceWorker.controller) { + // At this point, the updated precached content has been fetched, + // but the previous service worker will still serve the older + // content until all client tabs are closed. + console.log( + 'New content is available and will be used when all ' + + 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' + ); + + // Execute callback + if (config && config.onUpdate) { + config.onUpdate(registration); + } + } else { + // At this point, everything has been precached. + // It's the perfect time to display a + // "Content is cached for offline use." message. + console.log('Content is cached for offline use.'); + + // Execute callback + if (config && config.onSuccess) { + config.onSuccess(registration); + } + } + } + }; + }; + }) + .catch(error => { + console.error('Error during service worker registration:', error); + }); +} + +function checkValidServiceWorker(swUrl, config) { + // Check if the service worker can be found. If it can't reload the page. + fetch(swUrl) + .then(response => { + // Ensure service worker exists, and that we really are getting a JS file. + const contentType = response.headers.get('content-type'); + if ( + response.status === 404 || + (contentType != null && contentType.indexOf('javascript') === -1) + ) { + // No service worker found. Probably a different app. Reload the page. + navigator.serviceWorker.ready.then(registration => { + registration.unregister().then(() => { + window.location.reload(); + }); + }); + } else { + // Service worker found. Proceed as normal. + registerValidSW(swUrl, config); + } + }) + .catch(() => { + console.log( + 'No internet connection found. App is running in offline mode.' + ); + }); +} + +export function unregister() { + if ('serviceWorker' in navigator) { + navigator.serviceWorker.ready.then(registration => { + registration.unregister(); + }); + } +} diff --git a/cmd/templates/create-react-app/go.mod.template b/cmd/templates/create-react-app/go.mod.template new file mode 100644 index 000000000..780381065 --- /dev/null +++ b/cmd/templates/create-react-app/go.mod.template @@ -0,0 +1,5 @@ +module {{.BinaryName}} + +require ( + github.com/wailsapp/wails {{.WailsVersion}} +) \ No newline at end of file diff --git a/cmd/templates/create-react-app/main.go.template b/cmd/templates/create-react-app/main.go.template new file mode 100644 index 000000000..d6d1be03e --- /dev/null +++ b/cmd/templates/create-react-app/main.go.template @@ -0,0 +1,30 @@ +package main + +import ( + _ "embed" + "github.com/wailsapp/wails" +) + +func basic() string { + return "World!" +} + +//go:embed frontend/build/static/js/main.js +var js string + +//go:embed frontend/build/static/css/main.css +var css string + +func main() { + + app := wails.CreateApp(&wails.AppConfig{ + Width: 1024, + Height: 768, + Title: "{{.Name}}", + JS: js, + CSS: css, + Colour: "#131313", + }) + app.Bind(basic) + app.Run() +} diff --git a/cmd/templates/create-react-app/template.json b/cmd/templates/create-react-app/template.json new file mode 100755 index 000000000..ea6acbed2 --- /dev/null +++ b/cmd/templates/create-react-app/template.json @@ -0,0 +1,14 @@ +{ + "name": "React JS", + "version": "1.0.0", + "shortdescription": "Create React App v4 template", + "description": "Create React App v4 standard tooling", + "install": "npm install", + "build": "npm run build", + "author": "bh90210 ", + "created": "2019-06-07 18:23:48.666414555 +0300 EEST m=+223.934866008", + "frontenddir": "frontend", + "serve": "npm run serve", + "bridge": "src", + "wailsdir": "" +} diff --git a/cmd/templates/svelte/frontend/.gitignore b/cmd/templates/svelte/frontend/.gitignore new file mode 100644 index 000000000..da93220bc --- /dev/null +++ b/cmd/templates/svelte/frontend/.gitignore @@ -0,0 +1,4 @@ +/node_modules/ +/public/build/ + +.DS_Store diff --git a/cmd/templates/svelte/frontend/README.md b/cmd/templates/svelte/frontend/README.md new file mode 100644 index 000000000..360f27156 --- /dev/null +++ b/cmd/templates/svelte/frontend/README.md @@ -0,0 +1,90 @@ +*Looking for a shareable component template? Go here --> [sveltejs/component-template](https://github.com/sveltejs/component-template)* + +--- + +# svelte app + +This is a project template for [Svelte](https://svelte.dev) apps. It lives at https://github.com/sveltejs/template. + +To create a new project based on this template using [degit](https://github.com/Rich-Harris/degit): + +```bash +npx degit sveltejs/template svelte-app +cd svelte-app +``` + +*Note that you will need to have [Node.js](https://nodejs.org) installed.* + + +## Get started + +Install the dependencies... + +```bash +cd svelte-app +npm install +``` + +...then start [Rollup](https://rollupjs.org): + +```bash +npm run dev +``` + +Navigate to [localhost:5000](http://localhost:5000). You should see your app running. Edit a component file in `src`, save it, and reload the page to see your changes. + +By default, the server will only respond to requests from localhost. To allow connections from other computers, edit the `sirv` commands in package.json to include the option `--host 0.0.0.0`. + + +## Building and running in production mode + +To create an optimised version of the app: + +```bash +npm run build +``` + +You can run the newly built app with `npm run start`. This uses [sirv](https://github.com/lukeed/sirv), which is included in your package.json's `dependencies` so that the app will work when you deploy to platforms like [Heroku](https://heroku.com). + + +## Single-page app mode + +By default, sirv will only respond to requests that match files in `public`. This is to maximise compatibility with static fileservers, allowing you to deploy your app anywhere. + +If you're building a single-page app (SPA) with multiple routes, sirv needs to be able to respond to requests for *any* path. You can make it so by editing the `"start"` command in package.json: + +```js +"start": "sirv public --single" +``` + +## Deploying to the web + +### With [Vercel](https://vercel.com) + +Install `vercel` if you haven't already: + +```bash +npm install -g vercel +``` + +Then, from within your project folder: + +```bash +cd public +vercel deploy --name my-project +``` + +### With [surge](https://surge.sh/) + +Install `surge` if you haven't already: + +```bash +npm install -g surge +``` + +Then, from within your project folder: + +```bash +npm run build +surge public my-project.surge.sh +``` diff --git a/cmd/templates/svelte/frontend/package.json.template b/cmd/templates/svelte/frontend/package.json.template new file mode 100644 index 000000000..d833ead13 --- /dev/null +++ b/cmd/templates/svelte/frontend/package.json.template @@ -0,0 +1,31 @@ +{ + "name": "{{.NPMProjectName}}", + "author": "{{.Author.Name}}<{{.Author.Email}}>", + "scripts": { + "build": "rollup -c", + "serve": "rollup -c -w", + "start": "sirv public" + }, + "devDependencies": { + "@babel/core": "^7.11.6", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-transform-runtime": "^7.11.5", + "@babel/preset-env": "^7.11.5", + "@rollup/plugin-commonjs": "^14.0.0", + "@rollup/plugin-image": "^2.0.5", + "@rollup/plugin-node-resolve": "^8.0.0", + "core-js": "^3.6.5", + "rollup": "^2.3.4", + "rollup-plugin-babel": "^4.4.0", + "rollup-plugin-livereload": "^2.0.0", + "rollup-plugin-polyfill": "^3.0.0", + "rollup-plugin-svelte": "^6.0.0", + "rollup-plugin-terser": "^7.0.0", + "svelte": "^3.0.0" + }, + "dependencies": { + "sirv-cli": "^1.0.0", + "@wailsapp/runtime": "^1.0.10", + "svelte-simple-modal": "^0.6.0" + } +} diff --git a/cmd/templates/svelte/frontend/public/favicon.png b/cmd/templates/svelte/frontend/public/favicon.png new file mode 100644 index 000000000..7e6f5eb5a Binary files /dev/null and b/cmd/templates/svelte/frontend/public/favicon.png differ diff --git a/cmd/templates/svelte/frontend/public/index.html b/cmd/templates/svelte/frontend/public/index.html new file mode 100644 index 000000000..a9c8fd65d --- /dev/null +++ b/cmd/templates/svelte/frontend/public/index.html @@ -0,0 +1,17 @@ + + + + + + + Svelte app + + + + + + + + + + diff --git a/cmd/templates/svelte/frontend/rollup.config.js b/cmd/templates/svelte/frontend/rollup.config.js new file mode 100644 index 000000000..6d0a0a12d --- /dev/null +++ b/cmd/templates/svelte/frontend/rollup.config.js @@ -0,0 +1,109 @@ +import svelte from 'rollup-plugin-svelte'; +import resolve from '@rollup/plugin-node-resolve'; +import commonjs from '@rollup/plugin-commonjs'; +import livereload from 'rollup-plugin-livereload'; +import {terser} from 'rollup-plugin-terser'; +import image from '@rollup/plugin-image'; +import babel from 'rollup-plugin-babel'; +import polyfill from 'rollup-plugin-polyfill'; + +const production = !process.env.ROLLUP_WATCH; + +function serve() { + let server; + + function toExit() { + if (server) server.kill(0); + } + + return { + writeBundle() { + if (server) return; + server = require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], { + stdio: ['ignore', 'inherit', 'inherit'], + shell: true + }); + + process.on('SIGTERM', toExit); + process.on('exit', toExit); + } + }; +} + +export default { + input: 'src/main.js', + output: { + sourcemap: true, + format: 'iife', + name: 'app', + file: 'public/build/bundle.js' + }, + plugins: [ + image(), + svelte({ + // enable run-time checks when not in production + dev: !production, + // we'll extract any component CSS out into + // a separate file - better for performance + css: css => { + css.write('bundle.css'); + } + }), + + // If you have external dependencies installed from + // npm, you'll most likely need these plugins. In + // some cases you'll need additional configuration - + // consult the documentation for details: + // https://github.com/rollup/plugins/tree/master/packages/commonjs + resolve({ + browser: true, + dedupe: ['svelte', 'svelte/transition', 'svelte/internal'] + }), + commonjs(), + + // In dev mode, call `npm run start` once + // the bundle has been generated + !production && serve(), + + // Watch the `public` directory and refresh the + // browser on changes when not in production + !production && livereload('public'), + + // Credit: https://blog.az.sg/posts/svelte-and-ie11/ + babel({ + extensions: [ '.js', '.jsx', '.es6', '.es', '.mjs', '.svelte', '.html' ], + runtimeHelpers: true, + exclude: [ 'node_modules/@babel/**', 'node_modules/core-js/**' ], + presets: [ + [ + '@babel/preset-env', + { + targets: '> 0.25%, not dead, IE 11', + modules: false, + useBuiltIns: 'usage', + forceAllTransforms: true, + corejs: 3, + }, + + ] + ], + plugins: [ + '@babel/plugin-syntax-dynamic-import', + [ + '@babel/plugin-transform-runtime', + { + useESModules: true + } + ] + ] + }), + polyfill(['@webcomponents/webcomponentsjs']), + + // If we're building for production (npm run build + // instead of npm run dev), minify + production && terser() + ], + watch: { + clearScreen: false + } +}; diff --git a/cmd/templates/svelte/frontend/src/App.svelte b/cmd/templates/svelte/frontend/src/App.svelte new file mode 100644 index 000000000..dbc1c3ecc --- /dev/null +++ b/cmd/templates/svelte/frontend/src/App.svelte @@ -0,0 +1,69 @@ + + + + +
+
+
+ + +

Welcome to your new wails/svelte project.

+ +
+
+
+
+ + \ No newline at end of file diff --git a/cmd/templates/svelte/frontend/src/components/HelloWorld.svelte b/cmd/templates/svelte/frontend/src/components/HelloWorld.svelte new file mode 100644 index 000000000..10948498d --- /dev/null +++ b/cmd/templates/svelte/frontend/src/components/HelloWorld.svelte @@ -0,0 +1,18 @@ + + +
+

+
+ + \ No newline at end of file diff --git a/cmd/templates/svelte/frontend/src/components/ModalContent.svelte b/cmd/templates/svelte/frontend/src/components/ModalContent.svelte new file mode 100644 index 000000000..37ce80fbb --- /dev/null +++ b/cmd/templates/svelte/frontend/src/components/ModalContent.svelte @@ -0,0 +1,7 @@ + + +

+ {message} +

\ No newline at end of file diff --git a/cmd/templates/svelte/frontend/src/logo.png b/cmd/templates/svelte/frontend/src/logo.png new file mode 100644 index 000000000..31fc8249c Binary files /dev/null and b/cmd/templates/svelte/frontend/src/logo.png differ diff --git a/cmd/templates/svelte/frontend/src/main.js b/cmd/templates/svelte/frontend/src/main.js new file mode 100644 index 000000000..2646517ec --- /dev/null +++ b/cmd/templates/svelte/frontend/src/main.js @@ -0,0 +1,13 @@ +import App from './App.svelte'; + +import * as Wails from '@wailsapp/runtime'; + +let app; + +Wails.Init(() => { + app = new App({ + target: document.body, + }); +}); + +export default app; \ No newline at end of file diff --git a/cmd/templates/svelte/go.mod.template b/cmd/templates/svelte/go.mod.template new file mode 100644 index 000000000..780381065 --- /dev/null +++ b/cmd/templates/svelte/go.mod.template @@ -0,0 +1,5 @@ +module {{.BinaryName}} + +require ( + github.com/wailsapp/wails {{.WailsVersion}} +) \ No newline at end of file diff --git a/cmd/templates/svelte/main.go.template b/cmd/templates/svelte/main.go.template new file mode 100644 index 000000000..238d947cc --- /dev/null +++ b/cmd/templates/svelte/main.go.template @@ -0,0 +1,31 @@ +package main + +import ( + _ "embed" + "github.com/wailsapp/wails" +) + +func basic() string { + return "World!" +} + +//go:embed frontend/public/build/bundle.js +var js string + +//go:embed frontend/public/build/bundle.css +var css string + +func main() { + + app := wails.CreateApp(&wails.AppConfig{ + Width: 1024, + Height: 768, + Title: "{{.Name}}", + JS: js, + CSS: css, + Colour: "#131313", + }) + + app.Bind(basic) + app.Run() +} diff --git a/cmd/templates/svelte/template.json b/cmd/templates/svelte/template.json new file mode 100755 index 000000000..dea6ed191 --- /dev/null +++ b/cmd/templates/svelte/template.json @@ -0,0 +1,14 @@ +{ + "name": "Svelte", + "version": "1.0.0", + "shortdescription": "A basic Svelte template", + "description": "A basic Svelte template", + "install": "npm install", + "build": "npm run build", + "author": "Tim Kipp ", + "created": "2020-09-06 13:06:10.469848 -0700 PDT m=+213.578828559", + "frontenddir": "frontend", + "serve": "npm run serve", + "bridge": "src", + "wailsdir": "" +} diff --git a/cmd/templates/vanilla/README.md b/cmd/templates/vanilla/README.md new file mode 100644 index 000000000..4762fa49c --- /dev/null +++ b/cmd/templates/vanilla/README.md @@ -0,0 +1,5 @@ +# README + +This is an experimental template for vanilla HTML/JS/CSS. + +The webpack rules may need to be adjusted to correctly embed all assets. Babel may also need to be setup correctly. \ No newline at end of file diff --git a/cmd/templates/vanilla/counter.go b/cmd/templates/vanilla/counter.go new file mode 100644 index 000000000..ec93892cf --- /dev/null +++ b/cmd/templates/vanilla/counter.go @@ -0,0 +1,46 @@ +package main + +import ( + "math/rand" + + "github.com/wailsapp/wails" +) + +// Counter is what we use for counting +type Counter struct { + r *wails.Runtime + store *wails.Store +} + +// WailsInit is called when the component is being initialised +func (c *Counter) WailsInit(runtime *wails.Runtime) error { + c.r = runtime + c.store = runtime.Store.New("Counter", 0) + return nil +} + +// RandomValue sets the counter to a random value +func (c *Counter) RandomValue() { + c.store.Set(rand.Intn(1000)) +} + +// Increment will increment the counter +func (c *Counter) Increment() { + + increment := func(data int) int { + return data + 1 + } + + // Update the store using the increment function + c.store.Update(increment) +} + +// Decrement will decrement the counter +func (c *Counter) Decrement() { + + decrement := func(data int) int { + return data - 1 + } + // Update the store using the decrement function + c.store.Update(decrement) +} diff --git a/cmd/templates/vanilla/frontend/package.json.template b/cmd/templates/vanilla/frontend/package.json.template new file mode 100644 index 000000000..174e5ac93 --- /dev/null +++ b/cmd/templates/vanilla/frontend/package.json.template @@ -0,0 +1,42 @@ +{ + "name": "vanilla", + "author": "Lea", + "private": true, + "scripts": { + "serve": "webpack-dev-server", + "build": "npx webpack" + }, + "dependencies": { + "core-js": "^3.6.4", + "regenerator-runtime": "^0.13.3", + "@wailsapp/runtime": "^1.0.10" + }, + "devDependencies": { + "babel-eslint": "^10.1.0", + "copy-webpack-plugin": "^6.0.2", + "eslint": "^6.8.0", + "eventsource-polyfill": "^0.9.6", + "webpack": "^4.43.0", + "webpack-cli": "^3.3.11", + "webpack-dev-server": "^3.11.0", + "webpack-hot-middleware": "^2.25.0" + }, + "eslintConfig": { + "root": true, + "env": { + "node": true + }, + "extends": [ + "eslint:recommended" + ], + "rules": {}, + "parserOptions": { + "parser": "babel-eslint" + } + }, + "browserslist": [ + "> 1%", + "last 2 versions", + "not ie <= 8" + ] +} diff --git a/cmd/templates/vanilla/frontend/src/index.html b/cmd/templates/vanilla/frontend/src/index.html new file mode 100644 index 000000000..c7eb55539 --- /dev/null +++ b/cmd/templates/vanilla/frontend/src/index.html @@ -0,0 +1,9 @@ + + + + + +
+ + + \ No newline at end of file diff --git a/cmd/templates/vanilla/frontend/src/main.css b/cmd/templates/vanilla/frontend/src/main.css new file mode 100644 index 000000000..cbfc4313a --- /dev/null +++ b/cmd/templates/vanilla/frontend/src/main.css @@ -0,0 +1,45 @@ + +html, +body { + background-color: white; + color: black; + width: 100%; + height: 100%; + margin: 0; +} + +input { + background-color: rgb(254,254,254); + color: black; +} + +.container { + display: block; + width:100%; + text-align: center; + margin-top: 1rem; + font-size: 2rem; +} + +button { + font-size: 1rem; + background-color: white; + color: black; +} + +.result { + margin-top: 1rem; + text-align: center; + font-size: 2rem; +} + +.logo { + display: block; + margin-left: auto; + margin-right: auto; + width: 50%; + height: 50%; + background-image: url(data:image/png;base64,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); + background-size: cover; + background-position: 50% center; +} diff --git a/cmd/templates/vanilla/frontend/src/main.js b/cmd/templates/vanilla/frontend/src/main.js new file mode 100644 index 000000000..609e55e43 --- /dev/null +++ b/cmd/templates/vanilla/frontend/src/main.js @@ -0,0 +1,47 @@ +import 'core-js/stable'; +const runtime = require('@wailsapp/runtime'); + +// Main entry point +function start() { + + var mystore = runtime.Store.New('Counter'); + + // Ensure the default app div is 100% wide/high + var app = document.getElementById('app'); + app.style.width = '100%'; + app.style.height = '100%'; + + // Inject html + app.innerHTML = ` + +
+ + +
+
Counter:
+
+ + + +
+ `; + + // Connect counter value button to Go method + document.getElementById('setvalue').onclick = function() { + let newValue = parseInt(document.getElementById('newCounter').value,10); + mystore.set(newValue); + }; + + mystore.subscribe( function(state) { + document.getElementById('counter').innerText = state; + }); + + mystore.set(0); +}; + +// We provide our entrypoint as a callback for runtime.Init +runtime.Init(start); \ No newline at end of file diff --git a/cmd/templates/vanilla/frontend/webpack.config.js b/cmd/templates/vanilla/frontend/webpack.config.js new file mode 100644 index 000000000..c5490acce --- /dev/null +++ b/cmd/templates/vanilla/frontend/webpack.config.js @@ -0,0 +1,56 @@ +const path = require('path'); +const CopyWebpackPlugin = require('copy-webpack-plugin'); + +let imageSizeLimit = 9007199254740991; // Number.MAX_SAFE_INTEGER +let sourceDir = path.resolve(__dirname, 'src'); +let buildDir = path.resolve(__dirname, 'build'); + +module.exports = { + entry: { + index: path.resolve(sourceDir, 'main.js') + }, + output: { + path: buildDir, + filename: 'main.js' + }, + optimization: { + splitChunks: false + }, + devServer: { + disableHostCheck: true, + contentBase: path.join(__dirname, 'src'), + compress: true, + open: true, + port: 8090 + }, + mode: 'production', + module: { + rules: [ + { + test: /\.(png|gif|jpg|woff2?|eot|ttf|otf|svg)(\?.*)?$/i, + use: [ + { + loader: 'url-loader', + options: { + limit: imageSizeLimit + } + } + ], + } + ] + }, + plugins: [ + new CopyWebpackPlugin({ + patterns: [ + { + from: path.resolve(sourceDir, 'main.css'), + to: path.resolve(buildDir, 'main.css') + }, + { + from: path.resolve(sourceDir, 'index.html'), + to: path.resolve(buildDir, 'index.html') + }, + ] + }) + ] +}; diff --git a/cmd/templates/vanilla/go.mod.template b/cmd/templates/vanilla/go.mod.template new file mode 100644 index 000000000..780381065 --- /dev/null +++ b/cmd/templates/vanilla/go.mod.template @@ -0,0 +1,5 @@ +module {{.BinaryName}} + +require ( + github.com/wailsapp/wails {{.WailsVersion}} +) \ No newline at end of file diff --git a/cmd/templates/vanilla/main.go.template b/cmd/templates/vanilla/main.go.template new file mode 100644 index 000000000..e4dbbbc00 --- /dev/null +++ b/cmd/templates/vanilla/main.go.template @@ -0,0 +1,26 @@ +package main + +import ( + _ "embed" + "github.com/wailsapp/wails" +) + +//go:embed frontend/build/main.js +var js string + +//go:embed frontend/build/main.css +var css string + +func main() { + + app := wails.CreateApp(&wails.AppConfig{ + Width: 1024, + Height: 768, + Title: "{{.Name}}", + JS: js, + CSS: css, + Colour: "#131313", + }) + app.Bind(&Counter{}) + app.Run() +} diff --git a/cmd/templates/vanilla/template.json b/cmd/templates/vanilla/template.json new file mode 100644 index 000000000..2bad445ef --- /dev/null +++ b/cmd/templates/vanilla/template.json @@ -0,0 +1,12 @@ +{ + "name": "Vanilla", + "shortdescription": "A Vanilla HTML/JS template", + "description": "A basic template using plain html/js and bundled using Webpack 4", + "author": "Lea Anthony", + "created": "2020-06-14", + "frontenddir": "frontend", + "install": "npm install", + "build": "npm run build", + "serve": "npm run serve", + "bridge": "src" +} diff --git a/cmd/templates/vue3-full/frontend/.browserslistrc b/cmd/templates/vue3-full/frontend/.browserslistrc new file mode 100644 index 000000000..214388fe4 --- /dev/null +++ b/cmd/templates/vue3-full/frontend/.browserslistrc @@ -0,0 +1,3 @@ +> 1% +last 2 versions +not dead diff --git a/cmd/templates/vue3-full/frontend/.eslintrc.js b/cmd/templates/vue3-full/frontend/.eslintrc.js new file mode 100644 index 000000000..bf594a121 --- /dev/null +++ b/cmd/templates/vue3-full/frontend/.eslintrc.js @@ -0,0 +1,29 @@ +module.exports = { + root: true, + env: { + node: true + }, + 'extends': [ + 'plugin:vue/vue3-essential', + 'eslint:recommended', + '@vue/typescript/recommended' + ], + parserOptions: { + ecmaVersion: 2020 + }, + rules: { + 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', + 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off' + }, + overrides: [ + { + files: [ + '**/__tests__/*.{j,t}s?(x)', + '**/tests/unit/**/*.spec.{j,t}s?(x)' + ], + env: { + mocha: true + } + } + ] +} diff --git a/cmd/templates/vue3-full/frontend/.gitignore b/cmd/templates/vue3-full/frontend/.gitignore new file mode 100644 index 000000000..185e66319 --- /dev/null +++ b/cmd/templates/vue3-full/frontend/.gitignore @@ -0,0 +1,21 @@ +.DS_Store +node_modules +/dist + +# local env files +.env.local +.env.*.local + +# Log files +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw* diff --git a/cmd/templates/vue3-full/frontend/README.md b/cmd/templates/vue3-full/frontend/README.md new file mode 100644 index 000000000..6953f66d0 --- /dev/null +++ b/cmd/templates/vue3-full/frontend/README.md @@ -0,0 +1,35 @@ +# vue basic + +## Project setup + +``` +npm install +``` + +### Compiles and hot-reloads for development + +``` +npm run serve +``` + +### Compiles and minifies for production + +``` +npm run build +``` + +### Run your tests + +``` +npm run test +``` + +### Lints and fixes files + +``` +npm run lint +``` + +### Customize configuration + +See [Configuration Reference](https://cli.vuejs.org/config/). diff --git a/cmd/templates/vue3-full/frontend/package.json.template b/cmd/templates/vue3-full/frontend/package.json.template new file mode 100644 index 000000000..dc7eef41e --- /dev/null +++ b/cmd/templates/vue3-full/frontend/package.json.template @@ -0,0 +1,37 @@ +{ + "name": "{{.NPMProjectName}}", + "author": "{{.Author.Name}}<{{.Author.Email}}>", + "private": true, + "scripts": { + "serve": "vue-cli-service serve", + "build": "vue-cli-service build", + "test:unit": "vue-cli-service test:unit", + "lint": "vue-cli-service lint" + }, + "dependencies": { + "vue": "^3.0.0-0", + "vue-router": "^4.0.0-0", + "regenerator-runtime": "^0.13.7", + "@wailsapp/runtime": "^1.1.1" + }, + "devDependencies": { + "@types/chai": "^4.2.12", + "@types/mocha": "^8.0.3", + "@typescript-eslint/eslint-plugin": "^4.3.0", + "@typescript-eslint/parser": "^4.3.0", + "@vue/cli-plugin-eslint": "~4.5.9", + "@vue/cli-plugin-router": "~4.5.9", + "@vue/cli-plugin-typescript": "~4.5.9", + "@vue/cli-plugin-unit-mocha": "~4.5.9", + "@vue/cli-service": "~4.5.9", + "@vue/compiler-sfc": "^3.0.0", + "@vue/eslint-config-typescript": "^7.0.0", + "@vue/test-utils": "^2.0.0-0", + "chai": "^4.2.0", + "eslint": "<7.0.0", + "eslint-plugin-vue": "^7.0.0", + "node-sass": "^4.14.1", + "sass-loader": "^10.0.2", + "typescript": "~4.0.3" + } +} diff --git a/cmd/templates/vue3-full/frontend/src/App.vue b/cmd/templates/vue3-full/frontend/src/App.vue new file mode 100644 index 000000000..6939bbb9b --- /dev/null +++ b/cmd/templates/vue3-full/frontend/src/App.vue @@ -0,0 +1,32 @@ + + + diff --git a/cmd/templates/vue3-full/frontend/src/assets/appicon.png b/cmd/templates/vue3-full/frontend/src/assets/appicon.png new file mode 100644 index 000000000..9f22be34b Binary files /dev/null and b/cmd/templates/vue3-full/frontend/src/assets/appicon.png differ diff --git a/cmd/templates/vue3-full/frontend/src/components/HelloWorld.vue b/cmd/templates/vue3-full/frontend/src/components/HelloWorld.vue new file mode 100644 index 000000000..92d381cd8 --- /dev/null +++ b/cmd/templates/vue3-full/frontend/src/components/HelloWorld.vue @@ -0,0 +1,34 @@ + + + + + + diff --git a/cmd/templates/vue3-full/frontend/src/main.ts b/cmd/templates/vue3-full/frontend/src/main.ts new file mode 100644 index 000000000..0d2c5a90b --- /dev/null +++ b/cmd/templates/vue3-full/frontend/src/main.ts @@ -0,0 +1,8 @@ +import { createApp } from 'vue'; +import App from './App.vue'; +import router from './router'; +import * as Wails from '@wailsapp/runtime'; + +Wails.Init(() => { + createApp(App).use(router).mount('#app'); +}); diff --git a/cmd/templates/vue3-full/frontend/src/router/index.ts b/cmd/templates/vue3-full/frontend/src/router/index.ts new file mode 100644 index 000000000..73c740289 --- /dev/null +++ b/cmd/templates/vue3-full/frontend/src/router/index.ts @@ -0,0 +1,27 @@ +import { createRouter, createMemoryHistory, RouteRecordRaw } from 'vue-router' +import Home from '../views/Home.vue' +import About from '../views/About.vue' + +const routes: Array = [ + { + path: '/', + name: 'Home', + component: Home + }, + { + path: '/about', + name: 'About', + // route level code-splitting + // this generates a separate chunk (about.[hash].js) for this route + // which is lazy-loaded when the route is visited. + // component: () => import(/* webpackChunkName: "about" */ '../views/About.vue') + component: About + } +] + +const router = createRouter({ + history: createMemoryHistory(), + routes +}) + +export default router diff --git a/cmd/templates/vue3-full/frontend/src/shims-vue.d.ts b/cmd/templates/vue3-full/frontend/src/shims-vue.d.ts new file mode 100644 index 000000000..32a1b5cd4 --- /dev/null +++ b/cmd/templates/vue3-full/frontend/src/shims-vue.d.ts @@ -0,0 +1,5 @@ +declare module '*.vue' { + import { defineComponent } from 'vue' + const component: ReturnType + export default component +} diff --git a/cmd/templates/vue3-full/frontend/src/views/About.vue b/cmd/templates/vue3-full/frontend/src/views/About.vue new file mode 100644 index 000000000..3fa28070d --- /dev/null +++ b/cmd/templates/vue3-full/frontend/src/views/About.vue @@ -0,0 +1,5 @@ + diff --git a/cmd/templates/vue3-full/frontend/src/views/Home.vue b/cmd/templates/vue3-full/frontend/src/views/Home.vue new file mode 100644 index 000000000..cc6aac4cb --- /dev/null +++ b/cmd/templates/vue3-full/frontend/src/views/Home.vue @@ -0,0 +1,40 @@ + + + diff --git a/cmd/templates/vue3-full/frontend/tests/unit/example.spec.ts b/cmd/templates/vue3-full/frontend/tests/unit/example.spec.ts new file mode 100644 index 000000000..bbb728f18 --- /dev/null +++ b/cmd/templates/vue3-full/frontend/tests/unit/example.spec.ts @@ -0,0 +1,14 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; +import { shallowMount } from '@vue/test-utils'; +import HelloWorld from '@/components/HelloWorld.vue'; + +describe('HelloWorld.vue', () => { + it('renders props.msg when passed', () => { + const msg = 'new message'; + const wrapper = shallowMount(HelloWorld, { + props: { msg } + }); + expect(wrapper.text()).to.include(msg); + }); +}); diff --git a/cmd/templates/vue3-full/frontend/tsconfig.json b/cmd/templates/vue3-full/frontend/tsconfig.json new file mode 100644 index 000000000..e4ba95a15 --- /dev/null +++ b/cmd/templates/vue3-full/frontend/tsconfig.json @@ -0,0 +1,41 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "esnext", + "strict": true, + "jsx": "preserve", + "importHelpers": true, + "moduleResolution": "node", + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "sourceMap": true, + "baseUrl": ".", + "types": [ + "webpack-env", + "mocha", + "chai" + ], + "paths": { + "@/*": [ + "src/*" + ] + }, + "lib": [ + "esnext", + "dom", + "dom.iterable", + "scripthost" + ] + }, + "include": [ + "src/**/*.ts", + "src/**/*.tsx", + "src/**/*.vue", + "tests/**/*.ts", + "tests/**/*.tsx" + ], + "exclude": [ + "node_modules" + ] +} diff --git a/cmd/templates/vue3-full/frontend/vue.config.js b/cmd/templates/vue3-full/frontend/vue.config.js new file mode 100644 index 000000000..8dcf3e339 --- /dev/null +++ b/cmd/templates/vue3-full/frontend/vue.config.js @@ -0,0 +1,42 @@ +let cssConfig = {}; + +if (process.env.NODE_ENV == 'production') { + cssConfig = { + extract: { + filename: '[name].css', + chunkFilename: '[name].css' + } + }; +} + +module.exports = { + chainWebpack: config => { + let limit = 9999999999999999; + config.module + .rule('images') + .test(/\.(png|gif|jpg)(\?.*)?$/i) + .use('url-loader') + .loader('url-loader') + .tap(options => Object.assign(options, { limit: limit })); + config.module + .rule('fonts') + .test(/\.(woff2?|eot|ttf|otf|svg)(\?.*)?$/i) + .use('url-loader') + .loader('url-loader') + .options({ + limit: limit + }); + }, + css: cssConfig, + configureWebpack: { + output: { + filename: '[name].js' + }, + optimization: { + splitChunks: false + } + }, + devServer: { + disableHostCheck: true + } +}; diff --git a/cmd/templates/vue3-full/go.mod.template b/cmd/templates/vue3-full/go.mod.template new file mode 100644 index 000000000..780381065 --- /dev/null +++ b/cmd/templates/vue3-full/go.mod.template @@ -0,0 +1,5 @@ +module {{.BinaryName}} + +require ( + github.com/wailsapp/wails {{.WailsVersion}} +) \ No newline at end of file diff --git a/cmd/templates/vue3-full/main.go.template b/cmd/templates/vue3-full/main.go.template new file mode 100644 index 000000000..5c5453943 --- /dev/null +++ b/cmd/templates/vue3-full/main.go.template @@ -0,0 +1,30 @@ +package main + +import ( + _ "embed" + "github.com/wailsapp/wails" +) + +func basic() string { + return "Hello World!" +} + +//go:embed frontend/dist/app.js +var js string + +//go:embed frontend/dist/app.css +var css string + +func main() { + + app := wails.CreateApp(&wails.AppConfig{ + Width: 1024, + Height: 768, + Title: "{{.Name}}", + JS: js, + CSS: css, + Colour: "#131313", + }) + app.Bind(basic) + app.Run() +} diff --git a/cmd/templates/vue3-full/template.json b/cmd/templates/vue3-full/template.json new file mode 100755 index 000000000..a4e0cb520 --- /dev/null +++ b/cmd/templates/vue3-full/template.json @@ -0,0 +1,15 @@ +{ + "name": "Vue3 Full", + "version": "1.0.0", + "shortdescription": "Vue 3, Vuex, Vue-router, and Webpack4", + "description": "Vue3.0.0 Vuex, Vue-router, and Webpack 4", + "install": "npm install", + "build": "npm run build", + "author": "Kyle Muchmore ", + "created": "2020-09-24 21:18:55.09417 +0000 UTC m=+90.125590001", + "frontenddir": "frontend", + "serve": "npm run serve", + "bridge": "src", + "wailsdir": "", + "platforms": ["linux", "darwin"] +} diff --git a/cmd/templates/vue3-js/frontend/.gitignore b/cmd/templates/vue3-js/frontend/.gitignore new file mode 100644 index 000000000..403adbc1e --- /dev/null +++ b/cmd/templates/vue3-js/frontend/.gitignore @@ -0,0 +1,23 @@ +.DS_Store +node_modules +/dist + + +# local env files +.env.local +.env.*.local + +# Log files +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/cmd/templates/vue3-js/frontend/README.md b/cmd/templates/vue3-js/frontend/README.md new file mode 100644 index 000000000..f56df6be7 --- /dev/null +++ b/cmd/templates/vue3-js/frontend/README.md @@ -0,0 +1,29 @@ +# vue-js + +## Project setup + +``` +npm install +``` + +### Compiles and hot-reloads for development + +``` +npm run serve +``` + +### Compiles and minifies for production + +``` +npm run build +``` + +### Lints and fixes files + +``` +npm run lint +``` + +### Customize configuration + +See [Configuration Reference](https://cli.vuejs.org/config/). diff --git a/cmd/templates/vue3-js/frontend/babel.config.js b/cmd/templates/vue3-js/frontend/babel.config.js new file mode 100644 index 000000000..c94e72931 --- /dev/null +++ b/cmd/templates/vue3-js/frontend/babel.config.js @@ -0,0 +1,5 @@ +module.exports = { + presets: [ + '@vue/cli-plugin-babel/preset' + ] +} diff --git a/cmd/templates/vue3-js/frontend/package-lock.json b/cmd/templates/vue3-js/frontend/package-lock.json new file mode 100644 index 000000000..6431cfe4d --- /dev/null +++ b/cmd/templates/vue3-js/frontend/package-lock.json @@ -0,0 +1,12312 @@ +{ + "name": "vue-js", + "version": "0.1.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.12.13", + "resolved": "https://registry.npm.taobao.org/@babel/code-frame/download/@babel/code-frame-7.12.13.tgz?cache=0&sync_timestamp=1612314620252&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fcode-frame%2Fdownload%2F%40babel%2Fcode-frame-7.12.13.tgz", + "integrity": "sha1-3PyCa+72XnXFDiHTg319lXmN1lg=", + "dev": true, + "requires": { + "@babel/highlight": "^7.12.13" + } + }, + "@babel/compat-data": { + "version": "7.14.4", + "resolved": "https://registry.nlark.com/@babel/compat-data/download/@babel/compat-data-7.14.4.tgz?cache=0&sync_timestamp=1622221249104&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fcompat-data%2Fdownload%2F%40babel%2Fcompat-data-7.14.4.tgz", + "integrity": "sha1-RXIP4M7PP9QgGeHRLMPSf63JjVg=", + "dev": true + }, + "@babel/core": { + "version": "7.14.3", + "resolved": "https://registry.nlark.com/@babel/core/download/@babel/core-7.14.3.tgz", + "integrity": "sha1-U5XjBAXwd2Bn+9nPCITxW/t3Cjg=", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@babel/generator": "^7.14.3", + "@babel/helper-compilation-targets": "^7.13.16", + "@babel/helper-module-transforms": "^7.14.2", + "@babel/helpers": "^7.14.0", + "@babel/parser": "^7.14.3", + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.14.2", + "@babel/types": "^7.14.2", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.1.2", + "semver": "^6.3.0", + "source-map": "^0.5.0" + } + }, + "@babel/generator": { + "version": "7.14.3", + "resolved": "https://registry.nlark.com/@babel/generator/download/@babel/generator-7.14.3.tgz", + "integrity": "sha1-DCZS2R973at8zMa6gVfk9A3O25E=", + "dev": true, + "requires": { + "@babel/types": "^7.14.2", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.12.13", + "resolved": "https://registry.npm.taobao.org/@babel/helper-annotate-as-pure/download/@babel/helper-annotate-as-pure-7.12.13.tgz?cache=0&sync_timestamp=1612314684390&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-annotate-as-pure%2Fdownload%2F%40babel%2Fhelper-annotate-as-pure-7.12.13.tgz", + "integrity": "sha1-D1jobfxLs7H819uAZXDhd9Q5tqs=", + "dev": true, + "requires": { + "@babel/types": "^7.12.13" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.12.13", + "resolved": "https://registry.nlark.com/@babel/helper-builder-binary-assignment-operator-visitor/download/@babel/helper-builder-binary-assignment-operator-visitor-7.12.13.tgz", + "integrity": "sha1-a8IDYciLCnTQUTemXKyNPL9vYfw=", + "dev": true, + "requires": { + "@babel/helper-explode-assignable-expression": "^7.12.13", + "@babel/types": "^7.12.13" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.14.4", + "resolved": "https://registry.nlark.com/@babel/helper-compilation-targets/download/@babel/helper-compilation-targets-7.14.4.tgz?cache=0&sync_timestamp=1622221254097&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fhelper-compilation-targets%2Fdownload%2F%40babel%2Fhelper-compilation-targets-7.14.4.tgz", + "integrity": "sha1-M+vQ/8NCSAUe4giTUKkpqwLypRY=", + "dev": true, + "requires": { + "@babel/compat-data": "^7.14.4", + "@babel/helper-validator-option": "^7.12.17", + "browserslist": "^4.16.6", + "semver": "^6.3.0" + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.14.4", + "resolved": "https://registry.nlark.com/@babel/helper-create-class-features-plugin/download/@babel/helper-create-class-features-plugin-7.14.4.tgz?cache=0&sync_timestamp=1622221254182&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fhelper-create-class-features-plugin%2Fdownload%2F%40babel%2Fhelper-create-class-features-plugin-7.14.4.tgz", + "integrity": "sha1-q/iI2DakQavueDx1IpJ5dIcF3EI=", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.12.13", + "@babel/helper-function-name": "^7.14.2", + "@babel/helper-member-expression-to-functions": "^7.13.12", + "@babel/helper-optimise-call-expression": "^7.12.13", + "@babel/helper-replace-supers": "^7.14.4", + "@babel/helper-split-export-declaration": "^7.12.13" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.14.3", + "resolved": "https://registry.nlark.com/@babel/helper-create-regexp-features-plugin/download/@babel/helper-create-regexp-features-plugin-7.14.3.tgz?cache=0&sync_timestamp=1621284706846&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fhelper-create-regexp-features-plugin%2Fdownload%2F%40babel%2Fhelper-create-regexp-features-plugin-7.14.3.tgz", + "integrity": "sha1-FJqm14wBbjGMQ+JAmgrpwTaoZog=", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.12.13", + "regexpu-core": "^4.7.1" + } + }, + "@babel/helper-define-polyfill-provider": { + "version": "0.2.3", + "resolved": "https://registry.nlark.com/@babel/helper-define-polyfill-provider/download/@babel/helper-define-polyfill-provider-0.2.3.tgz?cache=0&sync_timestamp=1622025470416&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fhelper-define-polyfill-provider%2Fdownload%2F%40babel%2Fhelper-define-polyfill-provider-0.2.3.tgz", + "integrity": "sha1-BSXt7FCUZTooJojTTYRuTHXpwLY=", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.13.0", + "@babel/helper-module-imports": "^7.12.13", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/traverse": "^7.13.0", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + } + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.13.0", + "resolved": "https://registry.npm.taobao.org/@babel/helper-explode-assignable-expression/download/@babel/helper-explode-assignable-expression-7.13.0.tgz?cache=0&sync_timestamp=1614034233759&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-explode-assignable-expression%2Fdownload%2F%40babel%2Fhelper-explode-assignable-expression-7.13.0.tgz", + "integrity": "sha1-F7XFn/Rz2flW9A71cM86dsoSZX8=", + "dev": true, + "requires": { + "@babel/types": "^7.13.0" + } + }, + "@babel/helper-function-name": { + "version": "7.14.2", + "resolved": "https://registry.nlark.com/@babel/helper-function-name/download/@babel/helper-function-name-7.14.2.tgz", + "integrity": "sha1-OXaItZB2C273cltfCGDIJCfrqsI=", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.12.13", + "@babel/template": "^7.12.13", + "@babel/types": "^7.14.2" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.12.13", + "resolved": "https://registry.npm.taobao.org/@babel/helper-get-function-arity/download/@babel/helper-get-function-arity-7.12.13.tgz?cache=0&sync_timestamp=1612314652298&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-get-function-arity%2Fdownload%2F%40babel%2Fhelper-get-function-arity-7.12.13.tgz", + "integrity": "sha1-vGNFHUA6OzCCuX4diz/lvUCR5YM=", + "dev": true, + "requires": { + "@babel/types": "^7.12.13" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.13.16", + "resolved": "https://registry.nlark.com/@babel/helper-hoist-variables/download/@babel/helper-hoist-variables-7.13.16.tgz", + "integrity": "sha1-GxZRJJ6UtR+PDTNDmEPjPjl3WzA=", + "dev": true, + "requires": { + "@babel/traverse": "^7.13.15", + "@babel/types": "^7.13.16" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.13.12", + "resolved": "https://registry.npm.taobao.org/@babel/helper-member-expression-to-functions/download/@babel/helper-member-expression-to-functions-7.13.12.tgz?cache=0&sync_timestamp=1616428111276&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-member-expression-to-functions%2Fdownload%2F%40babel%2Fhelper-member-expression-to-functions-7.13.12.tgz", + "integrity": "sha1-3+No8m1CagcpnY1lE4IXaCFubXI=", + "dev": true, + "requires": { + "@babel/types": "^7.13.12" + } + }, + "@babel/helper-module-imports": { + "version": "7.13.12", + "resolved": "https://registry.nlark.com/@babel/helper-module-imports/download/@babel/helper-module-imports-7.13.12.tgz?cache=0&sync_timestamp=1618846791460&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fhelper-module-imports%2Fdownload%2F%40babel%2Fhelper-module-imports-7.13.12.tgz", + "integrity": "sha1-xqNppvNiHLJdoBQHhoTakZa2GXc=", + "dev": true, + "requires": { + "@babel/types": "^7.13.12" + } + }, + "@babel/helper-module-transforms": { + "version": "7.14.2", + "resolved": "https://registry.nlark.com/@babel/helper-module-transforms/download/@babel/helper-module-transforms-7.14.2.tgz?cache=0&sync_timestamp=1620839398699&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fhelper-module-transforms%2Fdownload%2F%40babel%2Fhelper-module-transforms-7.14.2.tgz", + "integrity": "sha1-rBzDDuR7lF4+DE2xL6DFOJUJ3+U=", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.13.12", + "@babel/helper-replace-supers": "^7.13.12", + "@babel/helper-simple-access": "^7.13.12", + "@babel/helper-split-export-declaration": "^7.12.13", + "@babel/helper-validator-identifier": "^7.14.0", + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.14.2", + "@babel/types": "^7.14.2" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.12.13", + "resolved": "https://registry.npm.taobao.org/@babel/helper-optimise-call-expression/download/@babel/helper-optimise-call-expression-7.12.13.tgz?cache=0&sync_timestamp=1612314687212&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-optimise-call-expression%2Fdownload%2F%40babel%2Fhelper-optimise-call-expression-7.12.13.tgz", + "integrity": "sha1-XALRcbTIYVsecWP4iMHIHDCiquo=", + "dev": true, + "requires": { + "@babel/types": "^7.12.13" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.13.0", + "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.13.0.tgz", + "integrity": "sha1-gGUmzhJa7QM3O8QWqCgyHjpqM68=", + "dev": true + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.13.0", + "resolved": "https://registry.nlark.com/@babel/helper-remap-async-to-generator/download/@babel/helper-remap-async-to-generator-7.13.0.tgz", + "integrity": "sha1-N2p2DZ97SyB3qd0Fqpw5J8rbIgk=", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.12.13", + "@babel/helper-wrap-function": "^7.13.0", + "@babel/types": "^7.13.0" + } + }, + "@babel/helper-replace-supers": { + "version": "7.14.4", + "resolved": "https://registry.nlark.com/@babel/helper-replace-supers/download/@babel/helper-replace-supers-7.14.4.tgz?cache=0&sync_timestamp=1622221254092&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fhelper-replace-supers%2Fdownload%2F%40babel%2Fhelper-replace-supers-7.14.4.tgz", + "integrity": "sha1-sqsWh13uz/89381Tm8MV9ymY2DY=", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.13.12", + "@babel/helper-optimise-call-expression": "^7.12.13", + "@babel/traverse": "^7.14.2", + "@babel/types": "^7.14.4" + } + }, + "@babel/helper-simple-access": { + "version": "7.13.12", + "resolved": "https://registry.npm.taobao.org/@babel/helper-simple-access/download/@babel/helper-simple-access-7.13.12.tgz?cache=0&sync_timestamp=1616428063009&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-simple-access%2Fdownload%2F%40babel%2Fhelper-simple-access-7.13.12.tgz", + "integrity": "sha1-3WxTivthgZ0gWgEsMXkqOcel6vY=", + "dev": true, + "requires": { + "@babel/types": "^7.13.12" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.12.1", + "resolved": "https://registry.npm.taobao.org/@babel/helper-skip-transparent-expression-wrappers/download/@babel/helper-skip-transparent-expression-wrappers-7.12.1.tgz", + "integrity": "sha1-Ri3GOn5DWt6EaDhcY9K4TM5LPL8=", + "dev": true, + "requires": { + "@babel/types": "^7.12.1" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.12.13", + "resolved": "https://registry.npm.taobao.org/@babel/helper-split-export-declaration/download/@babel/helper-split-export-declaration-7.12.13.tgz?cache=0&sync_timestamp=1612314686094&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-split-export-declaration%2Fdownload%2F%40babel%2Fhelper-split-export-declaration-7.12.13.tgz", + "integrity": "sha1-6UML4AuvPoiw4T5vnU6vITY3KwU=", + "dev": true, + "requires": { + "@babel/types": "^7.12.13" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.14.0", + "resolved": "https://registry.nlark.com/@babel/helper-validator-identifier/download/@babel/helper-validator-identifier-7.14.0.tgz?cache=0&sync_timestamp=1619727549370&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fhelper-validator-identifier%2Fdownload%2F%40babel%2Fhelper-validator-identifier-7.14.0.tgz", + "integrity": "sha1-0mytikfGUoaxXfFUcxml0Lzycog=" + }, + "@babel/helper-validator-option": { + "version": "7.12.17", + "resolved": "https://registry.npm.taobao.org/@babel/helper-validator-option/download/@babel/helper-validator-option-7.12.17.tgz", + "integrity": "sha1-0fvwEuGnm37rv9xtJwuq+NnrmDE=", + "dev": true + }, + "@babel/helper-wrap-function": { + "version": "7.13.0", + "resolved": "https://registry.npm.taobao.org/@babel/helper-wrap-function/download/@babel/helper-wrap-function-7.13.0.tgz?cache=0&sync_timestamp=1614034233760&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-wrap-function%2Fdownload%2F%40babel%2Fhelper-wrap-function-7.13.0.tgz", + "integrity": "sha1-vbXGb9qFJuwjWriUrVOhI1x5/MQ=", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.12.13", + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.13.0", + "@babel/types": "^7.13.0" + } + }, + "@babel/helpers": { + "version": "7.14.0", + "resolved": "https://registry.nlark.com/@babel/helpers/download/@babel/helpers-7.14.0.tgz?cache=0&sync_timestamp=1619727432208&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fhelpers%2Fdownload%2F%40babel%2Fhelpers-7.14.0.tgz", + "integrity": "sha1-6ptr6UeKE9b5Ydu182v3Xi87j2I=", + "dev": true, + "requires": { + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.14.0", + "@babel/types": "^7.14.0" + } + }, + "@babel/highlight": { + "version": "7.14.0", + "resolved": "https://registry.nlark.com/@babel/highlight/download/@babel/highlight-7.14.0.tgz?cache=0&sync_timestamp=1619727182056&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fhighlight%2Fdownload%2F%40babel%2Fhighlight-7.14.0.tgz", + "integrity": "sha1-MZfjdXEe9r+DTmfQ2uyI5PRhE88=", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.14.0", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.14.4", + "resolved": "https://registry.nlark.com/@babel/parser/download/@babel/parser-7.14.4.tgz", + "integrity": "sha1-pcVg1tts2ObtNCNo3qgDkjLLqxg=" + }, + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.13.12", + "resolved": "https://registry.npm.taobao.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/download/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.13.12.tgz", + "integrity": "sha1-o0hNhNC1SfP8kWuZ7keD8m+rrSo=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1", + "@babel/plugin-proposal-optional-chaining": "^7.13.12" + } + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.14.2", + "resolved": "https://registry.nlark.com/@babel/plugin-proposal-async-generator-functions/download/@babel/plugin-proposal-async-generator-functions-7.14.2.tgz?cache=0&sync_timestamp=1620839417583&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fplugin-proposal-async-generator-functions%2Fdownload%2F%40babel%2Fplugin-proposal-async-generator-functions-7.14.2.tgz", + "integrity": "sha1-OiCFq79dX5YtSA28gTRzhe1i6x4=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-remap-async-to-generator": "^7.13.0", + "@babel/plugin-syntax-async-generators": "^7.8.4" + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.13.0", + "resolved": "https://registry.npm.taobao.org/@babel/plugin-proposal-class-properties/download/@babel/plugin-proposal-class-properties-7.13.0.tgz?cache=0&sync_timestamp=1614035098704&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-proposal-class-properties%2Fdownload%2F%40babel%2Fplugin-proposal-class-properties-7.13.0.tgz", + "integrity": "sha1-FGN2AAuU79AB5XpAqIpSWvqrnzc=", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.13.0", + "@babel/helper-plugin-utils": "^7.13.0" + } + }, + "@babel/plugin-proposal-class-static-block": { + "version": "7.14.3", + "resolved": "https://registry.nlark.com/@babel/plugin-proposal-class-static-block/download/@babel/plugin-proposal-class-static-block-7.14.3.tgz", + "integrity": "sha1-WlJ+LK5KR1MRnDo+f2TsrozPE2A=", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.14.3", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-class-static-block": "^7.12.13" + } + }, + "@babel/plugin-proposal-decorators": { + "version": "7.14.2", + "resolved": "https://registry.nlark.com/@babel/plugin-proposal-decorators/download/@babel/plugin-proposal-decorators-7.14.2.tgz?cache=0&sync_timestamp=1620839996248&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fplugin-proposal-decorators%2Fdownload%2F%40babel%2Fplugin-proposal-decorators-7.14.2.tgz", + "integrity": "sha1-5ow8XkpqCINEVlaCVvw+cbk1kM8=", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.14.2", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-decorators": "^7.12.13" + } + }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.14.2", + "resolved": "https://registry.nlark.com/@babel/plugin-proposal-dynamic-import/download/@babel/plugin-proposal-dynamic-import-7.14.2.tgz", + "integrity": "sha1-Aeur18OBz/Ix+kPjApOaneW+nZ8=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + } + }, + "@babel/plugin-proposal-export-namespace-from": { + "version": "7.14.2", + "resolved": "https://registry.nlark.com/@babel/plugin-proposal-export-namespace-from/download/@babel/plugin-proposal-export-namespace-from-7.14.2.tgz", + "integrity": "sha1-YlQvlKqc6Pbbp57saYryIRIlN5E=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.14.2", + "resolved": "https://registry.nlark.com/@babel/plugin-proposal-json-strings/download/@babel/plugin-proposal-json-strings-7.14.2.tgz?cache=0&sync_timestamp=1620840046817&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fplugin-proposal-json-strings%2Fdownload%2F%40babel%2Fplugin-proposal-json-strings-7.14.2.tgz", + "integrity": "sha1-gwtOJCanguiyh4+/4suoW3DL+Yw=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-json-strings": "^7.8.3" + } + }, + "@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.14.2", + "resolved": "https://registry.nlark.com/@babel/plugin-proposal-logical-assignment-operators/download/@babel/plugin-proposal-logical-assignment-operators-7.14.2.tgz", + "integrity": "sha1-IiNIwIChZ44OdOpj/nbydYgtH9c=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.14.2", + "resolved": "https://registry.nlark.com/@babel/plugin-proposal-nullish-coalescing-operator/download/@babel/plugin-proposal-nullish-coalescing-operator-7.14.2.tgz", + "integrity": "sha1-QlsR3GL8JpOaKrQsu6aAvfVzRUY=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.14.2", + "resolved": "https://registry.nlark.com/@babel/plugin-proposal-numeric-separator/download/@babel/plugin-proposal-numeric-separator-7.14.2.tgz?cache=0&sync_timestamp=1620839422175&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fplugin-proposal-numeric-separator%2Fdownload%2F%40babel%2Fplugin-proposal-numeric-separator-7.14.2.tgz", + "integrity": "sha1-grTMBlcRQ/r1BiYQSzNd1xuqT54=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.14.4", + "resolved": "https://registry.nlark.com/@babel/plugin-proposal-object-rest-spread/download/@babel/plugin-proposal-object-rest-spread-7.14.4.tgz?cache=0&sync_timestamp=1622221269189&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fplugin-proposal-object-rest-spread%2Fdownload%2F%40babel%2Fplugin-proposal-object-rest-spread-7.14.4.tgz", + "integrity": "sha1-DitN5BmRXcC0CTeOgpQS4gMXd8Q=", + "dev": true, + "requires": { + "@babel/compat-data": "^7.14.4", + "@babel/helper-compilation-targets": "^7.14.4", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.14.2" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.14.2", + "resolved": "https://registry.nlark.com/@babel/plugin-proposal-optional-catch-binding/download/@babel/plugin-proposal-optional-catch-binding-7.14.2.tgz", + "integrity": "sha1-FQ1OWOUlsWqaFDG9UybE7thw1xc=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.14.2", + "resolved": "https://registry.nlark.com/@babel/plugin-proposal-optional-chaining/download/@babel/plugin-proposal-optional-chaining-7.14.2.tgz?cache=0&sync_timestamp=1620839998724&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fplugin-proposal-optional-chaining%2Fdownload%2F%40babel%2Fplugin-proposal-optional-chaining-7.14.2.tgz", + "integrity": "sha1-34FxqLnEPr9MHavmMRtDLYPhs04=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + } + }, + "@babel/plugin-proposal-private-methods": { + "version": "7.13.0", + "resolved": "https://registry.npm.taobao.org/@babel/plugin-proposal-private-methods/download/@babel/plugin-proposal-private-methods-7.13.0.tgz?cache=0&sync_timestamp=1614035100398&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-proposal-private-methods%2Fdownload%2F%40babel%2Fplugin-proposal-private-methods-7.13.0.tgz", + "integrity": "sha1-BL1MbUD25rv6L1fi2AlLrZAO94c=", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.13.0", + "@babel/helper-plugin-utils": "^7.13.0" + } + }, + "@babel/plugin-proposal-private-property-in-object": { + "version": "7.14.0", + "resolved": "https://registry.nlark.com/@babel/plugin-proposal-private-property-in-object/download/@babel/plugin-proposal-private-property-in-object-7.14.0.tgz?cache=0&sync_timestamp=1619727655656&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fplugin-proposal-private-property-in-object%2Fdownload%2F%40babel%2Fplugin-proposal-private-property-in-object-7.14.0.tgz", + "integrity": "sha1-saHyAwWGudNInMJhedLrWIMndjY=", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.12.13", + "@babel/helper-create-class-features-plugin": "^7.14.0", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-private-property-in-object": "^7.14.0" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.12.13", + "resolved": "https://registry.npm.taobao.org/@babel/plugin-proposal-unicode-property-regex/download/@babel/plugin-proposal-unicode-property-regex-7.12.13.tgz", + "integrity": "sha1-vr3lEzm+gpwXqqrO0YZB3rYrObo=", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.12.13", + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-async-generators/download/@babel/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha1-qYP7Gusuw/btBCohD2QOkOeG/g0=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-class-properties/download/@babel/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha1-tcmHJ0xKOoK4lxR5aTGmtTVErhA=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-class-static-block": { + "version": "7.12.13", + "resolved": "https://registry.nlark.com/@babel/plugin-syntax-class-static-block/download/@babel/plugin-syntax-class-static-block-7.12.13.tgz?cache=0&sync_timestamp=1619727671263&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fplugin-syntax-class-static-block%2Fdownload%2F%40babel%2Fplugin-syntax-class-static-block-7.12.13.tgz", + "integrity": "sha1-jj1nSwYT5nl1zqwndsl7YMr8XJw=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-decorators": { + "version": "7.12.13", + "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-decorators/download/@babel/plugin-syntax-decorators-7.12.13.tgz?cache=0&sync_timestamp=1612314725413&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-syntax-decorators%2Fdownload%2F%40babel%2Fplugin-syntax-decorators-7.12.13.tgz", + "integrity": "sha1-+sgpvzx+9KG8kWJXtAPljGva9kg=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-dynamic-import/download/@babel/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha1-Yr+Ysto80h1iYVT8lu5bPLaOrLM=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-export-namespace-from/download/@babel/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha1-AolkqbqA28CUyRXEh618TnpmRlo=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-json-strings/download/@babel/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha1-AcohtmjNghjJ5kDLbdiMVBKyyWo=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-jsx": { + "version": "7.12.13", + "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-jsx/download/@babel/plugin-syntax-jsx-7.12.13.tgz", + "integrity": "sha1-BE+4HrrWaY/mLEeIdVdby7m3DxU=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.nlark.com/@babel/plugin-syntax-logical-assignment-operators/download/@babel/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha1-ypHvRjA1MESLkGZSusLp/plB9pk=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.nlark.com/@babel/plugin-syntax-nullish-coalescing-operator/download/@babel/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha1-Fn7XA2iIYIH3S1w2xlqIwDtm0ak=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-numeric-separator/download/@babel/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha1-ubBws+M1cM2f0Hun+pHA3Te5r5c=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-object-rest-spread/download/@babel/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha1-YOIl7cvZimQDMqLnLdPmbxr1WHE=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-optional-catch-binding/download/@babel/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha1-YRGiZbz7Ag6579D9/X0mQCue1sE=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.nlark.com/@babel/plugin-syntax-optional-chaining/download/@babel/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha1-T2nCq5UWfgGAzVM2YT+MV4j31Io=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.0", + "resolved": "https://registry.nlark.com/@babel/plugin-syntax-private-property-in-object/download/@babel/plugin-syntax-private-property-in-object-7.14.0.tgz", + "integrity": "sha1-dipLq+xhF2/sbIhIDexANysUDAs=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.12.13", + "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-top-level-await/download/@babel/plugin-syntax-top-level-await-7.12.13.tgz", + "integrity": "sha1-xfD6biSfW3OXJ/kjVAz3qAYTAXg=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.13.0", + "resolved": "https://registry.nlark.com/@babel/plugin-transform-arrow-functions/download/@babel/plugin-transform-arrow-functions-7.13.0.tgz", + "integrity": "sha1-EKWb661S1jegJ6+mkujVzv9ePa4=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.13.0", + "resolved": "https://registry.nlark.com/@babel/plugin-transform-async-to-generator/download/@babel/plugin-transform-async-to-generator-7.13.0.tgz", + "integrity": "sha1-jhEr9ncbgr8el05eJoBsXJmqUW8=", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.12.13", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-remap-async-to-generator": "^7.13.0" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.12.13", + "resolved": "https://registry.nlark.com/@babel/plugin-transform-block-scoped-functions/download/@babel/plugin-transform-block-scoped-functions-7.12.13.tgz", + "integrity": "sha1-qb8YNvKjm062zwmWdzneKepL9MQ=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.14.4", + "resolved": "https://registry.nlark.com/@babel/plugin-transform-block-scoping/download/@babel/plugin-transform-block-scoping-7.14.4.tgz?cache=0&sync_timestamp=1622221249143&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fplugin-transform-block-scoping%2Fdownload%2F%40babel%2Fplugin-transform-block-scoping-7.14.4.tgz", + "integrity": "sha1-yvFAsLLiRixQlVPRQObQq++2Htg=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.14.4", + "resolved": "https://registry.nlark.com/@babel/plugin-transform-classes/download/@babel/plugin-transform-classes-7.14.4.tgz", + "integrity": "sha1-qDwVUD/HGg+Z6Hb9zn2tvGV17Do=", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.12.13", + "@babel/helper-function-name": "^7.14.2", + "@babel/helper-optimise-call-expression": "^7.12.13", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-replace-supers": "^7.14.4", + "@babel/helper-split-export-declaration": "^7.12.13", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.13.0", + "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-computed-properties/download/@babel/plugin-transform-computed-properties-7.13.0.tgz?cache=0&sync_timestamp=1614034212505&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-computed-properties%2Fdownload%2F%40babel%2Fplugin-transform-computed-properties-7.13.0.tgz", + "integrity": "sha1-hFxui5u1U3ax+guS7wvcjqBmRO0=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.14.4", + "resolved": "https://registry.nlark.com/@babel/plugin-transform-destructuring/download/@babel/plugin-transform-destructuring-7.14.4.tgz", + "integrity": "sha1-rL7FAumVHzD0RB6sodLynvreWe0=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.12.13", + "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-dotall-regex/download/@babel/plugin-transform-dotall-regex-7.12.13.tgz", + "integrity": "sha1-PxYBzCmQW/y2f1ORDxl66v67Ja0=", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.12.13", + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.12.13", + "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-duplicate-keys/download/@babel/plugin-transform-duplicate-keys-7.12.13.tgz?cache=0&sync_timestamp=1612314817333&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-duplicate-keys%2Fdownload%2F%40babel%2Fplugin-transform-duplicate-keys-7.12.13.tgz", + "integrity": "sha1-bwa4eouAP9ko5UuBwljwoAM5BN4=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.12.13", + "resolved": "https://registry.nlark.com/@babel/plugin-transform-exponentiation-operator/download/@babel/plugin-transform-exponentiation-operator-7.12.13.tgz", + "integrity": "sha1-TVI5C5onPmUeSrpq7knvQOgM0KE=", + "dev": true, + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.12.13", + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.13.0", + "resolved": "https://registry.nlark.com/@babel/plugin-transform-for-of/download/@babel/plugin-transform-for-of-7.13.0.tgz", + "integrity": "sha1-x5n4gagJGsJrVIZ6hFw+l9JpYGI=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.12.13", + "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-function-name/download/@babel/plugin-transform-function-name-7.12.13.tgz", + "integrity": "sha1-uwJEUvmq7YYdN0yOeiQlLOOlAFE=", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.12.13", + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.12.13", + "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-literals/download/@babel/plugin-transform-literals-7.12.13.tgz?cache=0&sync_timestamp=1612314818038&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-literals%2Fdownload%2F%40babel%2Fplugin-transform-literals-7.12.13.tgz", + "integrity": "sha1-LKRbr+SoIBl88xV5Sk0mVg/kvbk=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.12.13", + "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-member-expression-literals/download/@babel/plugin-transform-member-expression-literals-7.12.13.tgz?cache=0&sync_timestamp=1612314834575&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-member-expression-literals%2Fdownload%2F%40babel%2Fplugin-transform-member-expression-literals-7.12.13.tgz", + "integrity": "sha1-X/pmzVm54ZExTJ8fgDuTjowIHkA=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.14.2", + "resolved": "https://registry.nlark.com/@babel/plugin-transform-modules-amd/download/@babel/plugin-transform-modules-amd-7.14.2.tgz", + "integrity": "sha1-ZiKAb+GnwHoTiERCIu+VNfLKF7A=", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.14.2", + "@babel/helper-plugin-utils": "^7.13.0", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.14.0", + "resolved": "https://registry.nlark.com/@babel/plugin-transform-modules-commonjs/download/@babel/plugin-transform-modules-commonjs-7.14.0.tgz?cache=0&sync_timestamp=1619727184331&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fplugin-transform-modules-commonjs%2Fdownload%2F%40babel%2Fplugin-transform-modules-commonjs-7.14.0.tgz", + "integrity": "sha1-UrwZnLWB4Jku26Dw+ANWRnWH8WE=", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.14.0", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-simple-access": "^7.13.12", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.13.8", + "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-modules-systemjs/download/@babel/plugin-transform-modules-systemjs-7.13.8.tgz?cache=0&sync_timestamp=1614382839114&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-modules-systemjs%2Fdownload%2F%40babel%2Fplugin-transform-modules-systemjs-7.13.8.tgz", + "integrity": "sha1-bQZu4r/zx7PWC/KN7Baa2ZODGuM=", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.13.0", + "@babel/helper-module-transforms": "^7.13.0", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-validator-identifier": "^7.12.11", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.14.0", + "resolved": "https://registry.nlark.com/@babel/plugin-transform-modules-umd/download/@babel/plugin-transform-modules-umd-7.14.0.tgz?cache=0&sync_timestamp=1619727183056&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fplugin-transform-modules-umd%2Fdownload%2F%40babel%2Fplugin-transform-modules-umd-7.14.0.tgz", + "integrity": "sha1-L4F50bvJJjZlzkpl8wVSay6orDQ=", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.14.0", + "@babel/helper-plugin-utils": "^7.13.0" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.12.13", + "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-named-capturing-groups-regex/download/@babel/plugin-transform-named-capturing-groups-regex-7.12.13.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-named-capturing-groups-regex%2Fdownload%2F%40babel%2Fplugin-transform-named-capturing-groups-regex-7.12.13.tgz", + "integrity": "sha1-IhNyWl9bu+NktQw7pZmMlZnFydk=", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.12.13" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.12.13", + "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-new-target/download/@babel/plugin-transform-new-target-7.12.13.tgz?cache=0&sync_timestamp=1612314816557&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-new-target%2Fdownload%2F%40babel%2Fplugin-transform-new-target-7.12.13.tgz", + "integrity": "sha1-4i2MOvJLFQ3VKMvW5oXnmb8cNRw=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.12.13", + "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-object-super/download/@babel/plugin-transform-object-super-7.12.13.tgz?cache=0&sync_timestamp=1612314795746&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-object-super%2Fdownload%2F%40babel%2Fplugin-transform-object-super-7.12.13.tgz", + "integrity": "sha1-tEFqLWO4974xTz00m9VanBtRcfc=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13", + "@babel/helper-replace-supers": "^7.12.13" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.14.2", + "resolved": "https://registry.nlark.com/@babel/plugin-transform-parameters/download/@babel/plugin-transform-parameters-7.14.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fplugin-transform-parameters%2Fdownload%2F%40babel%2Fplugin-transform-parameters-7.14.2.tgz", + "integrity": "sha1-5CkPcuDp6DEADQZkJ8RmcJjezDE=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.12.13", + "resolved": "https://registry.nlark.com/@babel/plugin-transform-property-literals/download/@babel/plugin-transform-property-literals-7.12.13.tgz", + "integrity": "sha1-TmqeN4ZNjxs7wOLc57+IV9uLGoE=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.13.15", + "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-regenerator/download/@babel/plugin-transform-regenerator-7.13.15.tgz", + "integrity": "sha1-5esolFv4tlY+f4GJRflmqNKZfzk=", + "dev": true, + "requires": { + "regenerator-transform": "^0.14.2" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.12.13", + "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-reserved-words/download/@babel/plugin-transform-reserved-words-7.12.13.tgz?cache=0&sync_timestamp=1612314845661&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-reserved-words%2Fdownload%2F%40babel%2Fplugin-transform-reserved-words-7.12.13.tgz", + "integrity": "sha1-fZmI1PBuD+aX6h2YAxiKoYtHJpU=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-runtime": { + "version": "7.14.3", + "resolved": "https://registry.nlark.com/@babel/plugin-transform-runtime/download/@babel/plugin-transform-runtime-7.14.3.tgz?cache=0&sync_timestamp=1621284741103&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fplugin-transform-runtime%2Fdownload%2F%40babel%2Fplugin-transform-runtime-7.14.3.tgz", + "integrity": "sha1-H9iFotDeHTwiN5Wk6b5ywttFFc8=", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.13.12", + "@babel/helper-plugin-utils": "^7.13.0", + "babel-plugin-polyfill-corejs2": "^0.2.0", + "babel-plugin-polyfill-corejs3": "^0.2.0", + "babel-plugin-polyfill-regenerator": "^0.2.0", + "semver": "^6.3.0" + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.12.13", + "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-shorthand-properties/download/@babel/plugin-transform-shorthand-properties-7.12.13.tgz?cache=0&sync_timestamp=1612314820265&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-shorthand-properties%2Fdownload%2F%40babel%2Fplugin-transform-shorthand-properties-7.12.13.tgz", + "integrity": "sha1-23VXMrcMU51QTGOQ2c6Q/mSv960=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.13.0", + "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-spread/download/@babel/plugin-transform-spread-7.13.0.tgz?cache=0&sync_timestamp=1614034217488&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-spread%2Fdownload%2F%40babel%2Fplugin-transform-spread-7.13.0.tgz", + "integrity": "sha1-hIh3EOJzwYFaznrkWfb0Kl0x1f0=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.12.13", + "resolved": "https://registry.nlark.com/@babel/plugin-transform-sticky-regex/download/@babel/plugin-transform-sticky-regex-7.12.13.tgz", + "integrity": "sha1-dg/9k2+s5z+GCuZG+4bugvPQbR8=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.13.0", + "resolved": "https://registry.nlark.com/@babel/plugin-transform-template-literals/download/@babel/plugin-transform-template-literals-7.13.0.tgz", + "integrity": "sha1-o2BJEnl3rZRDje50Q1mNHO/fQJ0=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.12.13", + "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-typeof-symbol/download/@babel/plugin-transform-typeof-symbol-7.12.13.tgz?cache=0&sync_timestamp=1612314820235&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-typeof-symbol%2Fdownload%2F%40babel%2Fplugin-transform-typeof-symbol-7.12.13.tgz", + "integrity": "sha1-eF3Weh8upXnZwr5yLejITLhfWn8=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.12.13", + "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-unicode-escapes/download/@babel/plugin-transform-unicode-escapes-7.12.13.tgz?cache=0&sync_timestamp=1612314845292&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-unicode-escapes%2Fdownload%2F%40babel%2Fplugin-transform-unicode-escapes-7.12.13.tgz", + "integrity": "sha1-hAztO4FtO1En3R0S3O3F3q0aXnQ=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.12.13", + "resolved": "https://registry.nlark.com/@babel/plugin-transform-unicode-regex/download/@babel/plugin-transform-unicode-regex-7.12.13.tgz", + "integrity": "sha1-tSUhaFgE4VWxIC6D/BiNNLtw9aw=", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.12.13", + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/preset-env": { + "version": "7.14.4", + "resolved": "https://registry.nlark.com/@babel/preset-env/download/@babel/preset-env-7.14.4.tgz?cache=0&sync_timestamp=1622222650513&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fpreset-env%2Fdownload%2F%40babel%2Fpreset-env-7.14.4.tgz", + "integrity": "sha1-c/wyKMWXJ+XpdDGRVvME8NZoWi0=", + "dev": true, + "requires": { + "@babel/compat-data": "^7.14.4", + "@babel/helper-compilation-targets": "^7.14.4", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-validator-option": "^7.12.17", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.13.12", + "@babel/plugin-proposal-async-generator-functions": "^7.14.2", + "@babel/plugin-proposal-class-properties": "^7.13.0", + "@babel/plugin-proposal-class-static-block": "^7.14.3", + "@babel/plugin-proposal-dynamic-import": "^7.14.2", + "@babel/plugin-proposal-export-namespace-from": "^7.14.2", + "@babel/plugin-proposal-json-strings": "^7.14.2", + "@babel/plugin-proposal-logical-assignment-operators": "^7.14.2", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.14.2", + "@babel/plugin-proposal-numeric-separator": "^7.14.2", + "@babel/plugin-proposal-object-rest-spread": "^7.14.4", + "@babel/plugin-proposal-optional-catch-binding": "^7.14.2", + "@babel/plugin-proposal-optional-chaining": "^7.14.2", + "@babel/plugin-proposal-private-methods": "^7.13.0", + "@babel/plugin-proposal-private-property-in-object": "^7.14.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.12.13", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.12.13", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.0", + "@babel/plugin-syntax-top-level-await": "^7.12.13", + "@babel/plugin-transform-arrow-functions": "^7.13.0", + "@babel/plugin-transform-async-to-generator": "^7.13.0", + "@babel/plugin-transform-block-scoped-functions": "^7.12.13", + "@babel/plugin-transform-block-scoping": "^7.14.4", + "@babel/plugin-transform-classes": "^7.14.4", + "@babel/plugin-transform-computed-properties": "^7.13.0", + "@babel/plugin-transform-destructuring": "^7.14.4", + "@babel/plugin-transform-dotall-regex": "^7.12.13", + "@babel/plugin-transform-duplicate-keys": "^7.12.13", + "@babel/plugin-transform-exponentiation-operator": "^7.12.13", + "@babel/plugin-transform-for-of": "^7.13.0", + "@babel/plugin-transform-function-name": "^7.12.13", + "@babel/plugin-transform-literals": "^7.12.13", + "@babel/plugin-transform-member-expression-literals": "^7.12.13", + "@babel/plugin-transform-modules-amd": "^7.14.2", + "@babel/plugin-transform-modules-commonjs": "^7.14.0", + "@babel/plugin-transform-modules-systemjs": "^7.13.8", + "@babel/plugin-transform-modules-umd": "^7.14.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.12.13", + "@babel/plugin-transform-new-target": "^7.12.13", + "@babel/plugin-transform-object-super": "^7.12.13", + "@babel/plugin-transform-parameters": "^7.14.2", + "@babel/plugin-transform-property-literals": "^7.12.13", + "@babel/plugin-transform-regenerator": "^7.13.15", + "@babel/plugin-transform-reserved-words": "^7.12.13", + "@babel/plugin-transform-shorthand-properties": "^7.12.13", + "@babel/plugin-transform-spread": "^7.13.0", + "@babel/plugin-transform-sticky-regex": "^7.12.13", + "@babel/plugin-transform-template-literals": "^7.13.0", + "@babel/plugin-transform-typeof-symbol": "^7.12.13", + "@babel/plugin-transform-unicode-escapes": "^7.12.13", + "@babel/plugin-transform-unicode-regex": "^7.12.13", + "@babel/preset-modules": "^0.1.4", + "@babel/types": "^7.14.4", + "babel-plugin-polyfill-corejs2": "^0.2.0", + "babel-plugin-polyfill-corejs3": "^0.2.0", + "babel-plugin-polyfill-regenerator": "^0.2.0", + "core-js-compat": "^3.9.0", + "semver": "^6.3.0" + } + }, + "@babel/preset-modules": { + "version": "0.1.4", + "resolved": "https://registry.npm.taobao.org/@babel/preset-modules/download/@babel/preset-modules-0.1.4.tgz", + "integrity": "sha1-Ni8raMZihClw/bXiVP/I/BwuQV4=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + } + }, + "@babel/runtime": { + "version": "7.14.0", + "resolved": "https://registry.nlark.com/@babel/runtime/download/@babel/runtime-7.14.0.tgz?cache=0&sync_timestamp=1619727414495&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fruntime%2Fdownload%2F%40babel%2Fruntime-7.14.0.tgz", + "integrity": "sha1-RnlLwgthLF915i3QceJN/ZXxy+Y=", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/template": { + "version": "7.12.13", + "resolved": "https://registry.npm.taobao.org/@babel/template/download/@babel/template-7.12.13.tgz", + "integrity": "sha1-UwJlvooliduzdSOETFvLVZR/syc=", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@babel/parser": "^7.12.13", + "@babel/types": "^7.12.13" + } + }, + "@babel/traverse": { + "version": "7.14.2", + "resolved": "https://registry.nlark.com/@babel/traverse/download/@babel/traverse-7.14.2.tgz?cache=0&sync_timestamp=1620839391311&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Ftraverse%2Fdownload%2F%40babel%2Ftraverse-7.14.2.tgz", + "integrity": "sha1-kgGo2RJyOoMcJnnH678v4UFtdls=", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@babel/generator": "^7.14.2", + "@babel/helper-function-name": "^7.14.2", + "@babel/helper-split-export-declaration": "^7.12.13", + "@babel/parser": "^7.14.2", + "@babel/types": "^7.14.2", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.14.4", + "resolved": "https://registry.nlark.com/@babel/types/download/@babel/types-7.14.4.tgz?cache=0&sync_timestamp=1622221256190&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Ftypes%2Fdownload%2F%40babel%2Ftypes-7.14.4.tgz", + "integrity": "sha1-v9aYAQgWhZOziz60iiSqAmuRm8A=", + "requires": { + "@babel/helper-validator-identifier": "^7.14.0", + "to-fast-properties": "^2.0.0" + } + }, + "@hapi/address": { + "version": "2.1.4", + "resolved": "https://registry.nlark.com/@hapi/address/download/@hapi/address-2.1.4.tgz", + "integrity": "sha1-XWftQ/P9QaadS5/3tW58DR0KgeU=", + "dev": true + }, + "@hapi/bourne": { + "version": "1.3.2", + "resolved": "https://registry.nlark.com/@hapi/bourne/download/@hapi/bourne-1.3.2.tgz", + "integrity": "sha1-CnCVreoGckPOMoPhtWuKj0U7JCo=", + "dev": true + }, + "@hapi/hoek": { + "version": "8.5.1", + "resolved": "https://registry.nlark.com/@hapi/hoek/download/@hapi/hoek-8.5.1.tgz", + "integrity": "sha1-/elgZMpEbeyMVajC8TCVewcMbgY=", + "dev": true + }, + "@hapi/joi": { + "version": "15.1.1", + "resolved": "https://registry.npm.taobao.org/@hapi/joi/download/@hapi/joi-15.1.1.tgz?cache=0&sync_timestamp=1615984328397&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40hapi%2Fjoi%2Fdownload%2F%40hapi%2Fjoi-15.1.1.tgz", + "integrity": "sha1-xnW4pxKW8Cgz+NbSQ7NMV7jOGdc=", + "dev": true, + "requires": { + "@hapi/address": "2.x.x", + "@hapi/bourne": "1.x.x", + "@hapi/hoek": "8.x.x", + "@hapi/topo": "3.x.x" + } + }, + "@hapi/topo": { + "version": "3.1.6", + "resolved": "https://registry.npm.taobao.org/@hapi/topo/download/@hapi/topo-3.1.6.tgz", + "integrity": "sha1-aNk1+j6uf91asNf5U/MgXYsr/Ck=", + "dev": true, + "requires": { + "@hapi/hoek": "^8.3.0" + } + }, + "@intervolga/optimize-cssnano-plugin": { + "version": "1.0.6", + "resolved": "https://registry.npm.taobao.org/@intervolga/optimize-cssnano-plugin/download/@intervolga/optimize-cssnano-plugin-1.0.6.tgz", + "integrity": "sha1-vnx4RhKLiPapsdEmGgrQbrXA/fg=", + "dev": true, + "requires": { + "cssnano": "^4.0.0", + "cssnano-preset-default": "^4.0.0", + "postcss": "^7.0.0" + } + }, + "@mrmlnc/readdir-enhanced": { + "version": "2.2.1", + "resolved": "https://registry.npm.taobao.org/@mrmlnc/readdir-enhanced/download/@mrmlnc/readdir-enhanced-2.2.1.tgz", + "integrity": "sha1-UkryQNGjYFJ7cwR17PoTRKpUDd4=", + "dev": true, + "requires": { + "call-me-maybe": "^1.0.1", + "glob-to-regexp": "^0.3.0" + } + }, + "@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.nlark.com/@nodelib/fs.stat/download/@nodelib/fs.stat-1.1.3.tgz", + "integrity": "sha1-K1o6s/kYzKSKjHVMCBaOPwPrphs=", + "dev": true + }, + "@soda/friendly-errors-webpack-plugin": { + "version": "1.8.0", + "resolved": "https://registry.npm.taobao.org/@soda/friendly-errors-webpack-plugin/download/@soda/friendly-errors-webpack-plugin-1.8.0.tgz?cache=0&sync_timestamp=1607927438775&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40soda%2Ffriendly-errors-webpack-plugin%2Fdownload%2F%40soda%2Ffriendly-errors-webpack-plugin-1.8.0.tgz", + "integrity": "sha1-hHUdgqkwGdXJLAzw5FrFkIfNIkA=", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "error-stack-parser": "^2.0.2", + "string-width": "^2.0.0", + "strip-ansi": "^5" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.nlark.com/ansi-regex/download/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-2.0.0.tgz?cache=0&sync_timestamp=1618552489864&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-fullwidth-code-point%2Fdownload%2Fis-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.nlark.com/string-width/download/string-width-2.1.1.tgz", + "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-4.0.0.tgz?cache=0&sync_timestamp=1618553320591&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-5.2.0.tgz?cache=0&sync_timestamp=1618553320591&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-5.2.0.tgz", + "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.nlark.com/ansi-regex/download/ansi-regex-4.1.0.tgz", + "integrity": "sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc=", + "dev": true + } + } + } + } + }, + "@soda/get-current-script": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/@soda/get-current-script/download/@soda/get-current-script-1.0.2.tgz", + "integrity": "sha1-pTUV2yXYA4N0OBtzryC7Ty5QjYc=", + "dev": true + }, + "@types/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.nlark.com/@types/body-parser/download/@types/body-parser-1.19.0.tgz?cache=0&sync_timestamp=1621240602575&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fbody-parser%2Fdownload%2F%40types%2Fbody-parser-1.19.0.tgz", + "integrity": "sha1-BoWzxH6zAG/+0RfN1VFkth+AU48=", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.34", + "resolved": "https://registry.nlark.com/@types/connect/download/@types/connect-3.4.34.tgz", + "integrity": "sha1-FwpAIjptZmAG2TyhKK8r6x2bGQE=", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/connect-history-api-fallback": { + "version": "1.3.4", + "resolved": "https://registry.nlark.com/@types/connect-history-api-fallback/download/@types/connect-history-api-fallback-1.3.4.tgz?cache=0&sync_timestamp=1621240807633&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fconnect-history-api-fallback%2Fdownload%2F%40types%2Fconnect-history-api-fallback-1.3.4.tgz", + "integrity": "sha1-jA8Obl2CUraZ9aZi9Rvfgv2di7g=", + "dev": true, + "requires": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "@types/express": { + "version": "4.17.12", + "resolved": "https://registry.nlark.com/@types/express/download/@types/express-4.17.12.tgz?cache=0&sync_timestamp=1621962565565&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fexpress%2Fdownload%2F%40types%2Fexpress-4.17.12.tgz", + "integrity": "sha1-S8G/PNDP5tP28oU2SLQNt9VN41A=", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.20", + "resolved": "https://registry.nlark.com/@types/express-serve-static-core/download/@types/express-serve-static-core-4.17.20.tgz?cache=0&sync_timestamp=1621962788076&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fexpress-serve-static-core%2Fdownload%2F%40types%2Fexpress-serve-static-core-4.17.20.tgz", + "integrity": "sha1-RMruAp8sJsRnEdpehFzcEhZ61y0=", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "@types/glob": { + "version": "7.1.3", + "resolved": "https://registry.nlark.com/@types/glob/download/@types/glob-7.1.3.tgz", + "integrity": "sha1-5rqA82t9qtLGhazZJmOC5omFwYM=", + "dev": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/http-proxy": { + "version": "1.17.6", + "resolved": "https://registry.nlark.com/@types/http-proxy/download/@types/http-proxy-1.17.6.tgz", + "integrity": "sha1-Ytw/reIn1qwoYsjxnuDanan9hhY=", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/json-schema": { + "version": "7.0.7", + "resolved": "https://registry.nlark.com/@types/json-schema/download/@types/json-schema-7.0.7.tgz", + "integrity": "sha1-mKmTUWyFnrDVxMjwmDF6nqaNua0=", + "dev": true + }, + "@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.nlark.com/@types/mime/download/@types/mime-1.3.2.tgz", + "integrity": "sha1-k+Jb+e51/g/YC1lLxP6w6GIRG1o=", + "dev": true + }, + "@types/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.nlark.com/@types/minimatch/download/@types/minimatch-3.0.4.tgz?cache=0&sync_timestamp=1621241982882&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fminimatch%2Fdownload%2F%40types%2Fminimatch-3.0.4.tgz", + "integrity": "sha1-8Owl2/Lw5LGGRzE6wDETTKWySyE=", + "dev": true + }, + "@types/minimist": { + "version": "1.2.1", + "resolved": "https://registry.nlark.com/@types/minimist/download/@types/minimist-1.2.1.tgz?cache=0&sync_timestamp=1621241867849&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fminimist%2Fdownload%2F%40types%2Fminimist-1.2.1.tgz", + "integrity": "sha1-KD9mn/dte4Jg34q3pCYsyD2YglY=", + "dev": true + }, + "@types/node": { + "version": "15.6.1", + "resolved": "https://registry.nlark.com/@types/node/download/@types/node-15.6.1.tgz?cache=0&sync_timestamp=1621901244878&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fnode%2Fdownload%2F%40types%2Fnode-15.6.1.tgz", + "integrity": "sha1-MtQzkNXGLFtuxIapvJxZVE3jmgg=", + "dev": true + }, + "@types/normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.nlark.com/@types/normalize-package-data/download/@types/normalize-package-data-2.4.0.tgz?cache=0&sync_timestamp=1621242064742&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fnormalize-package-data%2Fdownload%2F%40types%2Fnormalize-package-data-2.4.0.tgz", + "integrity": "sha1-5IbQ2XOW15vu3QpuM/RTT/a0lz4=", + "dev": true + }, + "@types/q": { + "version": "1.5.4", + "resolved": "https://registry.nlark.com/@types/q/download/@types/q-1.5.4.tgz?cache=0&sync_timestamp=1621242400776&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fq%2Fdownload%2F%40types%2Fq-1.5.4.tgz", + "integrity": "sha1-FZJUFOCtLNdlv+9YhC9+JqesyyQ=", + "dev": true + }, + "@types/qs": { + "version": "6.9.6", + "resolved": "https://registry.nlark.com/@types/qs/download/@types/qs-6.9.6.tgz?cache=0&sync_timestamp=1621242292262&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fqs%2Fdownload%2F%40types%2Fqs-6.9.6.tgz", + "integrity": "sha1-35w8izGiR+wxXmmWVmvjFx30s7E=", + "dev": true + }, + "@types/range-parser": { + "version": "1.2.3", + "resolved": "https://registry.nlark.com/@types/range-parser/download/@types/range-parser-1.2.3.tgz?cache=0&sync_timestamp=1621242291785&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Frange-parser%2Fdownload%2F%40types%2Frange-parser-1.2.3.tgz", + "integrity": "sha1-fuMwunyq+5gJC+zoal7kQRWQTCw=", + "dev": true + }, + "@types/serve-static": { + "version": "1.13.9", + "resolved": "https://registry.nlark.com/@types/serve-static/download/@types/serve-static-1.13.9.tgz?cache=0&sync_timestamp=1621242658422&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fserve-static%2Fdownload%2F%40types%2Fserve-static-1.13.9.tgz", + "integrity": "sha1-qs8oqFoF7imhH7fD6tk1rFbzPk4=", + "dev": true, + "requires": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "@types/source-list-map": { + "version": "0.1.2", + "resolved": "https://registry.nlark.com/@types/source-list-map/download/@types/source-list-map-0.1.2.tgz", + "integrity": "sha1-AHiDYGP/rxdBI0m7o2QIfgrALsk=", + "dev": true + }, + "@types/tapable": { + "version": "1.0.7", + "resolved": "https://registry.nlark.com/@types/tapable/download/@types/tapable-1.0.7.tgz?cache=0&sync_timestamp=1621243788434&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Ftapable%2Fdownload%2F%40types%2Ftapable-1.0.7.tgz", + "integrity": "sha1-VFFYNC+Uno/Tv9gTIklx7N3D+sQ=", + "dev": true + }, + "@types/uglify-js": { + "version": "3.13.0", + "resolved": "https://registry.nlark.com/@types/uglify-js/download/@types/uglify-js-3.13.0.tgz", + "integrity": "sha1-HK2N8fsLFDxaugjeVxLqnR/3ESQ=", + "dev": true, + "requires": { + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "dev": true + } + } + }, + "@types/webpack": { + "version": "4.41.29", + "resolved": "https://registry.nlark.com/@types/webpack/download/@types/webpack-4.41.29.tgz?cache=0&sync_timestamp=1621533733988&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fwebpack%2Fdownload%2F%40types%2Fwebpack-4.41.29.tgz", + "integrity": "sha1-LmbB3oIjxEA2ZGlBXFCkfZdiV3M=", + "dev": true, + "requires": { + "@types/node": "*", + "@types/tapable": "^1", + "@types/uglify-js": "*", + "@types/webpack-sources": "*", + "anymatch": "^3.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "dev": true + } + } + }, + "@types/webpack-dev-server": { + "version": "3.11.4", + "resolved": "https://registry.nlark.com/@types/webpack-dev-server/download/@types/webpack-dev-server-3.11.4.tgz", + "integrity": "sha1-kNR91mC2ltQJQxq4wen6NhUQOgc=", + "dev": true, + "requires": { + "@types/connect-history-api-fallback": "*", + "@types/express": "*", + "@types/serve-static": "*", + "@types/webpack": "^4", + "http-proxy-middleware": "^1.0.0" + } + }, + "@types/webpack-sources": { + "version": "2.1.0", + "resolved": "https://registry.nlark.com/@types/webpack-sources/download/@types/webpack-sources-2.1.0.tgz?cache=0&sync_timestamp=1621243863278&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fwebpack-sources%2Fdownload%2F%40types%2Fwebpack-sources-2.1.0.tgz", + "integrity": "sha1-iIKwvWLR4M5i8YPQ0Bty5ugujBA=", + "dev": true, + "requires": { + "@types/node": "*", + "@types/source-list-map": "*", + "source-map": "^0.7.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.7.3.tgz", + "integrity": "sha1-UwL4FpAxc1ImVECS5kmB91F1A4M=", + "dev": true + } + } + }, + "@vue/babel-helper-vue-jsx-merge-props": { + "version": "1.2.1", + "resolved": "https://registry.npm.taobao.org/@vue/babel-helper-vue-jsx-merge-props/download/@vue/babel-helper-vue-jsx-merge-props-1.2.1.tgz?cache=0&sync_timestamp=1602851122331&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fbabel-helper-vue-jsx-merge-props%2Fdownload%2F%40vue%2Fbabel-helper-vue-jsx-merge-props-1.2.1.tgz", + "integrity": "sha1-MWJKelBfsU2h1YAjclpMXycOaoE=", + "dev": true + }, + "@vue/babel-helper-vue-transform-on": { + "version": "1.0.2", + "resolved": "https://registry.nlark.com/@vue/babel-helper-vue-transform-on/download/@vue/babel-helper-vue-transform-on-1.0.2.tgz", + "integrity": "sha1-m5xpHNBvyFUiGiR1w8yDHXdLx9w=", + "dev": true + }, + "@vue/babel-plugin-jsx": { + "version": "1.0.6", + "resolved": "https://registry.nlark.com/@vue/babel-plugin-jsx/download/@vue/babel-plugin-jsx-1.0.6.tgz?cache=0&sync_timestamp=1619929844730&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40vue%2Fbabel-plugin-jsx%2Fdownload%2F%40vue%2Fbabel-plugin-jsx-1.0.6.tgz", + "integrity": "sha1-GEvzVBq279vlB5q4sgwZ4q8QC/s=", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/plugin-syntax-jsx": "^7.0.0", + "@babel/template": "^7.0.0", + "@babel/traverse": "^7.0.0", + "@babel/types": "^7.0.0", + "@vue/babel-helper-vue-transform-on": "^1.0.2", + "camelcase": "^6.0.0", + "html-tags": "^3.1.0", + "svg-tags": "^1.0.0" + } + }, + "@vue/babel-plugin-transform-vue-jsx": { + "version": "1.2.1", + "resolved": "https://registry.npm.taobao.org/@vue/babel-plugin-transform-vue-jsx/download/@vue/babel-plugin-transform-vue-jsx-1.2.1.tgz?cache=0&sync_timestamp=1602851121024&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fbabel-plugin-transform-vue-jsx%2Fdownload%2F%40vue%2Fbabel-plugin-transform-vue-jsx-1.2.1.tgz", + "integrity": "sha1-ZGBGxlLC8CQnJ/NFGdkXsGQEHtc=", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-helper-vue-jsx-merge-props": "^1.2.1", + "html-tags": "^2.0.0", + "lodash.kebabcase": "^4.1.1", + "svg-tags": "^1.0.0" + }, + "dependencies": { + "html-tags": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/html-tags/download/html-tags-2.0.0.tgz", + "integrity": "sha1-ELMKOGCF9Dzt41PMj6fLDe7qZos=", + "dev": true + } + } + }, + "@vue/babel-preset-app": { + "version": "4.5.13", + "resolved": "https://registry.nlark.com/@vue/babel-preset-app/download/@vue/babel-preset-app-4.5.13.tgz", + "integrity": "sha1-y0dTIeTHP38RDawppIwqnLgK/rY=", + "dev": true, + "requires": { + "@babel/core": "^7.11.0", + "@babel/helper-compilation-targets": "^7.9.6", + "@babel/helper-module-imports": "^7.8.3", + "@babel/plugin-proposal-class-properties": "^7.8.3", + "@babel/plugin-proposal-decorators": "^7.8.3", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-jsx": "^7.8.3", + "@babel/plugin-transform-runtime": "^7.11.0", + "@babel/preset-env": "^7.11.0", + "@babel/runtime": "^7.11.0", + "@vue/babel-plugin-jsx": "^1.0.3", + "@vue/babel-preset-jsx": "^1.2.4", + "babel-plugin-dynamic-import-node": "^2.3.3", + "core-js": "^3.6.5", + "core-js-compat": "^3.6.5", + "semver": "^6.1.0" + } + }, + "@vue/babel-preset-jsx": { + "version": "1.2.4", + "resolved": "https://registry.npm.taobao.org/@vue/babel-preset-jsx/download/@vue/babel-preset-jsx-1.2.4.tgz", + "integrity": "sha1-kv6nnbbxOwHoDToAmeKSS9y+Toc=", + "dev": true, + "requires": { + "@vue/babel-helper-vue-jsx-merge-props": "^1.2.1", + "@vue/babel-plugin-transform-vue-jsx": "^1.2.1", + "@vue/babel-sugar-composition-api-inject-h": "^1.2.1", + "@vue/babel-sugar-composition-api-render-instance": "^1.2.4", + "@vue/babel-sugar-functional-vue": "^1.2.2", + "@vue/babel-sugar-inject-h": "^1.2.2", + "@vue/babel-sugar-v-model": "^1.2.3", + "@vue/babel-sugar-v-on": "^1.2.3" + } + }, + "@vue/babel-sugar-composition-api-inject-h": { + "version": "1.2.1", + "resolved": "https://registry.npm.taobao.org/@vue/babel-sugar-composition-api-inject-h/download/@vue/babel-sugar-composition-api-inject-h-1.2.1.tgz?cache=0&sync_timestamp=1602851211529&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fbabel-sugar-composition-api-inject-h%2Fdownload%2F%40vue%2Fbabel-sugar-composition-api-inject-h-1.2.1.tgz", + "integrity": "sha1-BdbgxDJxDjdYKyvppgSbaJtvA+s=", + "dev": true, + "requires": { + "@babel/plugin-syntax-jsx": "^7.2.0" + } + }, + "@vue/babel-sugar-composition-api-render-instance": { + "version": "1.2.4", + "resolved": "https://registry.npm.taobao.org/@vue/babel-sugar-composition-api-render-instance/download/@vue/babel-sugar-composition-api-render-instance-1.2.4.tgz", + "integrity": "sha1-5MvGmXw0T6wnF4WteikyXFHWjRk=", + "dev": true, + "requires": { + "@babel/plugin-syntax-jsx": "^7.2.0" + } + }, + "@vue/babel-sugar-functional-vue": { + "version": "1.2.2", + "resolved": "https://registry.nlark.com/@vue/babel-sugar-functional-vue/download/@vue/babel-sugar-functional-vue-1.2.2.tgz", + "integrity": "sha1-JnqayNeHyW7b8Dzj85LEnam9Jlg=", + "dev": true, + "requires": { + "@babel/plugin-syntax-jsx": "^7.2.0" + } + }, + "@vue/babel-sugar-inject-h": { + "version": "1.2.2", + "resolved": "https://registry.nlark.com/@vue/babel-sugar-inject-h/download/@vue/babel-sugar-inject-h-1.2.2.tgz", + "integrity": "sha1-1zjTyJM2fshJHcu2abAAkZKT46o=", + "dev": true, + "requires": { + "@babel/plugin-syntax-jsx": "^7.2.0" + } + }, + "@vue/babel-sugar-v-model": { + "version": "1.2.3", + "resolved": "https://registry.npm.taobao.org/@vue/babel-sugar-v-model/download/@vue/babel-sugar-v-model-1.2.3.tgz?cache=0&sync_timestamp=1603182488740&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fbabel-sugar-v-model%2Fdownload%2F%40vue%2Fbabel-sugar-v-model-1.2.3.tgz", + "integrity": "sha1-+h8pulHr8KoabDX6ZtU5vEWaGPI=", + "dev": true, + "requires": { + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-helper-vue-jsx-merge-props": "^1.2.1", + "@vue/babel-plugin-transform-vue-jsx": "^1.2.1", + "camelcase": "^5.0.0", + "html-tags": "^2.0.0", + "svg-tags": "^1.0.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.nlark.com/camelcase/download/camelcase-5.3.1.tgz", + "integrity": "sha1-48mzFWnhBoEd8kL3FXJaH0xJQyA=", + "dev": true + }, + "html-tags": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/html-tags/download/html-tags-2.0.0.tgz", + "integrity": "sha1-ELMKOGCF9Dzt41PMj6fLDe7qZos=", + "dev": true + } + } + }, + "@vue/babel-sugar-v-on": { + "version": "1.2.3", + "resolved": "https://registry.nlark.com/@vue/babel-sugar-v-on/download/@vue/babel-sugar-v-on-1.2.3.tgz", + "integrity": "sha1-NCNnF4WGpp85LwS/ujICHQKROto=", + "dev": true, + "requires": { + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-plugin-transform-vue-jsx": "^1.2.1", + "camelcase": "^5.0.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.nlark.com/camelcase/download/camelcase-5.3.1.tgz", + "integrity": "sha1-48mzFWnhBoEd8kL3FXJaH0xJQyA=", + "dev": true + } + } + }, + "@vue/cli-overlay": { + "version": "4.5.13", + "resolved": "https://registry.nlark.com/@vue/cli-overlay/download/@vue/cli-overlay-4.5.13.tgz", + "integrity": "sha1-Tx/SFhvo9p1suoB58/DX3E3uR6c=", + "dev": true + }, + "@vue/cli-plugin-babel": { + "version": "4.5.13", + "resolved": "https://registry.nlark.com/@vue/cli-plugin-babel/download/@vue/cli-plugin-babel-4.5.13.tgz", + "integrity": "sha1-qJxILtzE6h0TVkXOxQKn9f1MMOc=", + "dev": true, + "requires": { + "@babel/core": "^7.11.0", + "@vue/babel-preset-app": "^4.5.13", + "@vue/cli-shared-utils": "^4.5.13", + "babel-loader": "^8.1.0", + "cache-loader": "^4.1.0", + "thread-loader": "^2.1.3", + "webpack": "^4.0.0" + } + }, + "@vue/cli-plugin-eslint": { + "version": "4.5.13", + "resolved": "https://registry.nlark.com/@vue/cli-plugin-eslint/download/@vue/cli-plugin-eslint-4.5.13.tgz", + "integrity": "sha1-i68i0NltdnIMdQZka5b09iwFvfo=", + "dev": true, + "requires": { + "@vue/cli-shared-utils": "^4.5.13", + "eslint-loader": "^2.2.1", + "globby": "^9.2.0", + "inquirer": "^7.1.0", + "webpack": "^4.0.0", + "yorkie": "^2.0.0" + } + }, + "@vue/cli-plugin-router": { + "version": "4.5.13", + "resolved": "https://registry.nlark.com/@vue/cli-plugin-router/download/@vue/cli-plugin-router-4.5.13.tgz", + "integrity": "sha1-C2fIiYor8TKUGRmiouXzqsvZ/74=", + "dev": true, + "requires": { + "@vue/cli-shared-utils": "^4.5.13" + } + }, + "@vue/cli-plugin-vuex": { + "version": "4.5.13", + "resolved": "https://registry.nlark.com/@vue/cli-plugin-vuex/download/@vue/cli-plugin-vuex-4.5.13.tgz", + "integrity": "sha1-mGRti8HmnPbGpsui/tPqzgNWw2A=", + "dev": true + }, + "@vue/cli-service": { + "version": "4.5.13", + "resolved": "https://registry.nlark.com/@vue/cli-service/download/@vue/cli-service-4.5.13.tgz?cache=0&sync_timestamp=1620981774837&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40vue%2Fcli-service%2Fdownload%2F%40vue%2Fcli-service-4.5.13.tgz", + "integrity": "sha1-oJ5oSoAWhLbiTlQUrTBlCXDuye0=", + "dev": true, + "requires": { + "@intervolga/optimize-cssnano-plugin": "^1.0.5", + "@soda/friendly-errors-webpack-plugin": "^1.7.1", + "@soda/get-current-script": "^1.0.0", + "@types/minimist": "^1.2.0", + "@types/webpack": "^4.0.0", + "@types/webpack-dev-server": "^3.11.0", + "@vue/cli-overlay": "^4.5.13", + "@vue/cli-plugin-router": "^4.5.13", + "@vue/cli-plugin-vuex": "^4.5.13", + "@vue/cli-shared-utils": "^4.5.13", + "@vue/component-compiler-utils": "^3.1.2", + "@vue/preload-webpack-plugin": "^1.1.0", + "@vue/web-component-wrapper": "^1.2.0", + "acorn": "^7.4.0", + "acorn-walk": "^7.1.1", + "address": "^1.1.2", + "autoprefixer": "^9.8.6", + "browserslist": "^4.12.0", + "cache-loader": "^4.1.0", + "case-sensitive-paths-webpack-plugin": "^2.3.0", + "cli-highlight": "^2.1.4", + "clipboardy": "^2.3.0", + "cliui": "^6.0.0", + "copy-webpack-plugin": "^5.1.1", + "css-loader": "^3.5.3", + "cssnano": "^4.1.10", + "debug": "^4.1.1", + "default-gateway": "^5.0.5", + "dotenv": "^8.2.0", + "dotenv-expand": "^5.1.0", + "file-loader": "^4.2.0", + "fs-extra": "^7.0.1", + "globby": "^9.2.0", + "hash-sum": "^2.0.0", + "html-webpack-plugin": "^3.2.0", + "launch-editor-middleware": "^2.2.1", + "lodash.defaultsdeep": "^4.6.1", + "lodash.mapvalues": "^4.6.0", + "lodash.transform": "^4.6.0", + "mini-css-extract-plugin": "^0.9.0", + "minimist": "^1.2.5", + "pnp-webpack-plugin": "^1.6.4", + "portfinder": "^1.0.26", + "postcss-loader": "^3.0.0", + "ssri": "^8.0.1", + "terser-webpack-plugin": "^1.4.4", + "thread-loader": "^2.1.3", + "url-loader": "^2.2.0", + "vue-loader": "^15.9.2", + "vue-loader-v16": "npm:vue-loader@^16.1.0", + "vue-style-loader": "^4.1.2", + "webpack": "^4.0.0", + "webpack-bundle-analyzer": "^3.8.0", + "webpack-chain": "^6.4.0", + "webpack-dev-server": "^3.11.0", + "webpack-merge": "^4.2.2" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.nlark.com/acorn/download/acorn-7.4.1.tgz", + "integrity": "sha1-/q7SVZc9LndVW4PbwIhRpsY1IPo=", + "dev": true + }, + "ssri": { + "version": "8.0.1", + "resolved": "https://registry.nlark.com/ssri/download/ssri-8.0.1.tgz?cache=0&sync_timestamp=1621364626710&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fssri%2Fdownload%2Fssri-8.0.1.tgz", + "integrity": "sha1-Y45OQ54v+9LNKJd21cpFfE9Roq8=", + "dev": true, + "requires": { + "minipass": "^3.1.1" + } + } + } + }, + "@vue/cli-shared-utils": { + "version": "4.5.13", + "resolved": "https://registry.nlark.com/@vue/cli-shared-utils/download/@vue/cli-shared-utils-4.5.13.tgz", + "integrity": "sha1-rNQPMbR5DxY0KSvapfypXcHg/1A=", + "dev": true, + "requires": { + "@hapi/joi": "^15.0.1", + "chalk": "^2.4.2", + "execa": "^1.0.0", + "launch-editor": "^2.2.1", + "lru-cache": "^5.1.1", + "node-ipc": "^9.1.1", + "open": "^6.3.0", + "ora": "^3.4.0", + "read-pkg": "^5.1.1", + "request": "^2.88.2", + "semver": "^6.1.0", + "strip-ansi": "^6.0.0" + } + }, + "@vue/compiler-core": { + "version": "3.0.11", + "resolved": "https://registry.nlark.com/@vue/compiler-core/download/@vue/compiler-core-3.0.11.tgz", + "integrity": "sha1-XvV55G17M2uHNSKHWNHCxQWq5po=", + "requires": { + "@babel/parser": "^7.12.0", + "@babel/types": "^7.12.0", + "@vue/shared": "3.0.11", + "estree-walker": "^2.0.1", + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=" + } + } + }, + "@vue/compiler-dom": { + "version": "3.0.11", + "resolved": "https://registry.nlark.com/@vue/compiler-dom/download/@vue/compiler-dom-3.0.11.tgz", + "integrity": "sha1-sV/ByQk3H9ZxdGAgulW12rSnMO4=", + "requires": { + "@vue/compiler-core": "3.0.11", + "@vue/shared": "3.0.11" + } + }, + "@vue/compiler-sfc": { + "version": "3.0.11", + "resolved": "https://registry.nlark.com/@vue/compiler-sfc/download/@vue/compiler-sfc-3.0.11.tgz", + "integrity": "sha1-zYyiFUuIlntSH1rTsQ9fi2tmVnk=", + "dev": true, + "requires": { + "@babel/parser": "^7.13.9", + "@babel/types": "^7.13.0", + "@vue/compiler-core": "3.0.11", + "@vue/compiler-dom": "3.0.11", + "@vue/compiler-ssr": "3.0.11", + "@vue/shared": "3.0.11", + "consolidate": "^0.16.0", + "estree-walker": "^2.0.1", + "hash-sum": "^2.0.0", + "lru-cache": "^5.1.1", + "magic-string": "^0.25.7", + "merge-source-map": "^1.1.0", + "postcss": "^8.1.10", + "postcss-modules": "^4.0.0", + "postcss-selector-parser": "^6.0.4", + "source-map": "^0.6.1" + }, + "dependencies": { + "consolidate": { + "version": "0.16.0", + "resolved": "https://registry.npm.taobao.org/consolidate/download/consolidate-0.16.0.tgz", + "integrity": "sha1-oRhkdokw8vGUMWYKZZBmaPX73BY=", + "dev": true, + "requires": { + "bluebird": "^3.7.2" + } + }, + "postcss": { + "version": "8.3.0", + "resolved": "https://registry.nlark.com/postcss/download/postcss-8.3.0.tgz?cache=0&sync_timestamp=1621568644827&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss%2Fdownload%2Fpostcss-8.3.0.tgz", + "integrity": "sha1-sacT9hcspCfj8F7xMD3otlaDMl8=", + "dev": true, + "requires": { + "colorette": "^1.2.2", + "nanoid": "^3.1.23", + "source-map-js": "^0.6.2" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "dev": true + } + } + }, + "@vue/compiler-ssr": { + "version": "3.0.11", + "resolved": "https://registry.nlark.com/@vue/compiler-ssr/download/@vue/compiler-ssr-3.0.11.tgz", + "integrity": "sha1-rFoF/RJXQS+mYHnII9ggO2qImhM=", + "dev": true, + "requires": { + "@vue/compiler-dom": "3.0.11", + "@vue/shared": "3.0.11" + } + }, + "@vue/component-compiler-utils": { + "version": "3.2.0", + "resolved": "https://registry.npm.taobao.org/@vue/component-compiler-utils/download/@vue/component-compiler-utils-3.2.0.tgz", + "integrity": "sha1-j4UYLO7Sjps8dTE95mn4MWbRHl0=", + "dev": true, + "requires": { + "consolidate": "^0.15.1", + "hash-sum": "^1.0.2", + "lru-cache": "^4.1.2", + "merge-source-map": "^1.1.0", + "postcss": "^7.0.14", + "postcss-selector-parser": "^6.0.2", + "prettier": "^1.18.2", + "source-map": "~0.6.1", + "vue-template-es2015-compiler": "^1.9.0" + }, + "dependencies": { + "hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/hash-sum/download/hash-sum-1.0.2.tgz", + "integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=", + "dev": true + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.nlark.com/lru-cache/download/lru-cache-4.1.5.tgz", + "integrity": "sha1-i75Q6oW+1ZvJ4z3KuCNe6bz0Q80=", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npm.taobao.org/yallist/download/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } + } + }, + "@vue/devtools-api": { + "version": "6.0.0-beta.12", + "resolved": "https://registry.nlark.com/@vue/devtools-api/download/@vue/devtools-api-6.0.0-beta.12.tgz", + "integrity": "sha1-aT/8d7+2awgOXJV2q7V4bIVHCjI=" + }, + "@vue/preload-webpack-plugin": { + "version": "1.1.2", + "resolved": "https://registry.nlark.com/@vue/preload-webpack-plugin/download/@vue/preload-webpack-plugin-1.1.2.tgz", + "integrity": "sha1-zrkktOyzucQ4ccekKaAvhCPmIas=", + "dev": true + }, + "@vue/reactivity": { + "version": "3.0.11", + "resolved": "https://registry.nlark.com/@vue/reactivity/download/@vue/reactivity-3.0.11.tgz", + "integrity": "sha1-B7WINJ/QViaxfzUAy+99S9tNvQs=", + "requires": { + "@vue/shared": "3.0.11" + } + }, + "@vue/runtime-core": { + "version": "3.0.11", + "resolved": "https://registry.nlark.com/@vue/runtime-core/download/@vue/runtime-core-3.0.11.tgz", + "integrity": "sha1-xS38as8yFUk2I1UsHCkZCAxWLkQ=", + "requires": { + "@vue/reactivity": "3.0.11", + "@vue/shared": "3.0.11" + } + }, + "@vue/runtime-dom": { + "version": "3.0.11", + "resolved": "https://registry.nlark.com/@vue/runtime-dom/download/@vue/runtime-dom-3.0.11.tgz", + "integrity": "sha1-elUt8hkHlCch/raWHEGOIippkzc=", + "requires": { + "@vue/runtime-core": "3.0.11", + "@vue/shared": "3.0.11", + "csstype": "^2.6.8" + } + }, + "@vue/shared": { + "version": "3.0.11", + "resolved": "https://registry.nlark.com/@vue/shared/download/@vue/shared-3.0.11.tgz", + "integrity": "sha1-INIt0Np9NYuyHBf5vehigVJkLHc=" + }, + "@vue/web-component-wrapper": { + "version": "1.3.0", + "resolved": "https://registry.npm.taobao.org/@vue/web-component-wrapper/download/@vue/web-component-wrapper-1.3.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fweb-component-wrapper%2Fdownload%2F%40vue%2Fweb-component-wrapper-1.3.0.tgz", + "integrity": "sha1-trQKdiVCnSvXwigd26YB7QXcfxo=", + "dev": true + }, + "@wailsapp/runtime": { + "version": "1.1.1", + "resolved": "https://registry.npm.taobao.org/@wailsapp/runtime/download/@wailsapp/runtime-1.1.1.tgz", + "integrity": "sha1-Mj99KQN40wzs7KeR6wpUWyhEE0k=" + }, + "@webassemblyjs/ast": { + "version": "1.9.0", + "resolved": "https://registry.npm.taobao.org/@webassemblyjs/ast/download/@webassemblyjs/ast-1.9.0.tgz?cache=0&sync_timestamp=1610041327965&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40webassemblyjs%2Fast%2Fdownload%2F%40webassemblyjs%2Fast-1.9.0.tgz", + "integrity": "sha1-vYUGBLQEJFmlpBzX0zjL7Wle2WQ=", + "dev": true, + "requires": { + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.9.0", + "resolved": "https://registry.npm.taobao.org/@webassemblyjs/floating-point-hex-parser/download/@webassemblyjs/floating-point-hex-parser-1.9.0.tgz?cache=0&sync_timestamp=1610043274676&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40webassemblyjs%2Ffloating-point-hex-parser%2Fdownload%2F%40webassemblyjs%2Ffloating-point-hex-parser-1.9.0.tgz", + "integrity": "sha1-PD07Jxvd/ITesA9xNEQ4MR1S/7Q=", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.9.0", + "resolved": "https://registry.npm.taobao.org/@webassemblyjs/helper-api-error/download/@webassemblyjs/helper-api-error-1.9.0.tgz?cache=0&sync_timestamp=1610041334619&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40webassemblyjs%2Fhelper-api-error%2Fdownload%2F%40webassemblyjs%2Fhelper-api-error-1.9.0.tgz", + "integrity": "sha1-ID9nbjM7lsnaLuqzzO8zxFkotqI=", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.9.0", + "resolved": "https://registry.npm.taobao.org/@webassemblyjs/helper-buffer/download/@webassemblyjs/helper-buffer-1.9.0.tgz?cache=0&sync_timestamp=1610041334130&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40webassemblyjs%2Fhelper-buffer%2Fdownload%2F%40webassemblyjs%2Fhelper-buffer-1.9.0.tgz", + "integrity": "sha1-oUQtJpxf6yP8vJ73WdrDVH8p3gA=", + "dev": true + }, + "@webassemblyjs/helper-code-frame": { + "version": "1.9.0", + "resolved": "https://registry.npm.taobao.org/@webassemblyjs/helper-code-frame/download/@webassemblyjs/helper-code-frame-1.9.0.tgz?cache=0&sync_timestamp=1610041493871&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40webassemblyjs%2Fhelper-code-frame%2Fdownload%2F%40webassemblyjs%2Fhelper-code-frame-1.9.0.tgz", + "integrity": "sha1-ZH+Iks0gQ6gqwMjF51w28dkVnyc=", + "dev": true, + "requires": { + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "@webassemblyjs/helper-fsm": { + "version": "1.9.0", + "resolved": "https://registry.nlark.com/@webassemblyjs/helper-fsm/download/@webassemblyjs/helper-fsm-1.9.0.tgz", + "integrity": "sha1-wFJWtxJEIUZx9LCOwQitY7cO3bg=", + "dev": true + }, + "@webassemblyjs/helper-module-context": { + "version": "1.9.0", + "resolved": "https://registry.npm.taobao.org/@webassemblyjs/helper-module-context/download/@webassemblyjs/helper-module-context-1.9.0.tgz", + "integrity": "sha1-JdiIS3aDmHGgimxvgGw5ee9xLwc=", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.9.0", + "resolved": "https://registry.npm.taobao.org/@webassemblyjs/helper-wasm-bytecode/download/@webassemblyjs/helper-wasm-bytecode-1.9.0.tgz?cache=0&sync_timestamp=1610041334247&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40webassemblyjs%2Fhelper-wasm-bytecode%2Fdownload%2F%40webassemblyjs%2Fhelper-wasm-bytecode-1.9.0.tgz", + "integrity": "sha1-T+2L6sm4wU+MWLcNEk1UndH+V5A=", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.9.0", + "resolved": "https://registry.npm.taobao.org/@webassemblyjs/helper-wasm-section/download/@webassemblyjs/helper-wasm-section-1.9.0.tgz?cache=0&sync_timestamp=1610041332602&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40webassemblyjs%2Fhelper-wasm-section%2Fdownload%2F%40webassemblyjs%2Fhelper-wasm-section-1.9.0.tgz", + "integrity": "sha1-WkE41aYpK6GLBMWuSXF+QWeWU0Y=", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.9.0", + "resolved": "https://registry.npm.taobao.org/@webassemblyjs/ieee754/download/@webassemblyjs/ieee754-1.9.0.tgz?cache=0&sync_timestamp=1610041334740&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40webassemblyjs%2Fieee754%2Fdownload%2F%40webassemblyjs%2Fieee754-1.9.0.tgz", + "integrity": "sha1-Fceg+6roP7JhQ7us9tbfFwKtOeQ=", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.9.0", + "resolved": "https://registry.npm.taobao.org/@webassemblyjs/leb128/download/@webassemblyjs/leb128-1.9.0.tgz", + "integrity": "sha1-8Zygt2ptxVYjoJz/p2noOPoeHJU=", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.9.0", + "resolved": "https://registry.npm.taobao.org/@webassemblyjs/utf8/download/@webassemblyjs/utf8-1.9.0.tgz?cache=0&sync_timestamp=1610041334838&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40webassemblyjs%2Futf8%2Fdownload%2F%40webassemblyjs%2Futf8-1.9.0.tgz", + "integrity": "sha1-BNM7Y2945qaBMifoJAL3Y3tiKas=", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.9.0", + "resolved": "https://registry.npm.taobao.org/@webassemblyjs/wasm-edit/download/@webassemblyjs/wasm-edit-1.9.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40webassemblyjs%2Fwasm-edit%2Fdownload%2F%40webassemblyjs%2Fwasm-edit-1.9.0.tgz", + "integrity": "sha1-P+bXnT8PkiGDqoYALELdJWz+6c8=", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/helper-wasm-section": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-opt": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.9.0", + "resolved": "https://registry.npm.taobao.org/@webassemblyjs/wasm-gen/download/@webassemblyjs/wasm-gen-1.9.0.tgz?cache=0&sync_timestamp=1610041335808&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40webassemblyjs%2Fwasm-gen%2Fdownload%2F%40webassemblyjs%2Fwasm-gen-1.9.0.tgz", + "integrity": "sha1-ULxw7Gje2OJ2OwGhQYv0NJGnpJw=", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.9.0", + "resolved": "https://registry.npm.taobao.org/@webassemblyjs/wasm-opt/download/@webassemblyjs/wasm-opt-1.9.0.tgz?cache=0&sync_timestamp=1610041336191&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40webassemblyjs%2Fwasm-opt%2Fdownload%2F%40webassemblyjs%2Fwasm-opt-1.9.0.tgz", + "integrity": "sha1-IhEYHlsxMmRDzIES658LkChyGmE=", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.9.0", + "resolved": "https://registry.npm.taobao.org/@webassemblyjs/wasm-parser/download/@webassemblyjs/wasm-parser-1.9.0.tgz?cache=0&sync_timestamp=1610041328345&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40webassemblyjs%2Fwasm-parser%2Fdownload%2F%40webassemblyjs%2Fwasm-parser-1.9.0.tgz", + "integrity": "sha1-nUjkSCbfSmWYKUqmyHRp1kL/9l4=", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "@webassemblyjs/wast-parser": { + "version": "1.9.0", + "resolved": "https://registry.npm.taobao.org/@webassemblyjs/wast-parser/download/@webassemblyjs/wast-parser-1.9.0.tgz?cache=0&sync_timestamp=1610041489596&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40webassemblyjs%2Fwast-parser%2Fdownload%2F%40webassemblyjs%2Fwast-parser-1.9.0.tgz", + "integrity": "sha1-MDERXXmsW9JhVWzsw/qQo+9FGRQ=", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/floating-point-hex-parser": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-code-frame": "1.9.0", + "@webassemblyjs/helper-fsm": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.9.0", + "resolved": "https://registry.npm.taobao.org/@webassemblyjs/wast-printer/download/@webassemblyjs/wast-printer-1.9.0.tgz?cache=0&sync_timestamp=1610041335289&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40webassemblyjs%2Fwast-printer%2Fdownload%2F%40webassemblyjs%2Fwast-printer-1.9.0.tgz", + "integrity": "sha1-STXVTIX+9jewDOn1I3dFHQDUeJk=", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npm.taobao.org/@xtuc/ieee754/download/@xtuc/ieee754-1.2.0.tgz", + "integrity": "sha1-7vAUoxRa5Hehy8AM0eVSM23Ot5A=", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npm.taobao.org/@xtuc/long/download/@xtuc/long-4.2.2.tgz", + "integrity": "sha1-0pHGpOl5ibXGHZrPOWrk/hM6cY0=", + "dev": true + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npm.taobao.org/accepts/download/accepts-1.3.7.tgz", + "integrity": "sha1-UxvHJlF6OytB+FACHGzBXqq1B80=", + "dev": true, + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "acorn": { + "version": "6.4.2", + "resolved": "https://registry.nlark.com/acorn/download/acorn-6.4.2.tgz", + "integrity": "sha1-NYZv1xBSjpLeEM8GAWSY5H454eY=", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.1", + "resolved": "https://registry.npm.taobao.org/acorn-jsx/download/acorn-jsx-5.3.1.tgz?cache=0&sync_timestamp=1599499155970&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Facorn-jsx%2Fdownload%2Facorn-jsx-5.3.1.tgz", + "integrity": "sha1-/IZh4Rt6wVOcR9v+oucrOvNNJns=", + "dev": true + }, + "acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.nlark.com/acorn-walk/download/acorn-walk-7.2.0.tgz", + "integrity": "sha1-DeiJpgEgOQmw++B7iTjcIdLpZ7w=", + "dev": true + }, + "address": { + "version": "1.1.2", + "resolved": "https://registry.npm.taobao.org/address/download/address-1.1.2.tgz", + "integrity": "sha1-vxEWycdYxRt6kz0pa3LCIe2UKLY=", + "dev": true + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.nlark.com/ajv/download/ajv-6.12.6.tgz?cache=0&sync_timestamp=1621517694340&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fajv%2Fdownload%2Fajv-6.12.6.tgz", + "integrity": "sha1-uvWmLoArB9l3A0WG+MO69a3ybfQ=", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.nlark.com/ajv-errors/download/ajv-errors-1.0.1.tgz", + "integrity": "sha1-81mGrOuRr63sQQL72FAUlQzvpk0=", + "dev": true + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npm.taobao.org/ajv-keywords/download/ajv-keywords-3.5.2.tgz", + "integrity": "sha1-MfKdpatuANHC0yms97WSlhTVAU0=", + "dev": true + }, + "alphanum-sort": { + "version": "1.0.2", + "resolved": "https://registry.nlark.com/alphanum-sort/download/alphanum-sort-1.0.2.tgz", + "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", + "dev": true + }, + "ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npm.taobao.org/ansi-colors/download/ansi-colors-3.2.4.tgz", + "integrity": "sha1-46PaS/uubIapwoViXeEkojQCb78=", + "dev": true + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.nlark.com/ansi-escapes/download/ansi-escapes-4.3.2.tgz?cache=0&sync_timestamp=1618847144938&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fansi-escapes%2Fdownload%2Fansi-escapes-4.3.2.tgz", + "integrity": "sha1-ayKR0dt9mLZSHV8e+kLQ86n+tl4=", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + }, + "dependencies": { + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.nlark.com/type-fest/download/type-fest-0.21.3.tgz?cache=0&sync_timestamp=1621402446336&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ftype-fest%2Fdownload%2Ftype-fest-0.21.3.tgz", + "integrity": "sha1-0mCiSwGYQ24TP6JqUkptZfo7Ljc=", + "dev": true + } + } + }, + "ansi-html": { + "version": "0.0.7", + "resolved": "https://registry.nlark.com/ansi-html/download/ansi-html-0.0.7.tgz", + "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", + "dev": true + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.nlark.com/ansi-regex/download/ansi-regex-4.1.0.tgz", + "integrity": "sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.nlark.com/ansi-styles/download/ansi-styles-3.2.1.tgz", + "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.nlark.com/any-promise/download/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=", + "dev": true + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.nlark.com/anymatch/download/anymatch-3.1.2.tgz", + "integrity": "sha1-wFV8CWrzLxBhmPT04qODU343hxY=", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.nlark.com/aproba/download/aproba-1.2.0.tgz", + "integrity": "sha1-aALmJk79GMeQobDVF/DyYnvyyUo=", + "dev": true + }, + "arch": { + "version": "2.2.0", + "resolved": "https://registry.npm.taobao.org/arch/download/arch-2.2.0.tgz", + "integrity": "sha1-G8R4GPMFdk8jqzMGsL/AhsWinRE=", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npm.taobao.org/argparse/download/argparse-1.0.10.tgz", + "integrity": "sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE=", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.nlark.com/arr-diff/download/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.nlark.com/arr-flatten/download/arr-flatten-1.1.0.tgz?cache=0&sync_timestamp=1618846805394&other_urls=https%3A%2F%2Fregistry.nlark.com%2Farr-flatten%2Fdownload%2Farr-flatten-1.1.0.tgz", + "integrity": "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE=", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.nlark.com/arr-union/download/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.nlark.com/array-flatten/download/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", + "dev": true + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/array-union/download/array-union-1.0.2.tgz?cache=0&sync_timestamp=1614624407140&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Farray-union%2Fdownload%2Farray-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.nlark.com/array-uniq/download/array-uniq-1.0.3.tgz?cache=0&sync_timestamp=1620042121153&other_urls=https%3A%2F%2Fregistry.nlark.com%2Farray-uniq%2Fdownload%2Farray-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.nlark.com/array-unique/download/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npm.taobao.org/asn1/download/asn1-0.2.4.tgz", + "integrity": "sha1-jSR136tVO7M+d7VOWeiAu4ziMTY=", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npm.taobao.org/asn1.js/download/asn1.js-5.4.1.tgz", + "integrity": "sha1-EamAuE67kXgc41sP3C7ilON4Pwc=", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npm.taobao.org/bn.js/download/bn.js-4.12.0.tgz", + "integrity": "sha1-d1s/J477uXGO7HNh9IP7Nvu/6og=", + "dev": true + } + } + }, + "assert": { + "version": "1.5.0", + "resolved": "https://registry.nlark.com/assert/download/assert-1.5.0.tgz?cache=0&sync_timestamp=1618847153747&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fassert%2Fdownload%2Fassert-1.5.0.tgz", + "integrity": "sha1-VcEJqvbgrv2z3EtxJAxwv1dLGOs=", + "dev": true, + "requires": { + "object-assign": "^4.1.1", + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.nlark.com/inherits/download/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.nlark.com/util/download/util-0.10.3.tgz?cache=0&sync_timestamp=1622213047493&other_urls=https%3A%2F%2Fregistry.nlark.com%2Futil%2Fdownload%2Futil-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "requires": { + "inherits": "2.0.1" + } + } + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.nlark.com/assert-plus/download/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/assign-symbols/download/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/astral-regex/download/astral-regex-1.0.0.tgz", + "integrity": "sha1-bIw/uCfdQ+45GPJ7gngqt2WKb9k=", + "dev": true + }, + "async": { + "version": "2.6.3", + "resolved": "https://registry.nlark.com/async/download/async-2.6.3.tgz", + "integrity": "sha1-1yYl4jRKNlbjo61Pp0n6gymdgv8=", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npm.taobao.org/async-each/download/async-each-1.0.3.tgz", + "integrity": "sha1-tyfb+H12UWAvBvTUrDh/R9kbDL8=", + "dev": true + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npm.taobao.org/async-limiter/download/async-limiter-1.0.1.tgz", + "integrity": "sha1-3TeelPDbgxCwgpH51kwyCXZmF/0=", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.nlark.com/asynckit/download/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.nlark.com/atob/download/atob-2.1.2.tgz", + "integrity": "sha1-bZUX654DDSQ2ZmZR6GvZ9vE1M8k=", + "dev": true + }, + "autoprefixer": { + "version": "9.8.6", + "resolved": "https://registry.nlark.com/autoprefixer/download/autoprefixer-9.8.6.tgz?cache=0&sync_timestamp=1622039586788&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fautoprefixer%2Fdownload%2Fautoprefixer-9.8.6.tgz", + "integrity": "sha1-O3NZTKG/kmYyDFrPFYjXTep0IQ8=", + "dev": true, + "requires": { + "browserslist": "^4.12.0", + "caniuse-lite": "^1.0.30001109", + "colorette": "^1.2.1", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^7.0.32", + "postcss-value-parser": "^4.1.0" + } + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npm.taobao.org/aws-sign2/download/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.nlark.com/aws4/download/aws4-1.11.0.tgz", + "integrity": "sha1-1h9G2DslGSUOJ4Ta9bCUeai0HFk=", + "dev": true + }, + "babel-eslint": { + "version": "10.1.0", + "resolved": "https://registry.nlark.com/babel-eslint/download/babel-eslint-10.1.0.tgz?cache=0&sync_timestamp=1618846971799&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fbabel-eslint%2Fdownload%2Fbabel-eslint-10.1.0.tgz", + "integrity": "sha1-aWjlaKkQt4+zd5zdi2rC9HmUMjI=", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.0", + "@babel/traverse": "^7.7.0", + "@babel/types": "^7.7.0", + "eslint-visitor-keys": "^1.0.0", + "resolve": "^1.12.0" + } + }, + "babel-loader": { + "version": "8.2.2", + "resolved": "https://registry.nlark.com/babel-loader/download/babel-loader-8.2.2.tgz", + "integrity": "sha1-k2POhMEMmkDmx1N0jhRBtgyKC4E=", + "dev": true, + "requires": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^1.4.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + } + }, + "babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.nlark.com/babel-plugin-dynamic-import-node/download/babel-plugin-dynamic-import-node-2.3.3.tgz?cache=0&sync_timestamp=1618846790496&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fbabel-plugin-dynamic-import-node%2Fdownload%2Fbabel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha1-hP2hnJduxcbe/vV/lCez3vZuF6M=", + "dev": true, + "requires": { + "object.assign": "^4.1.0" + } + }, + "babel-plugin-polyfill-corejs2": { + "version": "0.2.2", + "resolved": "https://registry.nlark.com/babel-plugin-polyfill-corejs2/download/babel-plugin-polyfill-corejs2-0.2.2.tgz?cache=0&sync_timestamp=1622023904181&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fbabel-plugin-polyfill-corejs2%2Fdownload%2Fbabel-plugin-polyfill-corejs2-0.2.2.tgz", + "integrity": "sha1-6RJHheb9lPlLYYp5VOVpMFO/Uyc=", + "dev": true, + "requires": { + "@babel/compat-data": "^7.13.11", + "@babel/helper-define-polyfill-provider": "^0.2.2", + "semver": "^6.1.1" + } + }, + "babel-plugin-polyfill-corejs3": { + "version": "0.2.2", + "resolved": "https://registry.nlark.com/babel-plugin-polyfill-corejs3/download/babel-plugin-polyfill-corejs3-0.2.2.tgz?cache=0&sync_timestamp=1622023907017&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fbabel-plugin-polyfill-corejs3%2Fdownload%2Fbabel-plugin-polyfill-corejs3-0.2.2.tgz", + "integrity": "sha1-dCShaC7kS67IFzJ3ELGwlOX49/U=", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.2.2", + "core-js-compat": "^3.9.1" + } + }, + "babel-plugin-polyfill-regenerator": { + "version": "0.2.2", + "resolved": "https://registry.nlark.com/babel-plugin-polyfill-regenerator/download/babel-plugin-polyfill-regenerator-0.2.2.tgz?cache=0&sync_timestamp=1622023907940&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fbabel-plugin-polyfill-regenerator%2Fdownload%2Fbabel-plugin-polyfill-regenerator-0.2.2.tgz", + "integrity": "sha1-sxDI1kKsraNIwfo7Pmzg6FG+4Hc=", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.2.2" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/balanced-match/download/balanced-match-1.0.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbalanced-match%2Fdownload%2Fbalanced-match-1.0.2.tgz", + "integrity": "sha1-6D46fj8wCzTLnYf2FfoMvzV2kO4=", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npm.taobao.org/base/download/base-0.11.2.tgz", + "integrity": "sha1-e95c7RRbbVUakNuH+DxVi060io8=", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.nlark.com/is-accessor-descriptor/download/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.nlark.com/is-data-descriptor/download/is-data-descriptor-1.0.0.tgz", + "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/is-descriptor/download/is-descriptor-1.0.2.tgz", + "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.nlark.com/base64-js/download/base64-js-1.5.1.tgz", + "integrity": "sha1-GxtEAWClv3rUC2UPCVljSBkDkwo=", + "dev": true + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npm.taobao.org/batch/download/batch-0.6.1.tgz", + "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/bcrypt-pbkdf/download/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "bfj": { + "version": "6.1.2", + "resolved": "https://registry.npm.taobao.org/bfj/download/bfj-6.1.2.tgz", + "integrity": "sha1-MlyGGoIryzWKQceKM7jm4ght3n8=", + "dev": true, + "requires": { + "bluebird": "^3.5.5", + "check-types": "^8.0.3", + "hoopy": "^0.1.4", + "tryer": "^1.0.1" + } + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.nlark.com/big.js/download/big.js-5.2.2.tgz", + "integrity": "sha1-ZfCvOC9Xi83HQr2cKB6cstd2gyg=", + "dev": true + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.nlark.com/binary-extensions/download/binary-extensions-2.2.0.tgz", + "integrity": "sha1-dfUC7q+f/eQvyYgpZFvk6na9ni0=", + "dev": true, + "optional": true + }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.nlark.com/bindings/download/bindings-1.5.0.tgz", + "integrity": "sha1-EDU8npRTNLwFEabZCzj7x8nFBN8=", + "dev": true, + "optional": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.nlark.com/bluebird/download/bluebird-3.7.2.tgz?cache=0&sync_timestamp=1618847007562&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fbluebird%2Fdownload%2Fbluebird-3.7.2.tgz", + "integrity": "sha1-nyKcFb4nJFT/qXOs4NvueaGww28=", + "dev": true + }, + "bn.js": { + "version": "5.2.0", + "resolved": "https://registry.npm.taobao.org/bn.js/download/bn.js-5.2.0.tgz", + "integrity": "sha1-NYhgZ0OWxpl3canQUfzBtX1K4AI=", + "dev": true + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npm.taobao.org/body-parser/download/body-parser-1.19.0.tgz", + "integrity": "sha1-lrJwnlfJxOCab9Zqj9l5hE9p8Io=", + "dev": true, + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.nlark.com/debug/download/debug-2.6.9.tgz?cache=0&sync_timestamp=1618847042350&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdebug%2Fdownload%2Fdebug-2.6.9.tgz", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz?cache=0&sync_timestamp=1607433950466&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.nlark.com/qs/download/qs-6.7.0.tgz", + "integrity": "sha1-QdwaAV49WB8WIXdr4xr7KHapsbw=", + "dev": true + } + } + }, + "bonjour": { + "version": "3.5.0", + "resolved": "https://registry.nlark.com/bonjour/download/bonjour-3.5.0.tgz", + "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", + "dev": true, + "requires": { + "array-flatten": "^2.1.0", + "deep-equal": "^1.0.1", + "dns-equal": "^1.0.0", + "dns-txt": "^2.0.2", + "multicast-dns": "^6.0.1", + "multicast-dns-service-types": "^1.1.0" + }, + "dependencies": { + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.nlark.com/array-flatten/download/array-flatten-2.1.2.tgz", + "integrity": "sha1-JO+AoowaiTYX4hSbDG0NeIKTsJk=", + "dev": true + } + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.nlark.com/boolbase/download/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.nlark.com/brace-expansion/download/brace-expansion-1.1.11.tgz", + "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npm.taobao.org/braces/download/braces-2.3.2.tgz", + "integrity": "sha1-WXn9PxTNUxVl5fot8av/8d+u5yk=", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.nlark.com/extend-shallow/download/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.nlark.com/brorand/download/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.nlark.com/browserify-aes/download/browserify-aes-1.2.0.tgz", + "integrity": "sha1-Mmc0ZC9APavDADIJhTu3CtQo70g=", + "dev": true, + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.nlark.com/browserify-cipher/download/browserify-cipher-1.0.1.tgz", + "integrity": "sha1-jWR0wbhwv9q807z8wZNKEOlPFfA=", + "dev": true, + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.nlark.com/browserify-des/download/browserify-des-1.0.2.tgz", + "integrity": "sha1-OvTx9Zg5QDVy8cZiBDdfen9wPpw=", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.1.0", + "resolved": "https://registry.nlark.com/browserify-rsa/download/browserify-rsa-4.1.0.tgz", + "integrity": "sha1-sv0Gtbda4pf3zi3GUfkY9b4VjI0=", + "dev": true, + "requires": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.2.1", + "resolved": "https://registry.nlark.com/browserify-sign/download/browserify-sign-4.2.1.tgz", + "integrity": "sha1-6vSt1G3VS+O7OzbAzxWrvrp5VsM=", + "dev": true, + "requires": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.3", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.nlark.com/readable-stream/download/readable-stream-3.6.0.tgz", + "integrity": "sha1-M3u9o63AcGvT4CRCaihtS0sskZg=", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.nlark.com/safe-buffer/download/safe-buffer-5.2.1.tgz", + "integrity": "sha1-Hq+fqb2x/dTsdfWPnNtOa3gn7sY=", + "dev": true + } + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.nlark.com/browserify-zlib/download/browserify-zlib-0.2.0.tgz", + "integrity": "sha1-KGlFnZqjviRf6P4sofRuLn9U1z8=", + "dev": true, + "requires": { + "pako": "~1.0.5" + } + }, + "browserslist": { + "version": "4.16.6", + "resolved": "https://registry.nlark.com/browserslist/download/browserslist-4.16.6.tgz?cache=0&sync_timestamp=1619789101558&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fbrowserslist%2Fdownload%2Fbrowserslist-4.16.6.tgz", + "integrity": "sha1-15ASd6WojlVO0wWxg+ybDAj2b6I=", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001219", + "colorette": "^1.2.2", + "electron-to-chromium": "^1.3.723", + "escalade": "^3.1.1", + "node-releases": "^1.1.71" + } + }, + "buffer": { + "version": "4.9.2", + "resolved": "https://registry.nlark.com/buffer/download/buffer-4.9.2.tgz", + "integrity": "sha1-Iw6tNEACmIZEhBqwJEr4xEu+Pvg=", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npm.taobao.org/buffer-from/download/buffer-from-1.1.1.tgz", + "integrity": "sha1-MnE7wCj3XAL9txDXx7zsHyxgcO8=", + "dev": true + }, + "buffer-indexof": { + "version": "1.1.1", + "resolved": "https://registry.nlark.com/buffer-indexof/download/buffer-indexof-1.1.1.tgz", + "integrity": "sha1-Uvq8xqYG0aADAoAmSO9o9jnaJow=", + "dev": true + }, + "buffer-json": { + "version": "2.0.0", + "resolved": "https://registry.nlark.com/buffer-json/download/buffer-json-2.0.0.tgz", + "integrity": "sha1-9z4TseQvGW/i/WfQAcfXEH7dfCM=", + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npm.taobao.org/buffer-xor/download/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/builtin-status-codes/download/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", + "dev": true + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npm.taobao.org/bytes/download/bytes-3.1.0.tgz", + "integrity": "sha1-9s95M6Ng4FiPqf3oVlHNx/gF0fY=", + "dev": true + }, + "cacache": { + "version": "12.0.4", + "resolved": "https://registry.nlark.com/cacache/download/cacache-12.0.4.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fcacache%2Fdownload%2Fcacache-12.0.4.tgz", + "integrity": "sha1-ZovL0QWutfHZL+JVcOyVJcj6pAw=", + "dev": true, + "requires": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npm.taobao.org/cache-base/download/cache-base-1.0.1.tgz", + "integrity": "sha1-Cn9GQWgxyLZi7jb+TnxZ129marI=", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "cache-loader": { + "version": "4.1.0", + "resolved": "https://registry.nlark.com/cache-loader/download/cache-loader-4.1.0.tgz", + "integrity": "sha1-mUjK41OuwKH8ser9ojAIFuyFOH4=", + "dev": true, + "requires": { + "buffer-json": "^2.0.0", + "find-cache-dir": "^3.0.0", + "loader-utils": "^1.2.3", + "mkdirp": "^0.5.1", + "neo-async": "^2.6.1", + "schema-utils": "^2.0.0" + } + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.nlark.com/call-bind/download/call-bind-1.0.2.tgz", + "integrity": "sha1-sdTonmiBGcPJqQOtMKuy9qkZvjw=", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npm.taobao.org/call-me-maybe/download/call-me-maybe-1.0.1.tgz", + "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", + "dev": true + }, + "caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.nlark.com/caller-callsite/download/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "dev": true, + "requires": { + "callsites": "^2.0.0" + } + }, + "caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/caller-path/download/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "dev": true, + "requires": { + "caller-callsite": "^2.0.0" + } + }, + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/callsites/download/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "dev": true + }, + "camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/camel-case/download/camel-case-3.0.0.tgz?cache=0&sync_timestamp=1606867297052&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcamel-case%2Fdownload%2Fcamel-case-3.0.0.tgz", + "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", + "dev": true, + "requires": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, + "camelcase": { + "version": "6.2.0", + "resolved": "https://registry.nlark.com/camelcase/download/camelcase-6.2.0.tgz", + "integrity": "sha1-kkr4gcnVJaydh/QNlk5c6pgqGAk=", + "dev": true + }, + "caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/caniuse-api/download/caniuse-api-3.0.0.tgz", + "integrity": "sha1-Xk2Q4idJYdRikZl99Znj7QCO5MA=", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "caniuse-lite": { + "version": "1.0.30001231", + "resolved": "https://registry.nlark.com/caniuse-lite/download/caniuse-lite-1.0.30001231.tgz", + "integrity": "sha1-bB+bSfwnzDaLiU5kubKLOe+AYDs=", + "dev": true + }, + "case-sensitive-paths-webpack-plugin": { + "version": "2.4.0", + "resolved": "https://registry.nlark.com/case-sensitive-paths-webpack-plugin/download/case-sensitive-paths-webpack-plugin-2.4.0.tgz", + "integrity": "sha1-22QGbGQi7tLgjMFLmGykN5bbxtQ=", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npm.taobao.org/caseless/download/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.nlark.com/chalk/download/chalk-2.4.2.tgz?cache=0&sync_timestamp=1618995367379&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fchalk%2Fdownload%2Fchalk-2.4.2.tgz", + "integrity": "sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ=", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.nlark.com/chardet/download/chardet-0.7.0.tgz", + "integrity": "sha1-kAlISfCTfy7twkJdDSip5fDLrZ4=", + "dev": true + }, + "check-types": { + "version": "8.0.3", + "resolved": "https://registry.nlark.com/check-types/download/check-types-8.0.3.tgz", + "integrity": "sha1-M1bMoZyIlUTy16le1JzlCKDs9VI=", + "dev": true + }, + "chokidar": { + "version": "3.5.1", + "resolved": "https://registry.nlark.com/chokidar/download/chokidar-3.5.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fchokidar%2Fdownload%2Fchokidar-3.5.1.tgz", + "integrity": "sha1-7pznu+vSt59J8wR5nVRo4x4U5oo=", + "dev": true, + "optional": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.3.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + }, + "dependencies": { + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npm.taobao.org/braces/download/braces-3.0.2.tgz", + "integrity": "sha1-NFThpGLujVmeI23zNs2epPiv4Qc=", + "dev": true, + "optional": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npm.taobao.org/fill-range/download/fill-range-7.0.1.tgz", + "integrity": "sha1-GRmmp8df44ssfHflGYU12prN2kA=", + "dev": true, + "optional": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.nlark.com/is-number/download/is-number-7.0.0.tgz", + "integrity": "sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss=", + "dev": true, + "optional": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.nlark.com/to-regex-range/download/to-regex-range-5.0.1.tgz", + "integrity": "sha1-FkjESq58jZiKMmAY7XL1tN0DkuQ=", + "dev": true, + "optional": true, + "requires": { + "is-number": "^7.0.0" + } + } + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.nlark.com/chownr/download/chownr-1.1.4.tgz", + "integrity": "sha1-b8nXtC0ypYNZYzdmbn0ICE2izGs=", + "dev": true + }, + "chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.nlark.com/chrome-trace-event/download/chrome-trace-event-1.0.3.tgz", + "integrity": "sha1-EBXs7UdB4V0GZkqVfbv1DQQeJqw=", + "dev": true + }, + "ci-info": { + "version": "1.6.0", + "resolved": "https://registry.nlark.com/ci-info/download/ci-info-1.6.0.tgz?cache=0&sync_timestamp=1622039942508&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fci-info%2Fdownload%2Fci-info-1.6.0.tgz", + "integrity": "sha1-LKINu5zrMtRSSmgzAzE/AwSx5Jc=", + "dev": true + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.nlark.com/cipher-base/download/cipher-base-1.0.4.tgz", + "integrity": "sha1-h2Dk7MJy9MNjUy+SbYdKriwTl94=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npm.taobao.org/class-utils/download/class-utils-0.3.6.tgz", + "integrity": "sha1-+TNprouafOAv1B+q0MqDAzGQxGM=", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "clean-css": { + "version": "4.2.3", + "resolved": "https://registry.npm.taobao.org/clean-css/download/clean-css-4.2.3.tgz?cache=0&sync_timestamp=1616153455026&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fclean-css%2Fdownload%2Fclean-css-4.2.3.tgz", + "integrity": "sha1-UHtd59l7SO5T2ErbAWD/YhY4D3g=", + "dev": true, + "requires": { + "source-map": "~0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "dev": true + } + } + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npm.taobao.org/cli-cursor/download/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "cli-highlight": { + "version": "2.1.11", + "resolved": "https://registry.npm.taobao.org/cli-highlight/download/cli-highlight-2.1.11.tgz?cache=0&sync_timestamp=1616955054342&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcli-highlight%2Fdownload%2Fcli-highlight-2.1.11.tgz", + "integrity": "sha1-SXNvpFLwqvT65YDjCssmgo0twb8=", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "highlight.js": "^10.7.1", + "mz": "^2.4.0", + "parse5": "^5.1.1", + "parse5-htmlparser2-tree-adapter": "^6.0.0", + "yargs": "^16.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.nlark.com/ansi-styles/download/ansi-styles-4.3.0.tgz", + "integrity": "sha1-7dgDYornHATIWuegkG7a00tkiTc=", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.nlark.com/chalk/download/chalk-4.1.1.tgz?cache=0&sync_timestamp=1618995367379&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fchalk%2Fdownload%2Fchalk-4.1.1.tgz", + "integrity": "sha1-yAs/qyi/Y3HmhjMl7uZ+YYt35q0=", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz", + "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.nlark.com/color-name/download/color-name-1.1.4.tgz", + "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npm.taobao.org/has-flag/download/has-flag-4.0.0.tgz?cache=0&sync_timestamp=1618559676170&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhas-flag%2Fdownload%2Fhas-flag-4.0.0.tgz", + "integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s=", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.nlark.com/supports-color/download/supports-color-7.2.0.tgz?cache=0&sync_timestamp=1622293670728&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fsupports-color%2Fdownload%2Fsupports-color-7.2.0.tgz", + "integrity": "sha1-G33NyzK4E4gBs+R4umpRyqiWSNo=", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "cli-spinners": { + "version": "2.6.0", + "resolved": "https://registry.npm.taobao.org/cli-spinners/download/cli-spinners-2.6.0.tgz?cache=0&sync_timestamp=1616091572272&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcli-spinners%2Fdownload%2Fcli-spinners-2.6.0.tgz", + "integrity": "sha1-NsfcmPtqmna9YjjsP3fiQlYn6Tk=", + "dev": true + }, + "cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/cli-width/download/cli-width-3.0.0.tgz", + "integrity": "sha1-ovSEN6LKqaIkNueUvwceyeYc7fY=", + "dev": true + }, + "clipboardy": { + "version": "2.3.0", + "resolved": "https://registry.npm.taobao.org/clipboardy/download/clipboardy-2.3.0.tgz", + "integrity": "sha1-PCkDZQxo5GqRs4iYW8J3QofbopA=", + "dev": true, + "requires": { + "arch": "^2.1.1", + "execa": "^1.0.0", + "is-wsl": "^2.1.1" + }, + "dependencies": { + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.nlark.com/is-wsl/download/is-wsl-2.2.0.tgz", + "integrity": "sha1-dKTHbnfKn9P5MvKQwX6jJs0VcnE=", + "dev": true, + "requires": { + "is-docker": "^2.0.0" + } + } + } + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.nlark.com/cliui/download/cliui-6.0.0.tgz", + "integrity": "sha1-UR1wLAxOQcoVbX0OlgIfI+EyJbE=", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.nlark.com/ansi-styles/download/ansi-styles-4.3.0.tgz", + "integrity": "sha1-7dgDYornHATIWuegkG7a00tkiTc=", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz", + "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.nlark.com/color-name/download/color-name-1.1.4.tgz", + "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=", + "dev": true + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npm.taobao.org/wrap-ansi/download/wrap-ansi-6.2.0.tgz", + "integrity": "sha1-6Tk7oHEC5skaOyIUePAlfNKFblM=", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + } + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.nlark.com/clone/download/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "dev": true + }, + "coa": { + "version": "2.0.2", + "resolved": "https://registry.npm.taobao.org/coa/download/coa-2.0.2.tgz", + "integrity": "sha1-Q/bCEVG07yv1cYfbDXPeIp4+fsM=", + "dev": true, + "requires": { + "@types/q": "^1.5.1", + "chalk": "^2.4.1", + "q": "^1.1.2" + } + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.nlark.com/collection-visit/download/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color": { + "version": "3.1.3", + "resolved": "https://registry.nlark.com/color/download/color-3.1.3.tgz?cache=0&sync_timestamp=1618846945133&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fcolor%2Fdownload%2Fcolor-3.1.3.tgz", + "integrity": "sha1-ymf7TnuX1hHc3jns7tQiBn2RWW4=", + "dev": true, + "requires": { + "color-convert": "^1.9.1", + "color-string": "^1.5.4" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-1.9.3.tgz", + "integrity": "sha1-u3GFBpDh8TZWfeYp0tVHHe2kweg=", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.nlark.com/color-name/download/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "color-string": { + "version": "1.5.5", + "resolved": "https://registry.nlark.com/color-string/download/color-string-1.5.5.tgz", + "integrity": "sha1-ZUdKjw50OWJfPSemoZ2J/EUiMBQ=", + "dev": true, + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "colorette": { + "version": "1.2.2", + "resolved": "https://registry.npm.taobao.org/colorette/download/colorette-1.2.2.tgz?cache=0&sync_timestamp=1614259623635&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcolorette%2Fdownload%2Fcolorette-1.2.2.tgz", + "integrity": "sha1-y8x51emcrqLb8Q6zom/Ys+as+pQ=", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npm.taobao.org/combined-stream/download/combined-stream-1.0.8.tgz", + "integrity": "sha1-w9RaizT9cwYxoRCoolIGgrMdWn8=", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.nlark.com/commander/download/commander-2.20.3.tgz?cache=0&sync_timestamp=1622446257852&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fcommander%2Fdownload%2Fcommander-2.20.3.tgz", + "integrity": "sha1-/UhehMA+tIgcIHIrpIA16FMa6zM=", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npm.taobao.org/commondir/download/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.nlark.com/component-emitter/download/component-emitter-1.3.0.tgz", + "integrity": "sha1-FuQHD7qK4ptnnyIVhT7hgasuq8A=", + "dev": true + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.nlark.com/compressible/download/compressible-2.0.18.tgz", + "integrity": "sha1-r1PMprBw1MPAdQ+9dyhqbXzEb7o=", + "dev": true, + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npm.taobao.org/compression/download/compression-1.7.4.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcompression%2Fdownload%2Fcompression-1.7.4.tgz", + "integrity": "sha1-lVI+/xcMpXwpoMpB5v4TH0Hlu48=", + "dev": true, + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/bytes/download/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.nlark.com/debug/download/debug-2.6.9.tgz?cache=0&sync_timestamp=1618847042350&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdebug%2Fdownload%2Fdebug-2.6.9.tgz", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz?cache=0&sync_timestamp=1607433950466&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.nlark.com/concat-map/download/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.nlark.com/concat-stream/download/concat-stream-1.6.2.tgz", + "integrity": "sha1-kEvfGUzTEi/Gdcd/xKw9T/D9GjQ=", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.nlark.com/connect-history-api-fallback/download/connect-history-api-fallback-1.6.0.tgz?cache=0&sync_timestamp=1618847040596&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fconnect-history-api-fallback%2Fdownload%2Fconnect-history-api-fallback-1.6.0.tgz", + "integrity": "sha1-izIIk1kwjRERFdgcrT/Oq4iPl7w=", + "dev": true + }, + "console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.nlark.com/console-browserify/download/console-browserify-1.2.0.tgz", + "integrity": "sha1-ZwY871fOts9Jk6KrOlWECujEkzY=", + "dev": true + }, + "consolidate": { + "version": "0.15.1", + "resolved": "https://registry.npm.taobao.org/consolidate/download/consolidate-0.15.1.tgz", + "integrity": "sha1-IasEMjXHGgfUXZqtmFk7DbpWurc=", + "dev": true, + "requires": { + "bluebird": "^3.1.1" + } + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.nlark.com/constants-browserify/download/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", + "dev": true + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npm.taobao.org/content-disposition/download/content-disposition-0.5.3.tgz", + "integrity": "sha1-4TDK9+cnkIfFYWwgB9BIVpiYT70=", + "dev": true, + "requires": { + "safe-buffer": "5.1.2" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.nlark.com/content-type/download/content-type-1.0.4.tgz", + "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=", + "dev": true + }, + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npm.taobao.org/convert-source-map/download/convert-source-map-1.7.0.tgz", + "integrity": "sha1-F6LLiC1/d9NJBYXizmxSRCSjpEI=", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npm.taobao.org/cookie/download/cookie-0.4.0.tgz", + "integrity": "sha1-vrQ35wIrO21JAZ0IhmUwPr6cFLo=", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npm.taobao.org/cookie-signature/download/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "dev": true + }, + "copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.nlark.com/copy-concurrently/download/copy-concurrently-1.0.5.tgz", + "integrity": "sha1-kilzmMrjSTf8r9bsgTnBgFHwteA=", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npm.taobao.org/copy-descriptor/download/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "copy-webpack-plugin": { + "version": "5.1.2", + "resolved": "https://registry.nlark.com/copy-webpack-plugin/download/copy-webpack-plugin-5.1.2.tgz?cache=0&sync_timestamp=1621607252385&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fcopy-webpack-plugin%2Fdownload%2Fcopy-webpack-plugin-5.1.2.tgz", + "integrity": "sha1-ioieHcr6bJHGzUvhrRWPHTgjuuI=", + "dev": true, + "requires": { + "cacache": "^12.0.3", + "find-cache-dir": "^2.1.0", + "glob-parent": "^3.1.0", + "globby": "^7.1.1", + "is-glob": "^4.0.1", + "loader-utils": "^1.2.3", + "minimatch": "^3.0.4", + "normalize-path": "^3.0.0", + "p-limit": "^2.2.1", + "schema-utils": "^1.0.0", + "serialize-javascript": "^4.0.0", + "webpack-log": "^2.0.0" + }, + "dependencies": { + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npm.taobao.org/find-cache-dir/download/find-cache-dir-2.1.0.tgz", + "integrity": "sha1-jQ+UzRP+Q8bHwmGg2GEVypGMBfc=", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.nlark.com/find-up/download/find-up-3.0.0.tgz?cache=0&sync_timestamp=1618846778775&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ffind-up%2Fdownload%2Ffind-up-3.0.0.tgz", + "integrity": "sha1-SRafHXmTQwZG2mHsxa41XCHJe3M=", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.nlark.com/glob-parent/download/glob-parent-3.1.0.tgz?cache=0&sync_timestamp=1620073321855&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fglob-parent%2Fdownload%2Fglob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npm.taobao.org/is-glob/download/is-glob-3.1.0.tgz?cache=0&sync_timestamp=1598237815612&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-glob%2Fdownload%2Fis-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "globby": { + "version": "7.1.1", + "resolved": "https://registry.nlark.com/globby/download/globby-7.1.1.tgz", + "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "dir-glob": "^2.0.0", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/pify/download/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npm.taobao.org/ignore/download/ignore-3.3.10.tgz", + "integrity": "sha1-Cpf7h2mG6AgcYxFg+PnziRV/AEM=", + "dev": true + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/locate-path/download/locate-path-3.0.0.tgz", + "integrity": "sha1-2+w7OrdZdYBxtY/ln8QYca8hQA4=", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npm.taobao.org/make-dir/download/make-dir-2.1.0.tgz", + "integrity": "sha1-XwMQ4YuL6JjMBwCSlaMK5B6R5vU=", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.nlark.com/p-locate/download/p-locate-3.0.0.tgz", + "integrity": "sha1-Mi1poFwCZLJZl9n0DNiokasAZKQ=", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.nlark.com/path-exists/download/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/pkg-dir/download/pkg-dir-3.0.0.tgz?cache=0&sync_timestamp=1602859045787&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpkg-dir%2Fdownload%2Fpkg-dir-3.0.0.tgz", + "integrity": "sha1-J0kCDyOe2ZCIGx9xIQ1R62UjvqM=", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-1.0.0.tgz", + "integrity": "sha1-C3mpMgTXtgDUsoUNH2bCo0lRx3A=", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.nlark.com/semver/download/semver-5.7.1.tgz?cache=0&sync_timestamp=1618847119601&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fsemver%2Fdownload%2Fsemver-5.7.1.tgz", + "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=", + "dev": true + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.nlark.com/slash/download/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + } + } + }, + "core-js": { + "version": "3.13.1", + "resolved": "https://registry.nlark.com/core-js/download/core-js-3.13.1.tgz", + "integrity": "sha1-MDA/q9U2OIkgYti06ALKx1men7c=" + }, + "core-js-compat": { + "version": "3.13.1", + "resolved": "https://registry.nlark.com/core-js-compat/download/core-js-compat-3.13.1.tgz?cache=0&sync_timestamp=1622278867592&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fcore-js-compat%2Fdownload%2Fcore-js-compat-3.13.1.tgz", + "integrity": "sha1-BURMqo8VO+DGfbA8+K247Alk5Y4=", + "dev": true, + "requires": { + "browserslist": "^4.16.6", + "semver": "7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.nlark.com/semver/download/semver-7.0.0.tgz?cache=0&sync_timestamp=1618847119601&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fsemver%2Fdownload%2Fsemver-7.0.0.tgz", + "integrity": "sha1-XzyjV2HkfgWyBsba/yz4FPAxa44=", + "dev": true + } + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.nlark.com/core-util-is/download/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npm.taobao.org/cosmiconfig/download/cosmiconfig-5.2.1.tgz", + "integrity": "sha1-BA9yaAnFked6F8CjYmykW08Wixo=", + "dev": true, + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + }, + "dependencies": { + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.nlark.com/parse-json/download/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + } + } + }, + "create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.nlark.com/create-ecdh/download/create-ecdh-4.0.4.tgz", + "integrity": "sha1-1uf0v/pmc2CFoHYv06YyaE2rzE4=", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npm.taobao.org/bn.js/download/bn.js-4.12.0.tgz", + "integrity": "sha1-d1s/J477uXGO7HNh9IP7Nvu/6og=", + "dev": true + } + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npm.taobao.org/create-hash/download/create-hash-1.2.0.tgz", + "integrity": "sha1-iJB4rxGmN1a8+1m9IhmWvjqe8ZY=", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.nlark.com/create-hmac/download/create-hmac-1.1.7.tgz", + "integrity": "sha1-aRcMeLOrlXFHsriwRXLkfq0iQ/8=", + "dev": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npm.taobao.org/cross-spawn/download/cross-spawn-6.0.5.tgz", + "integrity": "sha1-Sl7Hxk364iw6FBJNus3uhG2Ay8Q=", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.nlark.com/semver/download/semver-5.7.1.tgz?cache=0&sync_timestamp=1618847119601&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fsemver%2Fdownload%2Fsemver-5.7.1.tgz", + "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=", + "dev": true + } + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npm.taobao.org/crypto-browserify/download/crypto-browserify-3.12.0.tgz", + "integrity": "sha1-OWz58xN/A+S45TLFj2mCVOAPgOw=", + "dev": true, + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "css": { + "version": "2.2.4", + "resolved": "https://registry.npm.taobao.org/css/download/css-2.2.4.tgz", + "integrity": "sha1-xkZ1XHOXHyu6amAeLPL9cbEpiSk=", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "source-map": "^0.6.1", + "source-map-resolve": "^0.5.2", + "urix": "^0.1.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "dev": true + } + } + }, + "css-color-names": { + "version": "0.0.4", + "resolved": "https://registry.nlark.com/css-color-names/download/css-color-names-0.0.4.tgz", + "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", + "dev": true + }, + "css-declaration-sorter": { + "version": "4.0.1", + "resolved": "https://registry.nlark.com/css-declaration-sorter/download/css-declaration-sorter-4.0.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fcss-declaration-sorter%2Fdownload%2Fcss-declaration-sorter-4.0.1.tgz", + "integrity": "sha1-wZiUD2OnbX42wecQGLABchBUyyI=", + "dev": true, + "requires": { + "postcss": "^7.0.1", + "timsort": "^0.3.0" + } + }, + "css-loader": { + "version": "3.6.0", + "resolved": "https://registry.nlark.com/css-loader/download/css-loader-3.6.0.tgz?cache=0&sync_timestamp=1621865043272&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fcss-loader%2Fdownload%2Fcss-loader-3.6.0.tgz", + "integrity": "sha1-Lkssfm4tJ/jI8o9hv/zS5ske9kU=", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "cssesc": "^3.0.0", + "icss-utils": "^4.1.1", + "loader-utils": "^1.2.3", + "normalize-path": "^3.0.0", + "postcss": "^7.0.32", + "postcss-modules-extract-imports": "^2.0.0", + "postcss-modules-local-by-default": "^3.0.2", + "postcss-modules-scope": "^2.2.0", + "postcss-modules-values": "^3.0.0", + "postcss-value-parser": "^4.1.0", + "schema-utils": "^2.7.0", + "semver": "^6.3.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.nlark.com/camelcase/download/camelcase-5.3.1.tgz", + "integrity": "sha1-48mzFWnhBoEd8kL3FXJaH0xJQyA=", + "dev": true + } + } + }, + "css-parse": { + "version": "2.0.0", + "resolved": "https://registry.nlark.com/css-parse/download/css-parse-2.0.0.tgz", + "integrity": "sha1-pGjuZnwW2BzPBcWMONKpfHgNv9Q=", + "dev": true, + "requires": { + "css": "^2.0.0" + } + }, + "css-select": { + "version": "2.1.0", + "resolved": "https://registry.nlark.com/css-select/download/css-select-2.1.0.tgz?cache=0&sync_timestamp=1618846786574&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fcss-select%2Fdownload%2Fcss-select-2.1.0.tgz", + "integrity": "sha1-ajRlM1ZjWTSoG6ymjQJVQyEF2+8=", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^3.2.1", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + } + }, + "css-select-base-adapter": { + "version": "0.1.1", + "resolved": "https://registry.npm.taobao.org/css-select-base-adapter/download/css-select-base-adapter-0.1.1.tgz", + "integrity": "sha1-Oy/0lyzDYquIVhUHqVQIoUMhNdc=", + "dev": true + }, + "css-tree": { + "version": "1.0.0-alpha.37", + "resolved": "https://registry.nlark.com/css-tree/download/css-tree-1.0.0-alpha.37.tgz", + "integrity": "sha1-mL69YsTB2flg7DQM+fdSLjBwmiI=", + "dev": true, + "requires": { + "mdn-data": "2.0.4", + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "dev": true + } + } + }, + "css-what": { + "version": "3.4.2", + "resolved": "https://registry.nlark.com/css-what/download/css-what-3.4.2.tgz", + "integrity": "sha1-6nAm/LAXd+295SEk4h8yfnrpUOQ=", + "dev": true + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/cssesc/download/cssesc-3.0.0.tgz", + "integrity": "sha1-N3QZGZA7hoVl4cCep0dEXNGJg+4=", + "dev": true + }, + "cssnano": { + "version": "4.1.11", + "resolved": "https://registry.nlark.com/cssnano/download/cssnano-4.1.11.tgz", + "integrity": "sha1-x7X1uB2iacsf2YLLlgwSAJEMmpk=", + "dev": true, + "requires": { + "cosmiconfig": "^5.0.0", + "cssnano-preset-default": "^4.0.8", + "is-resolvable": "^1.0.0", + "postcss": "^7.0.0" + } + }, + "cssnano-preset-default": { + "version": "4.0.8", + "resolved": "https://registry.nlark.com/cssnano-preset-default/download/cssnano-preset-default-4.0.8.tgz", + "integrity": "sha1-kgYisfwelaNOiDggPxOXpQTy0/8=", + "dev": true, + "requires": { + "css-declaration-sorter": "^4.0.1", + "cssnano-util-raw-cache": "^4.0.1", + "postcss": "^7.0.0", + "postcss-calc": "^7.0.1", + "postcss-colormin": "^4.0.3", + "postcss-convert-values": "^4.0.1", + "postcss-discard-comments": "^4.0.2", + "postcss-discard-duplicates": "^4.0.2", + "postcss-discard-empty": "^4.0.1", + "postcss-discard-overridden": "^4.0.1", + "postcss-merge-longhand": "^4.0.11", + "postcss-merge-rules": "^4.0.3", + "postcss-minify-font-values": "^4.0.2", + "postcss-minify-gradients": "^4.0.2", + "postcss-minify-params": "^4.0.2", + "postcss-minify-selectors": "^4.0.2", + "postcss-normalize-charset": "^4.0.1", + "postcss-normalize-display-values": "^4.0.2", + "postcss-normalize-positions": "^4.0.2", + "postcss-normalize-repeat-style": "^4.0.2", + "postcss-normalize-string": "^4.0.2", + "postcss-normalize-timing-functions": "^4.0.2", + "postcss-normalize-unicode": "^4.0.1", + "postcss-normalize-url": "^4.0.1", + "postcss-normalize-whitespace": "^4.0.2", + "postcss-ordered-values": "^4.1.2", + "postcss-reduce-initial": "^4.0.3", + "postcss-reduce-transforms": "^4.0.2", + "postcss-svgo": "^4.0.3", + "postcss-unique-selectors": "^4.0.1" + } + }, + "cssnano-util-get-arguments": { + "version": "4.0.0", + "resolved": "https://registry.nlark.com/cssnano-util-get-arguments/download/cssnano-util-get-arguments-4.0.0.tgz", + "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=", + "dev": true + }, + "cssnano-util-get-match": { + "version": "4.0.0", + "resolved": "https://registry.nlark.com/cssnano-util-get-match/download/cssnano-util-get-match-4.0.0.tgz", + "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=", + "dev": true + }, + "cssnano-util-raw-cache": { + "version": "4.0.1", + "resolved": "https://registry.npm.taobao.org/cssnano-util-raw-cache/download/cssnano-util-raw-cache-4.0.1.tgz", + "integrity": "sha1-sm1f1fcqEd/np4RvtMZyYPlr8oI=", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "cssnano-util-same-parent": { + "version": "4.0.1", + "resolved": "https://registry.nlark.com/cssnano-util-same-parent/download/cssnano-util-same-parent-4.0.1.tgz", + "integrity": "sha1-V0CC+yhZ0ttDOFWDXZqEVuoYu/M=", + "dev": true + }, + "csso": { + "version": "4.2.0", + "resolved": "https://registry.npm.taobao.org/csso/download/csso-4.2.0.tgz?cache=0&sync_timestamp=1606408777341&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcsso%2Fdownload%2Fcsso-4.2.0.tgz", + "integrity": "sha1-6jpWE0bo3J9UbW/r7dUBh884lSk=", + "dev": true, + "requires": { + "css-tree": "^1.1.2" + }, + "dependencies": { + "css-tree": { + "version": "1.1.3", + "resolved": "https://registry.nlark.com/css-tree/download/css-tree-1.1.3.tgz", + "integrity": "sha1-60hw+2/XcHMn7JXC/yqwm16NuR0=", + "dev": true, + "requires": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + } + }, + "mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.nlark.com/mdn-data/download/mdn-data-2.0.14.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fmdn-data%2Fdownload%2Fmdn-data-2.0.14.tgz", + "integrity": "sha1-cRP8QoGRfWPOKbQ0RvcB5owlulA=", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "dev": true + } + } + }, + "csstype": { + "version": "2.6.17", + "resolved": "https://registry.nlark.com/csstype/download/csstype-2.6.17.tgz?cache=0&sync_timestamp=1618818466657&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fcsstype%2Fdownload%2Fcsstype-2.6.17.tgz", + "integrity": "sha1-TPMOuH4dGgBdi2UQ+VKSQT9qHA4=" + }, + "cyclist": { + "version": "1.0.1", + "resolved": "https://registry.nlark.com/cyclist/download/cyclist-1.0.1.tgz", + "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", + "dev": true + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npm.taobao.org/dashdash/download/dashdash-1.14.1.tgz?cache=0&sync_timestamp=1601073454623&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdashdash%2Fdownload%2Fdashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "debug": { + "version": "4.3.1", + "resolved": "https://registry.nlark.com/debug/download/debug-4.3.1.tgz?cache=0&sync_timestamp=1618847042350&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdebug%2Fdownload%2Fdebug-4.3.1.tgz", + "integrity": "sha1-8NIpxQXgxtjEmsVT0bE9wYP2su4=", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.nlark.com/decamelize/download/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.nlark.com/decode-uri-component/download/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "deep-equal": { + "version": "1.1.1", + "resolved": "https://registry.npm.taobao.org/deep-equal/download/deep-equal-1.1.1.tgz?cache=0&sync_timestamp=1606859714626&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdeep-equal%2Fdownload%2Fdeep-equal-1.1.1.tgz", + "integrity": "sha1-tcmMlCzv+vfLBR4k4UNKJaLmB2o=", + "dev": true, + "requires": { + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.1", + "is-regex": "^1.0.4", + "object-is": "^1.0.1", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.2.0" + } + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.nlark.com/deep-is/download/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "deepmerge": { + "version": "1.5.2", + "resolved": "https://registry.npm.taobao.org/deepmerge/download/deepmerge-1.5.2.tgz", + "integrity": "sha1-EEmdhohEza1P7ghC34x/bwyVp1M=", + "dev": true + }, + "default-gateway": { + "version": "5.0.5", + "resolved": "https://registry.npm.taobao.org/default-gateway/download/default-gateway-5.0.5.tgz?cache=0&sync_timestamp=1610365756089&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdefault-gateway%2Fdownload%2Fdefault-gateway-5.0.5.tgz", + "integrity": "sha1-T9a9XShV05s0zFpZUFSG6ar8mxA=", + "dev": true, + "requires": { + "execa": "^3.3.0" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npm.taobao.org/cross-spawn/download/cross-spawn-7.0.3.tgz", + "integrity": "sha1-9zqFudXUHQRVUcF34ogtSshXKKY=", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "execa": { + "version": "3.4.0", + "resolved": "https://registry.nlark.com/execa/download/execa-3.4.0.tgz?cache=0&sync_timestamp=1622396637949&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fexeca%2Fdownload%2Fexeca-3.4.0.tgz", + "integrity": "sha1-wI7UVQ72XYWPrCaf/IVyRG8364k=", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "p-finally": "^2.0.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + } + }, + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npm.taobao.org/get-stream/download/get-stream-5.2.0.tgz", + "integrity": "sha1-SWaheV7lrOZecGxLe+txJX1uItM=", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.nlark.com/is-stream/download/is-stream-2.0.0.tgz", + "integrity": "sha1-venDJoDW+uBBKdasnZIc54FfeOM=", + "dev": true + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npm.taobao.org/mimic-fn/download/mimic-fn-2.1.0.tgz", + "integrity": "sha1-ftLCzMyvhNP/y3pptXcR/CCDQBs=", + "dev": true + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npm.taobao.org/npm-run-path/download/npm-run-path-4.0.1.tgz", + "integrity": "sha1-t+zR5e1T2o43pV4cImnguX7XSOo=", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npm.taobao.org/onetime/download/onetime-5.1.2.tgz", + "integrity": "sha1-0Oluu1awdHbfHdnEgG5SN5hcpF4=", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "p-finally": { + "version": "2.0.1", + "resolved": "https://registry.npm.taobao.org/p-finally/download/p-finally-2.0.1.tgz", + "integrity": "sha1-vW/KqcVZoJa2gIBvTWV7Pw8kBWE=", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npm.taobao.org/path-key/download/path-key-3.1.1.tgz?cache=0&sync_timestamp=1617971695678&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpath-key%2Fdownload%2Fpath-key-3.1.1.tgz", + "integrity": "sha1-WB9q3mWMu6ZaDTOA3ndTKVBU83U=", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/shebang-command/download/shebang-command-2.0.0.tgz", + "integrity": "sha1-zNCvT4g1+9wmW4JGGq8MNmY/NOo=", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/shebang-regex/download/shebang-regex-3.0.0.tgz", + "integrity": "sha1-rhbxZE2HPsrYQ7AwexQzYtTEIXI=", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.nlark.com/which/download/which-2.0.2.tgz", + "integrity": "sha1-fGqN0KY2oDJ+ELWckobu6T8/UbE=", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "defaults": { + "version": "1.0.3", + "resolved": "https://registry.npm.taobao.org/defaults/download/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "dev": true, + "requires": { + "clone": "^1.0.2" + } + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.nlark.com/define-properties/download/define-properties-1.1.3.tgz?cache=0&sync_timestamp=1618847174317&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdefine-properties%2Fdownload%2Fdefine-properties-1.1.3.tgz", + "integrity": "sha1-z4jabL7ib+bbcJT2HYcMvYTO6fE=", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-2.0.2.tgz", + "integrity": "sha1-1Flono1lS6d+AqgX+HENcCyxbp0=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.nlark.com/is-accessor-descriptor/download/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.nlark.com/is-data-descriptor/download/is-data-descriptor-1.0.0.tgz", + "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/is-descriptor/download/is-descriptor-1.0.2.tgz", + "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "del": { + "version": "4.1.1", + "resolved": "https://registry.npm.taobao.org/del/download/del-4.1.1.tgz?cache=0&sync_timestamp=1601076882347&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdel%2Fdownload%2Fdel-4.1.1.tgz", + "integrity": "sha1-no8RciLqRKMf86FWwEm5kFKp8LQ=", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "globby": "^6.1.0", + "is-path-cwd": "^2.0.0", + "is-path-in-cwd": "^2.0.0", + "p-map": "^2.0.0", + "pify": "^4.0.1", + "rimraf": "^2.6.3" + }, + "dependencies": { + "globby": { + "version": "6.1.0", + "resolved": "https://registry.nlark.com/globby/download/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npm.taobao.org/pify/download/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/delayed-stream/download/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.nlark.com/depd/download/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + }, + "des.js": { + "version": "1.0.1", + "resolved": "https://registry.npm.taobao.org/des.js/download/des.js-1.0.1.tgz", + "integrity": "sha1-U4IULhvcU/hdhtU+X0qn3rkeCEM=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.nlark.com/destroy/download/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "dev": true + }, + "detect-node": { + "version": "2.1.0", + "resolved": "https://registry.nlark.com/detect-node/download/detect-node-2.1.0.tgz?cache=0&sync_timestamp=1621147029891&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdetect-node%2Fdownload%2Fdetect-node-2.1.0.tgz", + "integrity": "sha1-yccHdaScPQO8LAbZpzvlUPl4+LE=", + "dev": true + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.nlark.com/diffie-hellman/download/diffie-hellman-5.0.3.tgz", + "integrity": "sha1-QOjumPVaIUlgcUaSHGPhrl89KHU=", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npm.taobao.org/bn.js/download/bn.js-4.12.0.tgz", + "integrity": "sha1-d1s/J477uXGO7HNh9IP7Nvu/6og=", + "dev": true + } + } + }, + "dir-glob": { + "version": "2.2.2", + "resolved": "https://registry.npm.taobao.org/dir-glob/download/dir-glob-2.2.2.tgz", + "integrity": "sha1-+gnwaUFTyJGLGLoN6vrpR2n8UMQ=", + "dev": true, + "requires": { + "path-type": "^3.0.0" + } + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.nlark.com/dns-equal/download/dns-equal-1.0.0.tgz", + "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", + "dev": true + }, + "dns-packet": { + "version": "1.3.4", + "resolved": "https://registry.nlark.com/dns-packet/download/dns-packet-1.3.4.tgz", + "integrity": "sha1-40VQZYJKJQe6iGxVqJljuxB97G8=", + "dev": true, + "requires": { + "ip": "^1.1.0", + "safe-buffer": "^5.0.1" + } + }, + "dns-txt": { + "version": "2.0.2", + "resolved": "https://registry.npm.taobao.org/dns-txt/download/dns-txt-2.0.2.tgz", + "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", + "dev": true, + "requires": { + "buffer-indexof": "^1.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.nlark.com/doctrine/download/doctrine-3.0.0.tgz", + "integrity": "sha1-rd6+rXKmV023g2OdyHoSF3OXOWE=", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npm.taobao.org/dom-converter/download/dom-converter-0.2.0.tgz", + "integrity": "sha1-ZyGp2u4uKTaClVtq/kFncWJ7t2g=", + "dev": true, + "requires": { + "utila": "~0.4" + } + }, + "dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.nlark.com/dom-serializer/download/dom-serializer-0.2.2.tgz?cache=0&sync_timestamp=1621256830355&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdom-serializer%2Fdownload%2Fdom-serializer-0.2.2.tgz", + "integrity": "sha1-GvuB9TNxcXXUeGVd68XjMtn5u1E=", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + }, + "dependencies": { + "domelementtype": { + "version": "2.2.0", + "resolved": "https://registry.npm.taobao.org/domelementtype/download/domelementtype-2.2.0.tgz?cache=0&sync_timestamp=1617298554829&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdomelementtype%2Fdownload%2Fdomelementtype-2.2.0.tgz", + "integrity": "sha1-mgtsJ4LtahxzI9QiZxg9+b2LHVc=", + "dev": true + } + } + }, + "domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.nlark.com/domain-browser/download/domain-browser-1.2.0.tgz", + "integrity": "sha1-PTH1AZGmdJ3RN1p/Ui6CPULlTto=", + "dev": true + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npm.taobao.org/domelementtype/download/domelementtype-1.3.1.tgz?cache=0&sync_timestamp=1617298554829&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdomelementtype%2Fdownload%2Fdomelementtype-1.3.1.tgz", + "integrity": "sha1-0EjESzew0Qp/Kj1f7j9DM9eQSB8=", + "dev": true + }, + "domhandler": { + "version": "2.4.2", + "resolved": "https://registry.npm.taobao.org/domhandler/download/domhandler-2.4.2.tgz?cache=0&sync_timestamp=1618563954924&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdomhandler%2Fdownload%2Fdomhandler-2.4.2.tgz", + "integrity": "sha1-iAUJfpM9ZehVRvcm1g9euItE+AM=", + "dev": true, + "requires": { + "domelementtype": "1" + } + }, + "domutils": { + "version": "1.7.0", + "resolved": "https://registry.nlark.com/domutils/download/domutils-1.7.0.tgz", + "integrity": "sha1-Vuo0HoNOBuZ0ivehyyXaZ+qfjCo=", + "dev": true, + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.nlark.com/dot-prop/download/dot-prop-5.3.0.tgz", + "integrity": "sha1-kMzOcIzZzYLMTcjD3dmr3VWyDog=", + "dev": true, + "requires": { + "is-obj": "^2.0.0" + } + }, + "dotenv": { + "version": "8.6.0", + "resolved": "https://registry.nlark.com/dotenv/download/dotenv-8.6.0.tgz?cache=0&sync_timestamp=1621627076012&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdotenv%2Fdownload%2Fdotenv-8.6.0.tgz", + "integrity": "sha1-Bhr2ZNGff02PxuT/m1hM4jety4s=", + "dev": true + }, + "dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npm.taobao.org/dotenv-expand/download/dotenv-expand-5.1.0.tgz?cache=0&sync_timestamp=1603163578680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdotenv-expand%2Fdownload%2Fdotenv-expand-5.1.0.tgz", + "integrity": "sha1-P7rwIL/XlIhAcuomsel5HUWmKfA=", + "dev": true + }, + "duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npm.taobao.org/duplexer/download/duplexer-0.1.2.tgz", + "integrity": "sha1-Or5DrvODX4rgd9E23c4PJ2sEAOY=", + "dev": true + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.nlark.com/duplexify/download/duplexify-3.7.1.tgz", + "integrity": "sha1-Kk31MX9sz9kfhtb9JdjYoQO4gwk=", + "dev": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "easy-stack": { + "version": "1.0.1", + "resolved": "https://registry.nlark.com/easy-stack/download/easy-stack-1.0.1.tgz", + "integrity": "sha1-iv5CZGJpiMq7EfPHBMzQyDVBEGY=", + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npm.taobao.org/ecc-jsbn/download/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "ejs": { + "version": "2.7.4", + "resolved": "https://registry.nlark.com/ejs/download/ejs-2.7.4.tgz", + "integrity": "sha1-SGYSh1c9zFPjZsehrlLDoSDuybo=", + "dev": true + }, + "electron-to-chromium": { + "version": "1.3.742", + "resolved": "https://registry.nlark.com/electron-to-chromium/download/electron-to-chromium-1.3.742.tgz?cache=0&sync_timestamp=1622240108830&other_urls=https%3A%2F%2Fregistry.nlark.com%2Felectron-to-chromium%2Fdownload%2Felectron-to-chromium-1.3.742.tgz", + "integrity": "sha1-ciMhWsu9OlKEli68tt+F2IuV8gA=", + "dev": true + }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npm.taobao.org/elliptic/download/elliptic-6.5.4.tgz", + "integrity": "sha1-2jfOvTHnmhNn6UG1ku0fvr1Yq7s=", + "dev": true, + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npm.taobao.org/bn.js/download/bn.js-4.12.0.tgz", + "integrity": "sha1-d1s/J477uXGO7HNh9IP7Nvu/6og=", + "dev": true + } + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.nlark.com/emoji-regex/download/emoji-regex-8.0.0.tgz", + "integrity": "sha1-6Bj9ac5cz8tARZT4QpY79TFkzDc=", + "dev": true + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/emojis-list/download/emojis-list-3.0.0.tgz", + "integrity": "sha1-VXBmIEatKeLpFucariYKvf9Pang=", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/encodeurl/download/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.nlark.com/end-of-stream/download/end-of-stream-1.4.4.tgz", + "integrity": "sha1-WuZKX0UFe682JuwU2gyl5LJDHrA=", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "enhanced-resolve": { + "version": "4.5.0", + "resolved": "https://registry.nlark.com/enhanced-resolve/download/enhanced-resolve-4.5.0.tgz?cache=0&sync_timestamp=1620663108627&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fenhanced-resolve%2Fdownload%2Fenhanced-resolve-4.5.0.tgz", + "integrity": "sha1-Lzz9hNvjtIfxjy2y7x4GSlccpew=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + }, + "dependencies": { + "memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.nlark.com/memory-fs/download/memory-fs-0.5.0.tgz", + "integrity": "sha1-MkwBKIuIZSlm0WHbd4OHIIRajjw=", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + } + } + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npm.taobao.org/entities/download/entities-2.2.0.tgz", + "integrity": "sha1-CY3JDruD2N/6CJ1VJWs1HTTE2lU=", + "dev": true + }, + "errno": { + "version": "0.1.8", + "resolved": "https://registry.npm.taobao.org/errno/download/errno-0.1.8.tgz", + "integrity": "sha1-i7Ppx9Rjvkl2/4iPdrSAnrwugR8=", + "dev": true, + "requires": { + "prr": "~1.0.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.nlark.com/error-ex/download/error-ex-1.3.2.tgz", + "integrity": "sha1-tKxAZIEH/c3PriQvQovqihTU8b8=", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "error-stack-parser": { + "version": "2.0.6", + "resolved": "https://registry.npm.taobao.org/error-stack-parser/download/error-stack-parser-2.0.6.tgz", + "integrity": "sha1-WpmnB716TFinl5AtSNgoA+3mqtg=", + "dev": true, + "requires": { + "stackframe": "^1.1.1" + } + }, + "es-abstract": { + "version": "1.18.3", + "resolved": "https://registry.nlark.com/es-abstract/download/es-abstract-1.18.3.tgz", + "integrity": "sha1-JcTDOAonqiA8RLK2hbupTaMbY+A=", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "is-callable": "^1.2.3", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.3", + "is-string": "^1.0.6", + "object-inspect": "^1.10.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npm.taobao.org/es-to-primitive/download/es-to-primitive-1.2.1.tgz", + "integrity": "sha1-5VzUyc3BiLzvsDs2bHNjI/xciYo=", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npm.taobao.org/escalade/download/escalade-3.1.1.tgz?cache=0&sync_timestamp=1602567306925&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fescalade%2Fdownload%2Fescalade-3.1.1.tgz", + "integrity": "sha1-2M/ccACWXFoBdLSoLqpcBVJ0LkA=", + "dev": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npm.taobao.org/escape-html/download/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.nlark.com/escape-string-regexp/download/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eslint": { + "version": "6.8.0", + "resolved": "https://registry.nlark.com/eslint/download/eslint-6.8.0.tgz", + "integrity": "sha1-YiYtZylzn5J1cjgkMC+yJ8jJP/s=", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npm.taobao.org/eslint-scope/download/eslint-scope-5.1.1.tgz?cache=0&sync_timestamp=1599933693172&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Feslint-scope%2Fdownload%2Feslint-scope-5.1.1.tgz", + "integrity": "sha1-54blmmbLkrP2wfsNUIqrF0hI9Iw=", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.nlark.com/globals/download/globals-12.4.0.tgz", + "integrity": "sha1-oYgTV2pBsAokqX5/gVkYwuGZJfg=", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npm.taobao.org/import-fresh/download/import-fresh-3.3.0.tgz?cache=0&sync_timestamp=1608469561643&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fimport-fresh%2Fdownload%2Fimport-fresh-3.3.0.tgz", + "integrity": "sha1-NxYsJfy566oublPVtNiM4X2eDCs=", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.nlark.com/resolve-from/download/resolve-from-4.0.0.tgz", + "integrity": "sha1-SrzYUq0y3Xuqv+m0DgCjbbXzkuY=", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-5.2.0.tgz?cache=0&sync_timestamp=1618553320591&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-5.2.0.tgz", + "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.nlark.com/type-fest/download/type-fest-0.8.1.tgz?cache=0&sync_timestamp=1621402446336&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ftype-fest%2Fdownload%2Ftype-fest-0.8.1.tgz", + "integrity": "sha1-CeJJ696FHTseSNJ8EFREZn8XuD0=", + "dev": true + } + } + }, + "eslint-loader": { + "version": "2.2.1", + "resolved": "https://registry.npm.taobao.org/eslint-loader/download/eslint-loader-2.2.1.tgz?cache=0&sync_timestamp=1601214436656&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Feslint-loader%2Fdownload%2Feslint-loader-2.2.1.tgz", + "integrity": "sha1-KLnBLaVAV68IReKmEScBova/gzc=", + "dev": true, + "requires": { + "loader-fs-cache": "^1.0.0", + "loader-utils": "^1.0.2", + "object-assign": "^4.0.1", + "object-hash": "^1.1.4", + "rimraf": "^2.6.1" + } + }, + "eslint-plugin-vue": { + "version": "7.10.0", + "resolved": "https://registry.nlark.com/eslint-plugin-vue/download/eslint-plugin-vue-7.10.0.tgz", + "integrity": "sha1-JRdJqpngieCFJ18BEELG50GJ+Jo=", + "dev": true, + "requires": { + "eslint-utils": "^2.1.0", + "natural-compare": "^1.4.0", + "semver": "^7.3.2", + "vue-eslint-parser": "^7.6.0" + }, + "dependencies": { + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.nlark.com/eslint-utils/download/eslint-utils-2.1.0.tgz?cache=0&sync_timestamp=1620975590529&other_urls=https%3A%2F%2Fregistry.nlark.com%2Feslint-utils%2Fdownload%2Feslint-utils-2.1.0.tgz", + "integrity": "sha1-0t5eA0JOcH3BDHQGjd7a5wh0Gyc=", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.nlark.com/lru-cache/download/lru-cache-6.0.0.tgz", + "integrity": "sha1-bW/mVw69lqr5D8rR2vo7JWbbOpQ=", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.nlark.com/semver/download/semver-7.3.5.tgz?cache=0&sync_timestamp=1618847119601&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fsemver%2Fdownload%2Fsemver-7.3.5.tgz", + "integrity": "sha1-C2Ich5NI2JmOSw5L6Us/EuYBjvc=", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npm.taobao.org/yallist/download/yallist-4.0.0.tgz", + "integrity": "sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI=", + "dev": true + } + } + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npm.taobao.org/eslint-scope/download/eslint-scope-4.0.3.tgz?cache=0&sync_timestamp=1599933693172&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Feslint-scope%2Fdownload%2Feslint-scope-4.0.3.tgz", + "integrity": "sha1-ygODMxD2iJoyZHgaqC5j65z+eEg=", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.nlark.com/eslint-utils/download/eslint-utils-1.4.3.tgz?cache=0&sync_timestamp=1620975590529&other_urls=https%3A%2F%2Fregistry.nlark.com%2Feslint-utils%2Fdownload%2Feslint-utils-1.4.3.tgz", + "integrity": "sha1-dP7HxU0Hdrb2fgJRBAtYBlZOmB8=", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.nlark.com/eslint-visitor-keys/download/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha1-MOvR73wv3/AcOk8VEESvJfqwUj4=", + "dev": true + }, + "espree": { + "version": "6.2.1", + "resolved": "https://registry.npm.taobao.org/espree/download/espree-6.2.1.tgz?cache=0&sync_timestamp=1607143966756&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fespree%2Fdownload%2Fespree-6.2.1.tgz", + "integrity": "sha1-d/xy4f10SiBSwg84pbV1gy6Cc0o=", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.nlark.com/acorn/download/acorn-7.4.1.tgz", + "integrity": "sha1-/q7SVZc9LndVW4PbwIhRpsY1IPo=", + "dev": true + } + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npm.taobao.org/esprima/download/esprima-4.0.1.tgz", + "integrity": "sha1-E7BM2z5sXRnfkatph6hpVhmwqnE=", + "dev": true + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.nlark.com/esquery/download/esquery-1.4.0.tgz", + "integrity": "sha1-IUj/w4uC6McFff7UhCWz5h8PJKU=", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.nlark.com/estraverse/download/estraverse-5.2.0.tgz", + "integrity": "sha1-MH30JUfmzHMk088DwVXVzbjFOIA=", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npm.taobao.org/esrecurse/download/esrecurse-4.3.0.tgz", + "integrity": "sha1-eteWTWeauyi+5yzsY3WLHF0smSE=", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.nlark.com/estraverse/download/estraverse-5.2.0.tgz", + "integrity": "sha1-MH30JUfmzHMk088DwVXVzbjFOIA=", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.nlark.com/estraverse/download/estraverse-4.3.0.tgz", + "integrity": "sha1-OYrT88WiSUi+dyXoPRGn3ijNvR0=", + "dev": true + }, + "estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npm.taobao.org/estree-walker/download/estree-walker-2.0.2.tgz?cache=0&sync_timestamp=1611956983677&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Festree-walker%2Fdownload%2Festree-walker-2.0.2.tgz", + "integrity": "sha1-UvAQF4wqTBF6d1fP6UKtt9LaTKw=" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.nlark.com/esutils/download/esutils-2.0.3.tgz", + "integrity": "sha1-dNLrTeC42hKTcRkQ1Qd1ubcQ72Q=", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npm.taobao.org/etag/download/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "dev": true + }, + "event-pubsub": { + "version": "4.3.0", + "resolved": "https://registry.npm.taobao.org/event-pubsub/download/event-pubsub-4.3.0.tgz?cache=0&sync_timestamp=1606361507592&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fevent-pubsub%2Fdownload%2Fevent-pubsub-4.3.0.tgz", + "integrity": "sha1-9o2Ba8KfHsAsU53FjI3UDOcss24=", + "dev": true + }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.nlark.com/eventemitter3/download/eventemitter3-4.0.7.tgz", + "integrity": "sha1-Lem2j2Uo1WRO9cWVJqG0oHMGFp8=", + "dev": true + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npm.taobao.org/events/download/events-3.3.0.tgz", + "integrity": "sha1-Mala0Kkk4tLEGagTrrLE6HjqdAA=", + "dev": true + }, + "eventsource": { + "version": "1.1.0", + "resolved": "https://registry.npm.taobao.org/eventsource/download/eventsource-1.1.0.tgz?cache=0&sync_timestamp=1616041710425&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Feventsource%2Fdownload%2Feventsource-1.1.0.tgz", + "integrity": "sha1-AOjKfJIQnpSw3fMtrGd9hBAoz68=", + "dev": true, + "requires": { + "original": "^1.0.0" + } + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.nlark.com/evp_bytestokey/download/evp_bytestokey-1.0.3.tgz", + "integrity": "sha1-f8vbGY3HGVlDLv4ThCaE4FJaywI=", + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.nlark.com/execa/download/execa-1.0.0.tgz?cache=0&sync_timestamp=1622396637949&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fexeca%2Fdownload%2Fexeca-1.0.0.tgz", + "integrity": "sha1-xiNqW7TfbW8V6I5/AXeYIWdJ3dg=", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npm.taobao.org/expand-brackets/download/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.nlark.com/debug/download/debug-2.6.9.tgz?cache=0&sync_timestamp=1618847042350&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdebug%2Fdownload%2Fdebug-2.6.9.tgz", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.nlark.com/extend-shallow/download/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz?cache=0&sync_timestamp=1607433950466&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.nlark.com/express/download/express-4.17.1.tgz?cache=0&sync_timestamp=1618847120573&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fexpress%2Fdownload%2Fexpress-4.17.1.tgz", + "integrity": "sha1-RJH8OGBc9R+GKdOcK10Cb5ikwTQ=", + "dev": true, + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.nlark.com/debug/download/debug-2.6.9.tgz?cache=0&sync_timestamp=1618847042350&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdebug%2Fdownload%2Fdebug-2.6.9.tgz", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz?cache=0&sync_timestamp=1607433950466&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.nlark.com/qs/download/qs-6.7.0.tgz", + "integrity": "sha1-QdwaAV49WB8WIXdr4xr7KHapsbw=", + "dev": true + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.nlark.com/extend/download/extend-3.0.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fextend%2Fdownload%2Fextend-3.0.2.tgz", + "integrity": "sha1-+LETa0Bx+9jrFAr/hYsQGewpFfo=", + "dev": true + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.nlark.com/extend-shallow/download/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npm.taobao.org/is-extendable/download/is-extendable-1.0.1.tgz", + "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npm.taobao.org/external-editor/download/external-editor-3.1.0.tgz", + "integrity": "sha1-ywP3QL764D6k0oPK7SdBqD8zVJU=", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.nlark.com/extglob/download/extglob-2.0.4.tgz", + "integrity": "sha1-rQD+TcYSqSMuhxhxHcXLWrAoVUM=", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.nlark.com/extend-shallow/download/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.nlark.com/is-accessor-descriptor/download/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.nlark.com/is-data-descriptor/download/is-data-descriptor-1.0.0.tgz", + "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/is-descriptor/download/is-descriptor-1.0.2.tgz", + "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npm.taobao.org/extsprintf/download/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-3.1.3.tgz", + "integrity": "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU=", + "dev": true + }, + "fast-glob": { + "version": "2.2.7", + "resolved": "https://registry.npm.taobao.org/fast-glob/download/fast-glob-2.2.7.tgz?cache=0&sync_timestamp=1610876605854&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffast-glob%2Fdownload%2Ffast-glob-2.2.7.tgz", + "integrity": "sha1-aVOFfDr6R1//ku5gFdUtpwpM050=", + "dev": true, + "requires": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" + }, + "dependencies": { + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.nlark.com/glob-parent/download/glob-parent-3.1.0.tgz?cache=0&sync_timestamp=1620073321855&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fglob-parent%2Fdownload%2Fglob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npm.taobao.org/is-glob/download/is-glob-3.1.0.tgz?cache=0&sync_timestamp=1598237815612&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-glob%2Fdownload%2Fis-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + } + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npm.taobao.org/fast-json-stable-stringify/download/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha1-h0v2nG9ATCtdmcSBNBOZ/VWJJjM=", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.nlark.com/fast-levenshtein/download/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.nlark.com/faye-websocket/download/faye-websocket-0.11.4.tgz", + "integrity": "sha1-fw2Sdc/dhqHJY9yLZfzEUe3Lsdo=", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "figgy-pudding": { + "version": "3.5.2", + "resolved": "https://registry.npm.taobao.org/figgy-pudding/download/figgy-pudding-3.5.2.tgz", + "integrity": "sha1-tO7oFIq7Adzx0aw0Nn1Z4S+mHW4=", + "dev": true + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.nlark.com/figures/download/figures-3.2.0.tgz", + "integrity": "sha1-YlwYvSk8YE3EqN2y/r8MiDQXRq8=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npm.taobao.org/file-entry-cache/download/file-entry-cache-5.0.1.tgz?cache=0&sync_timestamp=1613794357372&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffile-entry-cache%2Fdownload%2Ffile-entry-cache-5.0.1.tgz", + "integrity": "sha1-yg9u+m3T1WEzP7FFFQZcL6/fQ5w=", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "file-loader": { + "version": "4.3.0", + "resolved": "https://registry.npm.taobao.org/file-loader/download/file-loader-4.3.0.tgz?cache=0&sync_timestamp=1603900022388&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffile-loader%2Fdownload%2Ffile-loader-4.3.0.tgz", + "integrity": "sha1-eA8ED3KbPRgBnyBgX3I+hEuKWK8=", + "dev": true, + "requires": { + "loader-utils": "^1.2.3", + "schema-utils": "^2.5.0" + } + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/file-uri-to-path/download/file-uri-to-path-1.0.0.tgz", + "integrity": "sha1-VTp7hEb/b2hDWcRF8eN6BdrMM90=", + "dev": true, + "optional": true + }, + "filesize": { + "version": "3.6.1", + "resolved": "https://registry.nlark.com/filesize/download/filesize-3.6.1.tgz", + "integrity": "sha1-CQuz7gG2+AGoqL6Z0xcQs0Irsxc=", + "dev": true + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npm.taobao.org/fill-range/download/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.nlark.com/extend-shallow/download/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npm.taobao.org/finalhandler/download/finalhandler-1.1.2.tgz", + "integrity": "sha1-t+fQAP/RGTjQ/bBTUG9uur6fWH0=", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.nlark.com/debug/download/debug-2.6.9.tgz?cache=0&sync_timestamp=1618847042350&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdebug%2Fdownload%2Fdebug-2.6.9.tgz", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz?cache=0&sync_timestamp=1607433950466&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "find-cache-dir": { + "version": "3.3.1", + "resolved": "https://registry.npm.taobao.org/find-cache-dir/download/find-cache-dir-3.3.1.tgz", + "integrity": "sha1-ibM/rUpGcNqpT4Vff74x1thP6IA=", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.nlark.com/find-up/download/find-up-4.1.0.tgz?cache=0&sync_timestamp=1618846778775&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ffind-up%2Fdownload%2Ffind-up-4.1.0.tgz", + "integrity": "sha1-l6/n1s3AvFkoWEt8jXsW6KmqXRk=", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.nlark.com/flat-cache/download/flat-cache-2.0.1.tgz", + "integrity": "sha1-XSltbwS9pEpGMKMBQTvbwuwIXsA=", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + }, + "dependencies": { + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npm.taobao.org/rimraf/download/rimraf-2.6.3.tgz?cache=0&sync_timestamp=1614946161596&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frimraf%2Fdownload%2Frimraf-2.6.3.tgz", + "integrity": "sha1-stEE/g2Psnz54KHNqCYt04M8bKs=", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npm.taobao.org/flatted/download/flatted-2.0.2.tgz?cache=0&sync_timestamp=1611061273899&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fflatted%2Fdownload%2Fflatted-2.0.2.tgz", + "integrity": "sha1-RXWyHivO50NKqb5mL0t7X5wrUTg=", + "dev": true + }, + "flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npm.taobao.org/flush-write-stream/download/flush-write-stream-1.1.1.tgz", + "integrity": "sha1-jdfYc6G6vCB9lOrQwuDkQnbr8ug=", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "follow-redirects": { + "version": "1.14.1", + "resolved": "https://registry.nlark.com/follow-redirects/download/follow-redirects-1.14.1.tgz", + "integrity": "sha1-2RFN7Qoc/dM04WTmZirQK/2R/0M=", + "dev": true + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/for-in/download/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npm.taobao.org/forever-agent/download/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npm.taobao.org/form-data/download/form-data-2.3.3.tgz", + "integrity": "sha1-3M5SwF9kTymManq5Nr1yTO/786Y=", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npm.taobao.org/forwarded/download/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "dev": true + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.nlark.com/fragment-cache/download/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npm.taobao.org/fresh/download/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npm.taobao.org/from2/download/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.nlark.com/fs-extra/download/fs-extra-7.0.1.tgz", + "integrity": "sha1-TxicRKoSO4lfcigE9V6iPq3DSOk=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npm.taobao.org/fs-write-stream-atomic/download/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.nlark.com/fs.realpath/download/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npm.taobao.org/fsevents/download/fsevents-2.3.2.tgz", + "integrity": "sha1-ilJveLj99GI7cJ4Ll1xSwkwC/Ro=", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npm.taobao.org/function-bind/download/function-bind-1.1.1.tgz", + "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.nlark.com/functional-red-black-tree/download/functional-red-black-tree-1.0.1.tgz?cache=0&sync_timestamp=1618847182644&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ffunctional-red-black-tree%2Fdownload%2Ffunctional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "generic-names": { + "version": "2.0.1", + "resolved": "https://registry.npm.taobao.org/generic-names/download/generic-names-2.0.1.tgz?cache=0&sync_timestamp=1603542269880&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fgeneric-names%2Fdownload%2Fgeneric-names-2.0.1.tgz", + "integrity": "sha1-+KN46tLMqno08DF7BVVIMq5BuHI=", + "dev": true, + "requires": { + "loader-utils": "^1.1.0" + } + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npm.taobao.org/gensync/download/gensync-1.0.0-beta.2.tgz", + "integrity": "sha1-MqbudsPX9S1GsrGuXZP+qFgKJeA=", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npm.taobao.org/get-caller-file/download/get-caller-file-2.0.5.tgz", + "integrity": "sha1-T5RBKoLbMvNuOwuXQfipf+sDH34=", + "dev": true + }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.nlark.com/get-intrinsic/download/get-intrinsic-1.1.1.tgz", + "integrity": "sha1-FfWfN2+FXERpY5SPDSTNNje0q8Y=", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npm.taobao.org/get-stream/download/get-stream-4.1.0.tgz", + "integrity": "sha1-wbJVV189wh1Zv8ec09K0axw6VLU=", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.nlark.com/get-value/download/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.nlark.com/getpass/download/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.1.7", + "resolved": "https://registry.nlark.com/glob/download/glob-7.1.7.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fglob%2Fdownload%2Fglob-7.1.7.tgz", + "integrity": "sha1-Oxk+kjPwHULQs/eClLvutBj5SpA=", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.nlark.com/glob-parent/download/glob-parent-5.1.2.tgz?cache=0&sync_timestamp=1620073321855&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fglob-parent%2Fdownload%2Fglob-parent-5.1.2.tgz", + "integrity": "sha1-hpgyxYA0/mikCTwX3BXoNA2EAcQ=", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "glob-to-regexp": { + "version": "0.3.0", + "resolved": "https://registry.npm.taobao.org/glob-to-regexp/download/glob-to-regexp-0.3.0.tgz", + "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", + "dev": true + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.nlark.com/globals/download/globals-11.12.0.tgz", + "integrity": "sha1-q4eVM4hooLq9hSV1gBjCp+uVxC4=", + "dev": true + }, + "globby": { + "version": "9.2.0", + "resolved": "https://registry.nlark.com/globby/download/globby-9.2.0.tgz", + "integrity": "sha1-/QKacGxwPSm90XD0tts6P3p8tj0=", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "array-union": "^1.0.2", + "dir-glob": "^2.2.2", + "fast-glob": "^2.2.6", + "glob": "^7.1.3", + "ignore": "^4.0.3", + "pify": "^4.0.1", + "slash": "^2.0.0" + } + }, + "graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.nlark.com/graceful-fs/download/graceful-fs-4.2.6.tgz", + "integrity": "sha1-/wQLKwhTsjw9MQJ1I3BvGIXXa+4=", + "dev": true + }, + "gzip-size": { + "version": "5.1.1", + "resolved": "https://registry.npm.taobao.org/gzip-size/download/gzip-size-5.1.1.tgz?cache=0&sync_timestamp=1605523244597&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fgzip-size%2Fdownload%2Fgzip-size-5.1.1.tgz", + "integrity": "sha1-y5vuaS+HwGErIyhAqHOQTkwTUnQ=", + "dev": true, + "requires": { + "duplexer": "^0.1.1", + "pify": "^4.0.1" + } + }, + "handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npm.taobao.org/handle-thing/download/handle-thing-2.0.1.tgz", + "integrity": "sha1-hX95zjWVgMNA1DCBzGSJcNC7I04=", + "dev": true + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.nlark.com/har-schema/download/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.nlark.com/har-validator/download/har-validator-5.1.5.tgz", + "integrity": "sha1-HwgDufjLIMD6E4It8ezds2veHv0=", + "dev": true, + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npm.taobao.org/has/download/has-1.0.3.tgz", + "integrity": "sha1-ci18v8H2qoJB8W3YFOAR4fQeh5Y=", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npm.taobao.org/has-bigints/download/has-bigints-1.0.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhas-bigints%2Fdownload%2Fhas-bigints-1.0.1.tgz", + "integrity": "sha1-ZP5qywIGc+O3jbA1pa9pqp0HsRM=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/has-flag/download/has-flag-3.0.0.tgz?cache=0&sync_timestamp=1618559676170&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhas-flag%2Fdownload%2Fhas-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/has-symbols/download/has-symbols-1.0.2.tgz?cache=0&sync_timestamp=1614443484522&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhas-symbols%2Fdownload%2Fhas-symbols-1.0.2.tgz", + "integrity": "sha1-Fl0wcMADCXUqEjakeTMeOsVvFCM=", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/has-value/download/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/has-values/download/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.nlark.com/kind-of/download/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npm.taobao.org/hash-base/download/hash-base-3.1.0.tgz", + "integrity": "sha1-VcOB2eBuHSmXqIO0o/3f5/DTrzM=", + "dev": true, + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.nlark.com/readable-stream/download/readable-stream-3.6.0.tgz", + "integrity": "sha1-M3u9o63AcGvT4CRCaihtS0sskZg=", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.nlark.com/safe-buffer/download/safe-buffer-5.2.1.tgz", + "integrity": "sha1-Hq+fqb2x/dTsdfWPnNtOa3gn7sY=", + "dev": true + } + } + }, + "hash-sum": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/hash-sum/download/hash-sum-2.0.0.tgz", + "integrity": "sha1-gdAbtd6OpKIUrV1urRtSNGCwtFo=", + "dev": true + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npm.taobao.org/hash.js/download/hash.js-1.1.7.tgz", + "integrity": "sha1-C6vKU46NTuSg+JiNaIZlN6ADz0I=", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npm.taobao.org/he/download/he-1.2.0.tgz", + "integrity": "sha1-hK5l+n6vsWX922FWauFLrwVmTw8=", + "dev": true + }, + "hex-color-regex": { + "version": "1.1.0", + "resolved": "https://registry.nlark.com/hex-color-regex/download/hex-color-regex-1.1.0.tgz", + "integrity": "sha1-TAb8y0YC/iYCs8k9+C1+fb8aio4=", + "dev": true + }, + "highlight.js": { + "version": "10.7.2", + "resolved": "https://registry.nlark.com/highlight.js/download/highlight.js-10.7.2.tgz", + "integrity": "sha1-iTGbhh7cZsSIVO0ebaIeqJ+Ec2A=", + "dev": true + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.nlark.com/hmac-drbg/download/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "hoopy": { + "version": "0.1.4", + "resolved": "https://registry.nlark.com/hoopy/download/hoopy-0.1.4.tgz", + "integrity": "sha1-YJIH1mEQADOpqUAq096mdzgcGx0=", + "dev": true + }, + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npm.taobao.org/hosted-git-info/download/hosted-git-info-2.8.9.tgz", + "integrity": "sha1-3/wL+aIcAiCQkPKqaUKeFBTa8/k=", + "dev": true + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npm.taobao.org/hpack.js/download/hpack.js-2.1.6.tgz", + "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "hsl-regex": { + "version": "1.0.0", + "resolved": "https://registry.nlark.com/hsl-regex/download/hsl-regex-1.0.0.tgz", + "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=", + "dev": true + }, + "hsla-regex": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/hsla-regex/download/hsla-regex-1.0.0.tgz", + "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=", + "dev": true + }, + "html-entities": { + "version": "1.4.0", + "resolved": "https://registry.nlark.com/html-entities/download/html-entities-1.4.0.tgz", + "integrity": "sha1-z70bAdKvr5rcobEK59/6uYxx0tw=", + "dev": true + }, + "html-minifier": { + "version": "3.5.21", + "resolved": "https://registry.npm.taobao.org/html-minifier/download/html-minifier-3.5.21.tgz", + "integrity": "sha1-0AQOBUcw41TbAIRjWTGUAVIS0gw=", + "dev": true, + "requires": { + "camel-case": "3.0.x", + "clean-css": "4.2.x", + "commander": "2.17.x", + "he": "1.2.x", + "param-case": "2.1.x", + "relateurl": "0.2.x", + "uglify-js": "3.4.x" + }, + "dependencies": { + "commander": { + "version": "2.17.1", + "resolved": "https://registry.nlark.com/commander/download/commander-2.17.1.tgz?cache=0&sync_timestamp=1622446257852&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fcommander%2Fdownload%2Fcommander-2.17.1.tgz", + "integrity": "sha1-vXerfebelCBc6sxy8XFtKfIKd78=", + "dev": true + } + } + }, + "html-tags": { + "version": "3.1.0", + "resolved": "https://registry.npm.taobao.org/html-tags/download/html-tags-3.1.0.tgz", + "integrity": "sha1-e15vfmZen7QfMAB+2eDUHpf7IUA=", + "dev": true + }, + "html-webpack-plugin": { + "version": "3.2.0", + "resolved": "https://registry.npm.taobao.org/html-webpack-plugin/download/html-webpack-plugin-3.2.0.tgz", + "integrity": "sha1-sBq71yOsqqeze2r0SS69oD2d03s=", + "dev": true, + "requires": { + "html-minifier": "^3.2.3", + "loader-utils": "^0.2.16", + "lodash": "^4.17.3", + "pretty-error": "^2.0.2", + "tapable": "^1.0.0", + "toposort": "^1.0.0", + "util.promisify": "1.0.0" + }, + "dependencies": { + "big.js": { + "version": "3.2.0", + "resolved": "https://registry.nlark.com/big.js/download/big.js-3.2.0.tgz", + "integrity": "sha1-pfwpi4G54Nyi5FiCR4S2XFK6WI4=", + "dev": true + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npm.taobao.org/emojis-list/download/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npm.taobao.org/json5/download/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "loader-utils": { + "version": "0.2.17", + "resolved": "https://registry.nlark.com/loader-utils/download/loader-utils-0.2.17.tgz?cache=0&sync_timestamp=1618846812625&other_urls=https%3A%2F%2Fregistry.nlark.com%2Floader-utils%2Fdownload%2Floader-utils-0.2.17.tgz", + "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", + "dev": true, + "requires": { + "big.js": "^3.1.3", + "emojis-list": "^2.0.0", + "json5": "^0.5.0", + "object-assign": "^4.0.1" + } + }, + "util.promisify": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/util.promisify/download/util.promisify-1.0.0.tgz?cache=0&sync_timestamp=1610159895694&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Futil.promisify%2Fdownload%2Futil.promisify-1.0.0.tgz", + "integrity": "sha1-RA9xZaRZyaFtwUXrjnLzVocJcDA=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" + } + } + } + }, + "htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.nlark.com/htmlparser2/download/htmlparser2-3.10.1.tgz?cache=0&sync_timestamp=1618846794076&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fhtmlparser2%2Fdownload%2Fhtmlparser2-3.10.1.tgz", + "integrity": "sha1-vWedw/WYl7ajS7EHSchVu1OpOS8=", + "dev": true, + "requires": { + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npm.taobao.org/entities/download/entities-1.1.2.tgz", + "integrity": "sha1-vfpzUplmTfr9NFKe1PhSKidf6lY=", + "dev": true + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.nlark.com/readable-stream/download/readable-stream-3.6.0.tgz", + "integrity": "sha1-M3u9o63AcGvT4CRCaihtS0sskZg=", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.nlark.com/http-deceiver/download/http-deceiver-1.2.7.tgz", + "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", + "dev": true + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npm.taobao.org/http-errors/download/http-errors-1.7.2.tgz", + "integrity": "sha1-T1ApzxMjnzEDblsuVSkrz7zIXI8=", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.nlark.com/inherits/download/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + } + } + }, + "http-parser-js": { + "version": "0.5.3", + "resolved": "https://registry.npm.taobao.org/http-parser-js/download/http-parser-js-0.5.3.tgz", + "integrity": "sha1-AdJwnHnUFpi7AdTezF6dpOSgM9k=", + "dev": true + }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npm.taobao.org/http-proxy/download/http-proxy-1.18.1.tgz", + "integrity": "sha1-QBVB8FNIhLv5UmAzTnL4juOXZUk=", + "dev": true, + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-middleware": { + "version": "1.3.1", + "resolved": "https://registry.nlark.com/http-proxy-middleware/download/http-proxy-middleware-1.3.1.tgz?cache=0&sync_timestamp=1620409720336&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fhttp-proxy-middleware%2Fdownload%2Fhttp-proxy-middleware-1.3.1.tgz", + "integrity": "sha1-Q3ANbZ7st0Gb8IahKND3IF2etmU=", + "dev": true, + "requires": { + "@types/http-proxy": "^1.17.5", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "dependencies": { + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npm.taobao.org/braces/download/braces-3.0.2.tgz", + "integrity": "sha1-NFThpGLujVmeI23zNs2epPiv4Qc=", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npm.taobao.org/fill-range/download/fill-range-7.0.1.tgz", + "integrity": "sha1-GRmmp8df44ssfHflGYU12prN2kA=", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.nlark.com/is-number/download/is-number-7.0.0.tgz", + "integrity": "sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss=", + "dev": true + }, + "micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npm.taobao.org/micromatch/download/micromatch-4.0.4.tgz?cache=0&sync_timestamp=1618054787196&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmicromatch%2Fdownload%2Fmicromatch-4.0.4.tgz", + "integrity": "sha1-iW1Rnf6dsl/OlM63pQCRm/iB6/k=", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.nlark.com/to-regex-range/download/to-regex-range-5.0.1.tgz", + "integrity": "sha1-FkjESq58jZiKMmAY7XL1tN0DkuQ=", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + } + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.nlark.com/http-signature/download/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.nlark.com/https-browserify/download/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", + "dev": true + }, + "human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npm.taobao.org/human-signals/download/human-signals-1.1.1.tgz", + "integrity": "sha1-xbHNFPUK6uCatsWf5jujOV/k36M=", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.nlark.com/iconv-lite/download/iconv-lite-0.4.24.tgz", + "integrity": "sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "icss-replace-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npm.taobao.org/icss-replace-symbols/download/icss-replace-symbols-1.1.0.tgz", + "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=", + "dev": true + }, + "icss-utils": { + "version": "4.1.1", + "resolved": "https://registry.npm.taobao.org/icss-utils/download/icss-utils-4.1.1.tgz?cache=0&sync_timestamp=1605801291394&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ficss-utils%2Fdownload%2Ficss-utils-4.1.1.tgz", + "integrity": "sha1-IRcLU3ie4nRHwvR91oMIFAP5pGc=", + "dev": true, + "requires": { + "postcss": "^7.0.14" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.nlark.com/ieee754/download/ieee754-1.2.1.tgz", + "integrity": "sha1-jrehCmP/8l0VpXsAFYbRd9Gw01I=", + "dev": true + }, + "iferr": { + "version": "0.1.5", + "resolved": "https://registry.npm.taobao.org/iferr/download/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", + "dev": true + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npm.taobao.org/ignore/download/ignore-4.0.6.tgz", + "integrity": "sha1-dQ49tYYgh7RzfrrIIH/9HvJ7Jfw=", + "dev": true + }, + "import-cwd": { + "version": "2.1.0", + "resolved": "https://registry.nlark.com/import-cwd/download/import-cwd-2.1.0.tgz?cache=0&sync_timestamp=1618846826220&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fimport-cwd%2Fdownload%2Fimport-cwd-2.1.0.tgz", + "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", + "dev": true, + "requires": { + "import-from": "^2.1.0" + } + }, + "import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/import-fresh/download/import-fresh-2.0.0.tgz?cache=0&sync_timestamp=1608469561643&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fimport-fresh%2Fdownload%2Fimport-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "dev": true, + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + } + }, + "import-from": { + "version": "2.1.0", + "resolved": "https://registry.npm.taobao.org/import-from/download/import-from-2.1.0.tgz", + "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + } + }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.nlark.com/import-local/download/import-local-2.0.0.tgz", + "integrity": "sha1-VQcL44pZk88Y72236WH1vuXFoJ0=", + "dev": true, + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.nlark.com/find-up/download/find-up-3.0.0.tgz?cache=0&sync_timestamp=1618846778775&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ffind-up%2Fdownload%2Ffind-up-3.0.0.tgz", + "integrity": "sha1-SRafHXmTQwZG2mHsxa41XCHJe3M=", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/locate-path/download/locate-path-3.0.0.tgz", + "integrity": "sha1-2+w7OrdZdYBxtY/ln8QYca8hQA4=", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.nlark.com/p-locate/download/p-locate-3.0.0.tgz", + "integrity": "sha1-Mi1poFwCZLJZl9n0DNiokasAZKQ=", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.nlark.com/path-exists/download/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/pkg-dir/download/pkg-dir-3.0.0.tgz?cache=0&sync_timestamp=1602859045787&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpkg-dir%2Fdownload%2Fpkg-dir-3.0.0.tgz", + "integrity": "sha1-J0kCDyOe2ZCIGx9xIQ1R62UjvqM=", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + } + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npm.taobao.org/imurmurhash/download/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "indexes-of": { + "version": "1.0.1", + "resolved": "https://registry.npm.taobao.org/indexes-of/download/indexes-of-1.0.1.tgz", + "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", + "dev": true + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npm.taobao.org/infer-owner/download/infer-owner-1.0.4.tgz", + "integrity": "sha1-xM78qo5RBRwqQLos6KPScpWvlGc=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npm.taobao.org/inflight/download/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.nlark.com/inherits/download/inherits-2.0.4.tgz", + "integrity": "sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w=", + "dev": true + }, + "inquirer": { + "version": "7.3.3", + "resolved": "https://registry.nlark.com/inquirer/download/inquirer-7.3.3.tgz?cache=0&sync_timestamp=1621629105005&other_urls=https%3A%2F%2Fregistry.nlark.com%2Finquirer%2Fdownload%2Finquirer-7.3.3.tgz", + "integrity": "sha1-BNF2sq8Er8FXqD/XwQDpjuCq0AM=", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.19", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.6.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.nlark.com/ansi-styles/download/ansi-styles-4.3.0.tgz", + "integrity": "sha1-7dgDYornHATIWuegkG7a00tkiTc=", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.nlark.com/chalk/download/chalk-4.1.1.tgz?cache=0&sync_timestamp=1618995367379&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fchalk%2Fdownload%2Fchalk-4.1.1.tgz", + "integrity": "sha1-yAs/qyi/Y3HmhjMl7uZ+YYt35q0=", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npm.taobao.org/cli-cursor/download/cli-cursor-3.1.0.tgz", + "integrity": "sha1-JkMFp65JDR0Dvwybp8kl0XU68wc=", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz", + "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.nlark.com/color-name/download/color-name-1.1.4.tgz", + "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npm.taobao.org/has-flag/download/has-flag-4.0.0.tgz?cache=0&sync_timestamp=1618559676170&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhas-flag%2Fdownload%2Fhas-flag-4.0.0.tgz", + "integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s=", + "dev": true + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npm.taobao.org/mimic-fn/download/mimic-fn-2.1.0.tgz", + "integrity": "sha1-ftLCzMyvhNP/y3pptXcR/CCDQBs=", + "dev": true + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npm.taobao.org/onetime/download/onetime-5.1.2.tgz", + "integrity": "sha1-0Oluu1awdHbfHdnEgG5SN5hcpF4=", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.nlark.com/restore-cursor/download/restore-cursor-3.1.0.tgz", + "integrity": "sha1-OfZ8VLOnpYzqUjbZXPADQjljH34=", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.nlark.com/supports-color/download/supports-color-7.2.0.tgz?cache=0&sync_timestamp=1622293670728&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fsupports-color%2Fdownload%2Fsupports-color-7.2.0.tgz", + "integrity": "sha1-G33NyzK4E4gBs+R4umpRyqiWSNo=", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "internal-ip": { + "version": "4.3.0", + "resolved": "https://registry.npm.taobao.org/internal-ip/download/internal-ip-4.3.0.tgz?cache=0&sync_timestamp=1605885528721&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Finternal-ip%2Fdownload%2Finternal-ip-4.3.0.tgz", + "integrity": "sha1-hFRSuq2dLKO2nGNaE3rLmg2tCQc=", + "dev": true, + "requires": { + "default-gateway": "^4.2.0", + "ipaddr.js": "^1.9.0" + }, + "dependencies": { + "default-gateway": { + "version": "4.2.0", + "resolved": "https://registry.npm.taobao.org/default-gateway/download/default-gateway-4.2.0.tgz?cache=0&sync_timestamp=1610365756089&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdefault-gateway%2Fdownload%2Fdefault-gateway-4.2.0.tgz", + "integrity": "sha1-FnEEx1AMIRX23WmwpTa7jtcgVSs=", + "dev": true, + "requires": { + "execa": "^1.0.0", + "ip-regex": "^2.1.0" + } + } + } + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.nlark.com/ip/download/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + }, + "ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.nlark.com/ip-regex/download/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "dev": true + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npm.taobao.org/ipaddr.js/download/ipaddr.js-1.9.1.tgz", + "integrity": "sha1-v/OFQ+64mEglB5/zoqjmy9RngbM=", + "dev": true + }, + "is-absolute-url": { + "version": "2.1.0", + "resolved": "https://registry.nlark.com/is-absolute-url/download/is-absolute-url-2.1.0.tgz", + "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=", + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.nlark.com/is-accessor-descriptor/download/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.nlark.com/kind-of/download/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-arguments": { + "version": "1.1.0", + "resolved": "https://registry.nlark.com/is-arguments/download/is-arguments-1.1.0.tgz", + "integrity": "sha1-YjUwMd++4HzrNGVqa95Z7+yujdk=", + "dev": true, + "requires": { + "call-bind": "^1.0.0" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npm.taobao.org/is-arrayish/download/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-bigint": { + "version": "1.0.2", + "resolved": "https://registry.nlark.com/is-bigint/download/is-bigint-1.0.2.tgz", + "integrity": "sha1-/7OBRCUDI1rSReqJ5Fs9v/BA7lo=", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.nlark.com/is-binary-path/download/is-binary-path-2.1.0.tgz", + "integrity": "sha1-6h9/O4DwZCNug0cPhsCcJU+0Wwk=", + "dev": true, + "optional": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-boolean-object": { + "version": "1.1.1", + "resolved": "https://registry.nlark.com/is-boolean-object/download/is-boolean-object-1.1.1.tgz", + "integrity": "sha1-PAh48DXLghIo01DS4eNnGXFqPeg=", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.nlark.com/is-buffer/download/is-buffer-1.1.6.tgz", + "integrity": "sha1-76ouqdqg16suoTqXsritUf776L4=", + "dev": true + }, + "is-callable": { + "version": "1.2.3", + "resolved": "https://registry.nlark.com/is-callable/download/is-callable-1.2.3.tgz", + "integrity": "sha1-ix4FALc6HXbHBIdjbzaOUZ3o244=", + "dev": true + }, + "is-ci": { + "version": "1.2.1", + "resolved": "https://registry.npm.taobao.org/is-ci/download/is-ci-1.2.1.tgz?cache=0&sync_timestamp=1613632023079&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-ci%2Fdownload%2Fis-ci-1.2.1.tgz", + "integrity": "sha1-43ecjuF/zPQoSI9uKBGH8uYyhBw=", + "dev": true, + "requires": { + "ci-info": "^1.5.0" + } + }, + "is-color-stop": { + "version": "1.1.0", + "resolved": "https://registry.nlark.com/is-color-stop/download/is-color-stop-1.1.0.tgz", + "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=", + "dev": true, + "requires": { + "css-color-names": "^0.0.4", + "hex-color-regex": "^1.1.0", + "hsl-regex": "^1.0.0", + "hsla-regex": "^1.0.0", + "rgb-regex": "^1.0.1", + "rgba-regex": "^1.0.0" + } + }, + "is-core-module": { + "version": "2.4.0", + "resolved": "https://registry.nlark.com/is-core-module/download/is-core-module-2.4.0.tgz?cache=0&sync_timestamp=1620592570629&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fis-core-module%2Fdownload%2Fis-core-module-2.4.0.tgz", + "integrity": "sha1-jp/I4VAnsBFBgCbpjw5vTYYwXME=", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.nlark.com/is-data-descriptor/download/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.nlark.com/kind-of/download/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-date-object": { + "version": "1.0.4", + "resolved": "https://registry.nlark.com/is-date-object/download/is-date-object-1.0.4.tgz?cache=0&sync_timestamp=1620451921850&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fis-date-object%2Fdownload%2Fis-date-object-1.0.4.tgz", + "integrity": "sha1-VQz8wDr62gXuo90wmBx7CVUfc+U=", + "dev": true + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npm.taobao.org/is-descriptor/download/is-descriptor-0.1.6.tgz", + "integrity": "sha1-Nm2CQN3kh8pRgjsaufB6EKeCUco=", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.nlark.com/kind-of/download/kind-of-5.1.0.tgz", + "integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0=", + "dev": true + } + } + }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npm.taobao.org/is-directory/download/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "dev": true + }, + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.nlark.com/is-docker/download/is-docker-2.2.1.tgz", + "integrity": "sha1-M+6r4jz+hvFL3kQIoCwM+4U6zao=", + "dev": true + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npm.taobao.org/is-extendable/download/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npm.taobao.org/is-extglob/download/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-3.0.0.tgz?cache=0&sync_timestamp=1618552489864&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-fullwidth-code-point%2Fdownload%2Fis-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha1-8Rb4Bk/pCz94RKOJl8C3UFEmnx0=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npm.taobao.org/is-glob/download/is-glob-4.0.1.tgz?cache=0&sync_timestamp=1598237815612&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-glob%2Fdownload%2Fis-glob-4.0.1.tgz", + "integrity": "sha1-dWfb6fL14kZ7x3q4PEopSCQHpdw=", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.nlark.com/is-negative-zero/download/is-negative-zero-2.0.1.tgz", + "integrity": "sha1-PedGwY3aIxkkGlNnWQjY92bxHCQ=", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.nlark.com/is-number/download/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.nlark.com/kind-of/download/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-number-object": { + "version": "1.0.5", + "resolved": "https://registry.nlark.com/is-number-object/download/is-number-object-1.0.5.tgz", + "integrity": "sha1-bt+u7XlQz/Ga/tzp+/yp7m3Sies=", + "dev": true + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/is-obj/download/is-obj-2.0.0.tgz", + "integrity": "sha1-Rz+wXZc3BeP9liBUUBjKjiLvSYI=", + "dev": true + }, + "is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npm.taobao.org/is-path-cwd/download/is-path-cwd-2.2.0.tgz", + "integrity": "sha1-Z9Q7gmZKe1GR/ZEZEn6zAASKn9s=", + "dev": true + }, + "is-path-in-cwd": { + "version": "2.1.0", + "resolved": "https://registry.nlark.com/is-path-in-cwd/download/is-path-in-cwd-2.1.0.tgz?cache=0&sync_timestamp=1620047110449&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fis-path-in-cwd%2Fdownload%2Fis-path-in-cwd-2.1.0.tgz", + "integrity": "sha1-v+Lcomxp85cmWkAJljYCk1oFOss=", + "dev": true, + "requires": { + "is-path-inside": "^2.1.0" + } + }, + "is-path-inside": { + "version": "2.1.0", + "resolved": "https://registry.nlark.com/is-path-inside/download/is-path-inside-2.1.0.tgz?cache=0&sync_timestamp=1620046845369&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fis-path-inside%2Fdownload%2Fis-path-inside-2.1.0.tgz", + "integrity": "sha1-fJgQWH1lmkDSe8201WFuqwWUlLI=", + "dev": true, + "requires": { + "path-is-inside": "^1.0.2" + } + }, + "is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/is-plain-obj/download/is-plain-obj-3.0.0.tgz", + "integrity": "sha1-r28uoUrFpkYYOlu9tbqrvBVq2dc=", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npm.taobao.org/is-plain-object/download/is-plain-object-2.0.4.tgz", + "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-regex": { + "version": "1.1.3", + "resolved": "https://registry.nlark.com/is-regex/download/is-regex-1.1.3.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fis-regex%2Fdownload%2Fis-regex-1.1.3.tgz", + "integrity": "sha1-0Cn5r/ZEi5Prvj8z2scVEf3L758=", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-symbols": "^1.0.2" + } + }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npm.taobao.org/is-resolvable/download/is-resolvable-1.1.0.tgz", + "integrity": "sha1-+xj4fOH+uSUWnJpAfBkxijIG7Yg=", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.nlark.com/is-stream/download/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-string": { + "version": "1.0.6", + "resolved": "https://registry.nlark.com/is-string/download/is-string-1.0.6.tgz", + "integrity": "sha1-P+XVmS+w2TQE8yWE1LAXmnG1Sl8=", + "dev": true + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.nlark.com/is-symbol/download/is-symbol-1.0.4.tgz?cache=0&sync_timestamp=1620501174327&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fis-symbol%2Fdownload%2Fis-symbol-1.0.4.tgz", + "integrity": "sha1-ptrJO2NbBjymhyI23oiRClevE5w=", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/is-typedarray/download/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.nlark.com/is-windows/download/is-windows-1.0.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fis-windows%2Fdownload%2Fis-windows-1.0.2.tgz", + "integrity": "sha1-0YUOuXkezRjmGCzhKjDzlmNLsZ0=", + "dev": true + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.nlark.com/is-wsl/download/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.nlark.com/isexe/download/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npm.taobao.org/isobject/download/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.nlark.com/isstream/download/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "javascript-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npm.taobao.org/javascript-stringify/download/javascript-stringify-2.1.0.tgz", + "integrity": "sha1-J8dlOb4U2L0Sghmi1zGwkzeQTnk=", + "dev": true + }, + "js-message": { + "version": "1.0.7", + "resolved": "https://registry.npm.taobao.org/js-message/download/js-message-1.0.7.tgz", + "integrity": "sha1-+93QU8ekcCGHG7iyyVOXzBfCDkc=", + "dev": true + }, + "js-queue": { + "version": "2.0.2", + "resolved": "https://registry.npm.taobao.org/js-queue/download/js-queue-2.0.2.tgz", + "integrity": "sha1-C+WQM4+QOzbHPTPDGIOoIUEs1II=", + "dev": true, + "requires": { + "easy-stack": "^1.0.1" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.nlark.com/js-tokens/download/js-tokens-4.0.0.tgz?cache=0&sync_timestamp=1619345098261&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fjs-tokens%2Fdownload%2Fjs-tokens-4.0.0.tgz", + "integrity": "sha1-GSA/tZmR35jjoocFDUZHzerzJJk=", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npm.taobao.org/js-yaml/download/js-yaml-3.14.1.tgz?cache=0&sync_timestamp=1618435004368&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjs-yaml%2Fdownload%2Fjs-yaml-3.14.1.tgz", + "integrity": "sha1-2ugS/bOCX6MGYJqHFzg8UMNqBTc=", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.nlark.com/jsbn/download/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.nlark.com/jsesc/download/jsesc-2.5.2.tgz", + "integrity": "sha1-gFZNLkg9rPbo7yCWUKZ98/DCg6Q=", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/json-parse-better-errors/download/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha1-u4Z8+zRQ5pEHwTHRxRS6s9yLyqk=", + "dev": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.nlark.com/json-parse-even-better-errors/download/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha1-fEeAWpQxmSjgV3dAXcEuH3pO4C0=", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npm.taobao.org/json-schema/download/json-schema-0.2.3.tgz?cache=0&sync_timestamp=1609553637722&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjson-schema%2Fdownload%2Fjson-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz?cache=0&sync_timestamp=1607998264311&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjson-schema-traverse%2Fdownload%2Fjson-schema-traverse-0.4.1.tgz", + "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.nlark.com/json-stable-stringify-without-jsonify/download/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npm.taobao.org/json-stringify-safe/download/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "json3": { + "version": "3.3.3", + "resolved": "https://registry.npm.taobao.org/json3/download/json3-3.3.3.tgz", + "integrity": "sha1-f8EON1/FrkLEcFpcwKpvYr4wW4E=", + "dev": true + }, + "json5": { + "version": "2.2.0", + "resolved": "https://registry.npm.taobao.org/json5/download/json5-2.2.0.tgz", + "integrity": "sha1-Lf7+cgxrpSXZ69kJlQ8FFTFsiaM=", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npm.taobao.org/jsonfile/download/jsonfile-4.0.0.tgz?cache=0&sync_timestamp=1604161843950&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjsonfile%2Fdownload%2Fjsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npm.taobao.org/jsprim/download/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "killable": { + "version": "1.0.1", + "resolved": "https://registry.nlark.com/killable/download/killable-1.0.1.tgz", + "integrity": "sha1-TIzkQRh6Bhx0dPuHygjipjgZSJI=", + "dev": true + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.nlark.com/kind-of/download/kind-of-6.0.3.tgz", + "integrity": "sha1-B8BQNKbDSfoG4k+jWqdttFgM5N0=", + "dev": true + }, + "launch-editor": { + "version": "2.2.1", + "resolved": "https://registry.npm.taobao.org/launch-editor/download/launch-editor-2.2.1.tgz", + "integrity": "sha1-hxtaPuOdZoD8wm03kwtu7aidsMo=", + "dev": true, + "requires": { + "chalk": "^2.3.0", + "shell-quote": "^1.6.1" + } + }, + "launch-editor-middleware": { + "version": "2.2.1", + "resolved": "https://registry.npm.taobao.org/launch-editor-middleware/download/launch-editor-middleware-2.2.1.tgz", + "integrity": "sha1-4UsH5scVSwpLhqD9NFeE5FgEwVc=", + "dev": true, + "requires": { + "launch-editor": "^2.2.1" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npm.taobao.org/levn/download/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "lines-and-columns": { + "version": "1.1.6", + "resolved": "https://registry.nlark.com/lines-and-columns/download/lines-and-columns-1.1.6.tgz", + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", + "dev": true + }, + "loader-fs-cache": { + "version": "1.0.3", + "resolved": "https://registry.nlark.com/loader-fs-cache/download/loader-fs-cache-1.0.3.tgz", + "integrity": "sha1-8IZXZG1gcHi+LwoDL4vWndbyd9k=", + "dev": true, + "requires": { + "find-cache-dir": "^0.1.1", + "mkdirp": "^0.5.1" + }, + "dependencies": { + "find-cache-dir": { + "version": "0.1.1", + "resolved": "https://registry.npm.taobao.org/find-cache-dir/download/find-cache-dir-0.1.1.tgz", + "integrity": "sha1-yN765XyKUqinhPnjHFfHQumToLk=", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "mkdirp": "^0.5.1", + "pkg-dir": "^1.0.0" + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.nlark.com/find-up/download/find-up-1.1.2.tgz?cache=0&sync_timestamp=1618846778775&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ffind-up%2Fdownload%2Ffind-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.nlark.com/path-exists/download/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "pkg-dir": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/pkg-dir/download/pkg-dir-1.0.0.tgz?cache=0&sync_timestamp=1602859045787&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpkg-dir%2Fdownload%2Fpkg-dir-1.0.0.tgz", + "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "dev": true, + "requires": { + "find-up": "^1.0.0" + } + } + } + }, + "loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npm.taobao.org/loader-runner/download/loader-runner-2.4.0.tgz?cache=0&sync_timestamp=1610027908268&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Floader-runner%2Fdownload%2Floader-runner-2.4.0.tgz", + "integrity": "sha1-7UcGa/5TTX6ExMe5mYwqdWB9k1c=", + "dev": true + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.nlark.com/loader-utils/download/loader-utils-1.4.0.tgz?cache=0&sync_timestamp=1618846812625&other_urls=https%3A%2F%2Fregistry.nlark.com%2Floader-utils%2Fdownload%2Floader-utils-1.4.0.tgz", + "integrity": "sha1-xXm140yzSxp07cbB+za/o3HVphM=", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npm.taobao.org/json5/download/json5-1.0.1.tgz", + "integrity": "sha1-d5+wAYYE+oVOrL9iUhgNg1Q+Pb4=", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + } + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npm.taobao.org/locate-path/download/locate-path-5.0.0.tgz", + "integrity": "sha1-Gvujlq/WdqbUJQTQpno6frn2KqA=", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.nlark.com/lodash/download/lodash-4.17.21.tgz", + "integrity": "sha1-Z5WRxWTDv/quhFTPCz3zcMPWkRw=", + "dev": true + }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npm.taobao.org/lodash.camelcase/download/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", + "dev": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npm.taobao.org/lodash.clonedeep/download/lodash.clonedeep-4.5.0.tgz?cache=0&sync_timestamp=1599054271708&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash.clonedeep%2Fdownload%2Flodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npm.taobao.org/lodash.debounce/download/lodash.debounce-4.0.8.tgz", + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", + "dev": true + }, + "lodash.defaultsdeep": { + "version": "4.6.1", + "resolved": "https://registry.nlark.com/lodash.defaultsdeep/download/lodash.defaultsdeep-4.6.1.tgz", + "integrity": "sha1-US6b1yHSctlOPTpjZT+hdRZ0HKY=", + "dev": true + }, + "lodash.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.nlark.com/lodash.kebabcase/download/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha1-hImxyw0p/4gZXM7KRI/21swpXDY=", + "dev": true + }, + "lodash.mapvalues": { + "version": "4.6.0", + "resolved": "https://registry.npm.taobao.org/lodash.mapvalues/download/lodash.mapvalues-4.6.0.tgz", + "integrity": "sha1-G6+lAF3p3W9PJmaMMMo3IwzJaJw=", + "dev": true + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.nlark.com/lodash.memoize/download/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, + "lodash.transform": { + "version": "4.6.0", + "resolved": "https://registry.npm.taobao.org/lodash.transform/download/lodash.transform-4.6.0.tgz", + "integrity": "sha1-EjBkIvYzJK7YSD0/ODMrX2cFR6A=", + "dev": true + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.nlark.com/lodash.uniq/download/lodash.uniq-4.5.0.tgz", + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", + "dev": true + }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.nlark.com/log-symbols/download/log-symbols-2.2.0.tgz?cache=0&sync_timestamp=1618847128438&other_urls=https%3A%2F%2Fregistry.nlark.com%2Flog-symbols%2Fdownload%2Flog-symbols-2.2.0.tgz", + "integrity": "sha1-V0Dhxdbw39pK2TI7UzIQfva0xAo=", + "dev": true, + "requires": { + "chalk": "^2.0.1" + } + }, + "loglevel": { + "version": "1.7.1", + "resolved": "https://registry.npm.taobao.org/loglevel/download/loglevel-1.7.1.tgz?cache=0&sync_timestamp=1606314031897&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Floglevel%2Fdownload%2Floglevel-1.7.1.tgz", + "integrity": "sha1-AF/eL15uRwaPk1/yhXPhJe9y8Zc=", + "dev": true + }, + "lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npm.taobao.org/lower-case/download/lower-case-1.1.4.tgz?cache=0&sync_timestamp=1606867333511&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flower-case%2Fdownload%2Flower-case-1.1.4.tgz", + "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", + "dev": true + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.nlark.com/lru-cache/download/lru-cache-5.1.1.tgz", + "integrity": "sha1-HaJ+ZxAnGUdpXa9oSOhH8B2EuSA=", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "magic-string": { + "version": "0.25.7", + "resolved": "https://registry.npm.taobao.org/magic-string/download/magic-string-0.25.7.tgz", + "integrity": "sha1-P0l9b9NMZpxnmNy4IfLvMfVEUFE=", + "dev": true, + "requires": { + "sourcemap-codec": "^1.4.4" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npm.taobao.org/make-dir/download/make-dir-3.1.0.tgz", + "integrity": "sha1-QV6WcEazp/HRhSd9hKpYIDcmoT8=", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.nlark.com/map-cache/download/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.nlark.com/map-visit/download/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npm.taobao.org/md5.js/download/md5.js-1.3.5.tgz", + "integrity": "sha1-tdB7jjIW4+J81yjXL3DR5qNCAF8=", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "mdn-data": { + "version": "2.0.4", + "resolved": "https://registry.nlark.com/mdn-data/download/mdn-data-2.0.4.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fmdn-data%2Fdownload%2Fmdn-data-2.0.4.tgz", + "integrity": "sha1-aZs8OKxvHXKAkaZGULZdOIUC/Vs=", + "dev": true + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.nlark.com/media-typer/download/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.nlark.com/memory-fs/download/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.nlark.com/merge-descriptors/download/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "dev": true + }, + "merge-source-map": { + "version": "1.1.0", + "resolved": "https://registry.npm.taobao.org/merge-source-map/download/merge-source-map-1.1.0.tgz", + "integrity": "sha1-L93n5gIJOfcJBqaPLXrmheTIxkY=", + "dev": true, + "requires": { + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "dev": true + } + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.nlark.com/merge-stream/download/merge-stream-2.0.0.tgz", + "integrity": "sha1-UoI2KaFN0AyXcPtq1H3GMQ8sH2A=", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npm.taobao.org/merge2/download/merge2-1.4.1.tgz", + "integrity": "sha1-Q2iJL4hekHRVpv19xVwMnUBJkK4=", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npm.taobao.org/methods/download/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npm.taobao.org/micromatch/download/micromatch-3.1.10.tgz?cache=0&sync_timestamp=1618054787196&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmicromatch%2Fdownload%2Fmicromatch-3.1.10.tgz", + "integrity": "sha1-cIWbyVyYQJUvNZoGij/En57PrCM=", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.nlark.com/miller-rabin/download/miller-rabin-4.0.1.tgz", + "integrity": "sha1-8IA1HIZbDcViqEYpZtqlNUPHik0=", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npm.taobao.org/bn.js/download/bn.js-4.12.0.tgz", + "integrity": "sha1-d1s/J477uXGO7HNh9IP7Nvu/6og=", + "dev": true + } + } + }, + "mime": { + "version": "2.5.2", + "resolved": "https://registry.npm.taobao.org/mime/download/mime-2.5.2.tgz", + "integrity": "sha1-bj3GzCuVEGQ4MOXxnVy3U9pe6r4=", + "dev": true + }, + "mime-db": { + "version": "1.47.0", + "resolved": "https://registry.nlark.com/mime-db/download/mime-db-1.47.0.tgz", + "integrity": "sha1-jLMT5Zll08Bc+/iYkVomevRqM1w=", + "dev": true + }, + "mime-types": { + "version": "2.1.30", + "resolved": "https://registry.npm.taobao.org/mime-types/download/mime-types-2.1.30.tgz", + "integrity": "sha1-bnvotMR5gl+F7WMmaV23P5MF1i0=", + "dev": true, + "requires": { + "mime-db": "1.47.0" + } + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npm.taobao.org/mimic-fn/download/mimic-fn-1.2.0.tgz", + "integrity": "sha1-ggyGo5M0ZA6ZUWkovQP8qIBX0CI=", + "dev": true + }, + "mini-css-extract-plugin": { + "version": "0.9.0", + "resolved": "https://registry.nlark.com/mini-css-extract-plugin/download/mini-css-extract-plugin-0.9.0.tgz?cache=0&sync_timestamp=1619783320763&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fmini-css-extract-plugin%2Fdownload%2Fmini-css-extract-plugin-0.9.0.tgz", + "integrity": "sha1-R/LPB6oWWrNXM7H8l9TEbAVkM54=", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "normalize-url": "1.9.1", + "schema-utils": "^1.0.0", + "webpack-sources": "^1.1.0" + }, + "dependencies": { + "normalize-url": { + "version": "1.9.1", + "resolved": "https://registry.nlark.com/normalize-url/download/normalize-url-1.9.1.tgz", + "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=", + "dev": true, + "requires": { + "object-assign": "^4.0.1", + "prepend-http": "^1.0.0", + "query-string": "^4.1.0", + "sort-keys": "^1.0.0" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-1.0.0.tgz", + "integrity": "sha1-C3mpMgTXtgDUsoUNH2bCo0lRx3A=", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.nlark.com/minimalistic-assert/download/minimalistic-assert-1.0.1.tgz", + "integrity": "sha1-LhlN4ERibUoQ5/f7wAznPoPk1cc=", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.nlark.com/minimalistic-crypto-utils/download/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npm.taobao.org/minimatch/download/minimatch-3.0.4.tgz", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.nlark.com/minimist/download/minimist-1.2.5.tgz?cache=0&sync_timestamp=1618847017774&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fminimist%2Fdownload%2Fminimist-1.2.5.tgz", + "integrity": "sha1-Z9ZgFLZqaoqqDAg8X9WN9OTpdgI=", + "dev": true + }, + "minipass": { + "version": "3.1.3", + "resolved": "https://registry.npm.taobao.org/minipass/download/minipass-3.1.3.tgz", + "integrity": "sha1-fUL/HzljVILhX5zbUxhN7r1YFf0=", + "dev": true, + "requires": { + "yallist": "^4.0.0" + }, + "dependencies": { + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npm.taobao.org/yallist/download/yallist-4.0.0.tgz", + "integrity": "sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI=", + "dev": true + } + } + }, + "mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/mississippi/download/mississippi-3.0.0.tgz", + "integrity": "sha1-6goykfl+C16HdrNj1fChLZTGcCI=", + "dev": true, + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + } + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npm.taobao.org/mixin-deep/download/mixin-deep-1.3.2.tgz", + "integrity": "sha1-ESC0PcNZp4Xc5ltVuC4lfM9HlWY=", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npm.taobao.org/is-extendable/download/is-extendable-1.0.1.tgz", + "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npm.taobao.org/mkdirp/download/mkdirp-0.5.5.tgz", + "integrity": "sha1-2Rzv1i0UNsoPQWIOJRKI1CAJne8=", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.nlark.com/move-concurrently/download/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.2.tgz?cache=0&sync_timestamp=1607433950466&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.1.2.tgz", + "integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk=", + "dev": true + }, + "multicast-dns": { + "version": "6.2.3", + "resolved": "https://registry.nlark.com/multicast-dns/download/multicast-dns-6.2.3.tgz", + "integrity": "sha1-oOx72QVcQoL3kMPIL04o2zsxsik=", + "dev": true, + "requires": { + "dns-packet": "^1.3.1", + "thunky": "^1.0.2" + } + }, + "multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.nlark.com/multicast-dns-service-types/download/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", + "dev": true + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.nlark.com/mute-stream/download/mute-stream-0.0.8.tgz", + "integrity": "sha1-FjDEKyJR/4HiooPelqVJfqkuXg0=", + "dev": true + }, + "mz": { + "version": "2.7.0", + "resolved": "https://registry.npm.taobao.org/mz/download/mz-2.7.0.tgz", + "integrity": "sha1-lQCAV6Vsr63CvGPd5/n/aVWUjjI=", + "dev": true, + "requires": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "nan": { + "version": "2.14.2", + "resolved": "https://registry.nlark.com/nan/download/nan-2.14.2.tgz", + "integrity": "sha1-9TdkAGlRaPTMaUrJOT0MlYXu6hk=", + "dev": true, + "optional": true + }, + "nanoid": { + "version": "3.1.23", + "resolved": "https://registry.nlark.com/nanoid/download/nanoid-3.1.23.tgz", + "integrity": "sha1-90QIbOfCvEfuCoRyV01ceOQYOoE=", + "dev": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.nlark.com/nanomatch/download/nanomatch-1.2.13.tgz", + "integrity": "sha1-uHqKpPwN6P5r6IiVs4mD/yZb0Rk=", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npm.taobao.org/natural-compare/download/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npm.taobao.org/negotiator/download/negotiator-0.6.2.tgz", + "integrity": "sha1-/qz3zPUlp3rpY0Q2pkiD/+yjRvs=", + "dev": true + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.nlark.com/neo-async/download/neo-async-2.6.2.tgz", + "integrity": "sha1-tKr7k+OustgXTKU88WOrfXMIMF8=", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npm.taobao.org/nice-try/download/nice-try-1.0.5.tgz?cache=0&sync_timestamp=1614510016909&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnice-try%2Fdownload%2Fnice-try-1.0.5.tgz", + "integrity": "sha1-ozeKdpbOfSI+iPybdkvX7xCJ42Y=", + "dev": true + }, + "no-case": { + "version": "2.3.2", + "resolved": "https://registry.npm.taobao.org/no-case/download/no-case-2.3.2.tgz", + "integrity": "sha1-YLgTOWvjmz8SiKTB7V0efSi0ZKw=", + "dev": true, + "requires": { + "lower-case": "^1.1.1" + } + }, + "node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npm.taobao.org/node-forge/download/node-forge-0.10.0.tgz?cache=0&sync_timestamp=1599054189018&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnode-forge%2Fdownload%2Fnode-forge-0.10.0.tgz", + "integrity": "sha1-Mt6ir7Ppkm8C7lzoeUkCaRpna/M=", + "dev": true + }, + "node-ipc": { + "version": "9.1.4", + "resolved": "https://registry.nlark.com/node-ipc/download/node-ipc-9.1.4.tgz", + "integrity": "sha1-Ks+WJoGv2sJgKHbZj+ZDTVTZvTw=", + "dev": true, + "requires": { + "event-pubsub": "4.3.0", + "js-message": "1.0.7", + "js-queue": "2.0.2" + } + }, + "node-libs-browser": { + "version": "2.2.1", + "resolved": "https://registry.nlark.com/node-libs-browser/download/node-libs-browser-2.2.1.tgz", + "integrity": "sha1-tk9RPRgzhiX5A0bSew0jXmMfZCU=", + "dev": true, + "requires": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.1", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "^1.0.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.nlark.com/punycode/download/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } + } + }, + "node-releases": { + "version": "1.1.72", + "resolved": "https://registry.nlark.com/node-releases/download/node-releases-1.1.72.tgz?cache=0&sync_timestamp=1620978655178&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fnode-releases%2Fdownload%2Fnode-releases-1.1.72.tgz", + "integrity": "sha1-FIAqtrEDmnmgx9ZithClu9durL4=", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.nlark.com/normalize-package-data/download/normalize-package-data-2.5.0.tgz", + "integrity": "sha1-5m2xg4sgDB38IzIl0SyzZSDiNKg=", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.nlark.com/semver/download/semver-5.7.1.tgz?cache=0&sync_timestamp=1618847119601&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fsemver%2Fdownload%2Fsemver-5.7.1.tgz", + "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=", + "dev": true + } + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/normalize-path/download/normalize-path-3.0.0.tgz", + "integrity": "sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU=", + "dev": true + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npm.taobao.org/normalize-range/download/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "dev": true + }, + "normalize-url": { + "version": "3.3.0", + "resolved": "https://registry.nlark.com/normalize-url/download/normalize-url-3.3.0.tgz", + "integrity": "sha1-suHE3E98bVd0PfczpPWXjRhlBVk=", + "dev": true + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npm.taobao.org/npm-run-path/download/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "nth-check": { + "version": "1.0.2", + "resolved": "https://registry.nlark.com/nth-check/download/nth-check-1.0.2.tgz", + "integrity": "sha1-sr0pXDfj3VijvwcAN2Zjuk2c8Fw=", + "dev": true, + "requires": { + "boolbase": "~1.0.0" + } + }, + "num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npm.taobao.org/num2fraction/download/num2fraction-1.2.2.tgz", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", + "dev": true + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.nlark.com/oauth-sign/download/oauth-sign-0.9.0.tgz", + "integrity": "sha1-R6ewFrqmi1+g7PPe4IqFxnmsZFU=", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.nlark.com/object-assign/download/object-assign-4.1.1.tgz?cache=0&sync_timestamp=1618847043548&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fobject-assign%2Fdownload%2Fobject-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npm.taobao.org/object-copy/download/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.nlark.com/kind-of/download/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-hash": { + "version": "1.3.1", + "resolved": "https://registry.nlark.com/object-hash/download/object-hash-1.3.1.tgz", + "integrity": "sha1-/eRSCYqVHLFF8Dm7fUVUSd3BJt8=", + "dev": true + }, + "object-inspect": { + "version": "1.10.3", + "resolved": "https://registry.nlark.com/object-inspect/download/object-inspect-1.10.3.tgz", + "integrity": "sha1-wqp9LQn1DJk3VwT3oK3yTFeC02k=", + "dev": true + }, + "object-is": { + "version": "1.1.5", + "resolved": "https://registry.npm.taobao.org/object-is/download/object-is-1.1.5.tgz?cache=0&sync_timestamp=1613857698573&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fobject-is%2Fdownload%2Fobject-is-1.1.5.tgz", + "integrity": "sha1-ud7qpfx/GEag+uzc7sE45XePU6w=", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.nlark.com/object-keys/download/object-keys-1.1.1.tgz", + "integrity": "sha1-HEfyct8nfzsdrwYWd9nILiMixg4=", + "dev": true + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.nlark.com/object-visit/download/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.nlark.com/object.assign/download/object.assign-4.1.2.tgz", + "integrity": "sha1-DtVKNC7Os3s4/3brgxoOeIy2OUA=", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.2", + "resolved": "https://registry.npm.taobao.org/object.getownpropertydescriptors/download/object.getownpropertydescriptors-2.1.2.tgz?cache=0&sync_timestamp=1613860004199&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fobject.getownpropertydescriptors%2Fdownload%2Fobject.getownpropertydescriptors-2.1.2.tgz", + "integrity": "sha1-G9Y66s8NXS0vMbXjk7A6fGAaI/c=", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npm.taobao.org/object.pick/download/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "object.values": { + "version": "1.1.4", + "resolved": "https://registry.nlark.com/object.values/download/object.values-1.1.4.tgz?cache=0&sync_timestamp=1622070620040&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fobject.values%2Fdownload%2Fobject.values-1.1.4.tgz", + "integrity": "sha1-DSc3YoM+gWtpOmN9MAc+cFFTWzA=", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.2" + } + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.nlark.com/obuf/download/obuf-1.1.2.tgz", + "integrity": "sha1-Cb6jND1BhZ69RGKS0RydTbYZCE4=", + "dev": true + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.nlark.com/on-finished/download/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.nlark.com/on-headers/download/on-headers-1.0.2.tgz", + "integrity": "sha1-dysK5qqlJcOZ5Imt+tkMQD6zwo8=", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.nlark.com/once/download/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npm.taobao.org/onetime/download/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "open": { + "version": "6.4.0", + "resolved": "https://registry.nlark.com/open/download/open-6.4.0.tgz", + "integrity": "sha1-XBPpbQ3IlGhhZPGJZez+iJ7PyKk=", + "dev": true, + "requires": { + "is-wsl": "^1.1.0" + } + }, + "opener": { + "version": "1.5.2", + "resolved": "https://registry.npm.taobao.org/opener/download/opener-1.5.2.tgz", + "integrity": "sha1-XTfh81B3udysQwE3InGv3rKhNZg=", + "dev": true + }, + "opn": { + "version": "5.5.0", + "resolved": "https://registry.nlark.com/opn/download/opn-5.5.0.tgz", + "integrity": "sha1-/HFk+rVtI1kExRw7J9pnWMo7m/w=", + "dev": true, + "requires": { + "is-wsl": "^1.1.0" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.nlark.com/optionator/download/optionator-0.8.3.tgz", + "integrity": "sha1-hPodA2/p08fiHZmIS2ARZ+yPtJU=", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "ora": { + "version": "3.4.0", + "resolved": "https://registry.nlark.com/ora/download/ora-3.4.0.tgz", + "integrity": "sha1-vwdSSRBZo+8+1MhQl1Md6f280xg=", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-spinners": "^2.0.0", + "log-symbols": "^2.2.0", + "strip-ansi": "^5.2.0", + "wcwidth": "^1.0.1" + }, + "dependencies": { + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-5.2.0.tgz?cache=0&sync_timestamp=1618553320591&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-5.2.0.tgz", + "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "original": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/original/download/original-1.0.2.tgz", + "integrity": "sha1-5EKmHP/hxf0gpl8yYcJmY7MD8l8=", + "dev": true, + "requires": { + "url-parse": "^1.4.3" + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.nlark.com/os-browserify/download/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", + "dev": true + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/os-tmpdir/download/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/p-finally/download/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.nlark.com/p-limit/download/p-limit-2.3.0.tgz", + "integrity": "sha1-PdM8ZHohT9//2DWTPrCG2g3CHbE=", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.nlark.com/p-locate/download/p-locate-4.1.0.tgz", + "integrity": "sha1-o0KLtwiLOmApL2aRkni3wpetTwc=", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.nlark.com/p-map/download/p-map-2.1.0.tgz", + "integrity": "sha1-MQko/u+cnsxltosXaTAYpmXOoXU=", + "dev": true + }, + "p-retry": { + "version": "3.0.1", + "resolved": "https://registry.npm.taobao.org/p-retry/download/p-retry-3.0.1.tgz", + "integrity": "sha1-MWtMiJPiyNwc+okfQGxLQivr8yg=", + "dev": true, + "requires": { + "retry": "^0.12.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npm.taobao.org/p-try/download/p-try-2.2.0.tgz", + "integrity": "sha1-yyhoVA4xPWHeWPr741zpAE1VQOY=", + "dev": true + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.nlark.com/pako/download/pako-1.0.11.tgz", + "integrity": "sha1-bJWZ00DVTf05RjgCUqNXBaa5kr8=", + "dev": true + }, + "parallel-transform": { + "version": "1.2.0", + "resolved": "https://registry.npm.taobao.org/parallel-transform/download/parallel-transform-1.2.0.tgz", + "integrity": "sha1-kEnKN9bLIYLDsdLHIL6U0UpYFPw=", + "dev": true, + "requires": { + "cyclist": "^1.0.1", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "param-case": { + "version": "2.1.1", + "resolved": "https://registry.nlark.com/param-case/download/param-case-2.1.1.tgz", + "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", + "dev": true, + "requires": { + "no-case": "^2.2.0" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npm.taobao.org/parent-module/download/parent-module-1.0.1.tgz", + "integrity": "sha1-aR0nCeeMefrjoVZiJFLQB2LKqqI=", + "dev": true, + "requires": { + "callsites": "^3.0.0" + }, + "dependencies": { + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npm.taobao.org/callsites/download/callsites-3.1.0.tgz", + "integrity": "sha1-s2MKvYlDQy9Us/BRkjjjPNffL3M=", + "dev": true + } + } + }, + "parse-asn1": { + "version": "5.1.6", + "resolved": "https://registry.nlark.com/parse-asn1/download/parse-asn1-5.1.6.tgz", + "integrity": "sha1-OFCAo+wTy2KmLTlAnLPoiETNrtQ=", + "dev": true, + "requires": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.nlark.com/parse-json/download/parse-json-5.2.0.tgz", + "integrity": "sha1-x2/Gbe5UIxyWKyK8yKcs8vmXU80=", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "parse5": { + "version": "5.1.1", + "resolved": "https://registry.nlark.com/parse5/download/parse5-5.1.1.tgz", + "integrity": "sha1-9o5OW6GFKsLK3AD0VV//bCq7YXg=", + "dev": true + }, + "parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npm.taobao.org/parse5-htmlparser2-tree-adapter/download/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha1-LN+a2CMyEUA3DU2/XT6Sx8jdxuY=", + "dev": true, + "requires": { + "parse5": "^6.0.1" + }, + "dependencies": { + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.nlark.com/parse5/download/parse5-6.0.1.tgz", + "integrity": "sha1-4aHAhcVps9wIMhGE8Zo5zCf3wws=", + "dev": true + } + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npm.taobao.org/parseurl/download/parseurl-1.3.3.tgz?cache=0&sync_timestamp=1599054201722&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fparseurl%2Fdownload%2Fparseurl-1.3.3.tgz", + "integrity": "sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ=", + "dev": true + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npm.taobao.org/pascalcase/download/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.nlark.com/path-browserify/download/path-browserify-0.0.1.tgz", + "integrity": "sha1-5sTd1+06onxoogzE5Q4aTug7vEo=", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/path-dirname/download/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.nlark.com/path-exists/download/path-exists-4.0.0.tgz", + "integrity": "sha1-UTvb4tO5XXdi6METfvoZXGxhtbM=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npm.taobao.org/path-is-absolute/download/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.nlark.com/path-is-inside/download/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npm.taobao.org/path-key/download/path-key-2.0.1.tgz?cache=0&sync_timestamp=1617971695678&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpath-key%2Fdownload%2Fpath-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.nlark.com/path-parse/download/path-parse-1.0.7.tgz", + "integrity": "sha1-+8EUtgykKzDZ2vWFjkvWi77bZzU=", + "dev": true + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.nlark.com/path-to-regexp/download/path-to-regexp-0.1.7.tgz?cache=0&sync_timestamp=1618846809278&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpath-to-regexp%2Fdownload%2Fpath-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", + "dev": true + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/path-type/download/path-type-3.0.0.tgz?cache=0&sync_timestamp=1611752107592&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpath-type%2Fdownload%2Fpath-type-3.0.0.tgz", + "integrity": "sha1-zvMdyOCho7sNEFwM2Xzzv0f0428=", + "dev": true, + "requires": { + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/pify/download/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.nlark.com/pbkdf2/download/pbkdf2-3.1.2.tgz", + "integrity": "sha1-3YIqoIh1gOUvGgOdw+2hCO+uMHU=", + "dev": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.nlark.com/performance-now/download/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.nlark.com/picomatch/download/picomatch-2.3.0.tgz?cache=0&sync_timestamp=1621648246651&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpicomatch%2Fdownload%2Fpicomatch-2.3.0.tgz", + "integrity": "sha1-8fBh3o9qS/AiiS4tEoI0+5gwKXI=", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npm.taobao.org/pify/download/pify-4.0.1.tgz", + "integrity": "sha1-SyzSXFDVmHNcUCkiJP2MbfQeMjE=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npm.taobao.org/pinkie/download/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.nlark.com/pinkie-promise/download/pinkie-promise-2.0.1.tgz?cache=0&sync_timestamp=1618847023792&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpinkie-promise%2Fdownload%2Fpinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npm.taobao.org/pkg-dir/download/pkg-dir-4.2.0.tgz?cache=0&sync_timestamp=1602859045787&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpkg-dir%2Fdownload%2Fpkg-dir-4.2.0.tgz", + "integrity": "sha1-8JkTPfft5CLoHR2ESCcO6z5CYfM=", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "pnp-webpack-plugin": { + "version": "1.6.4", + "resolved": "https://registry.npm.taobao.org/pnp-webpack-plugin/download/pnp-webpack-plugin-1.6.4.tgz", + "integrity": "sha1-yXEaxNxIpoXauvyG+Lbdn434QUk=", + "dev": true, + "requires": { + "ts-pnp": "^1.1.6" + } + }, + "portfinder": { + "version": "1.0.28", + "resolved": "https://registry.nlark.com/portfinder/download/portfinder-1.0.28.tgz", + "integrity": "sha1-Z8RiKFK9U3TdHdkA93n1NGL6x3g=", + "dev": true, + "requires": { + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.5" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.nlark.com/debug/download/debug-3.2.7.tgz?cache=0&sync_timestamp=1618847042350&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdebug%2Fdownload%2Fdebug-3.2.7.tgz", + "integrity": "sha1-clgLfpFF+zm2Z2+cXl+xALk0F5o=", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.nlark.com/posix-character-classes/download/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.nlark.com/postcss/download/postcss-7.0.35.tgz?cache=0&sync_timestamp=1621568644827&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss%2Fdownload%2Fpostcss-7.0.35.tgz", + "integrity": "sha1-0r4AuZj38hHYonaXQHny6SuXDiQ=", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.nlark.com/supports-color/download/supports-color-6.1.0.tgz?cache=0&sync_timestamp=1622293670728&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fsupports-color%2Fdownload%2Fsupports-color-6.1.0.tgz", + "integrity": "sha1-B2Srxpxj1ayELdSGfo0CXogN+PM=", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-calc": { + "version": "7.0.5", + "resolved": "https://registry.npm.taobao.org/postcss-calc/download/postcss-calc-7.0.5.tgz?cache=0&sync_timestamp=1609689139608&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-calc%2Fdownload%2Fpostcss-calc-7.0.5.tgz", + "integrity": "sha1-+KbpnxLmGcLrwjz2xIb9wVhgkz4=", + "dev": true, + "requires": { + "postcss": "^7.0.27", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.0.2" + } + }, + "postcss-colormin": { + "version": "4.0.3", + "resolved": "https://registry.nlark.com/postcss-colormin/download/postcss-colormin-4.0.3.tgz", + "integrity": "sha1-rgYLzpPteUrHEmTwgTLVUJVr04E=", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "color": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.nlark.com/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-value-parser%2Fdownload%2Fpostcss-value-parser-3.3.1.tgz", + "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", + "dev": true + } + } + }, + "postcss-convert-values": { + "version": "4.0.1", + "resolved": "https://registry.nlark.com/postcss-convert-values/download/postcss-convert-values-4.0.1.tgz?cache=0&sync_timestamp=1621449733448&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-convert-values%2Fdownload%2Fpostcss-convert-values-4.0.1.tgz", + "integrity": "sha1-yjgT7U2g+BL51DcDWE5Enr4Ymn8=", + "dev": true, + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.nlark.com/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-value-parser%2Fdownload%2Fpostcss-value-parser-3.3.1.tgz", + "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", + "dev": true + } + } + }, + "postcss-discard-comments": { + "version": "4.0.2", + "resolved": "https://registry.nlark.com/postcss-discard-comments/download/postcss-discard-comments-4.0.2.tgz?cache=0&sync_timestamp=1621449558287&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-discard-comments%2Fdownload%2Fpostcss-discard-comments-4.0.2.tgz", + "integrity": "sha1-H7q9LCRr/2qq15l7KwkY9NevQDM=", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-discard-duplicates": { + "version": "4.0.2", + "resolved": "https://registry.nlark.com/postcss-discard-duplicates/download/postcss-discard-duplicates-4.0.2.tgz?cache=0&sync_timestamp=1621449558296&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-discard-duplicates%2Fdownload%2Fpostcss-discard-duplicates-4.0.2.tgz", + "integrity": "sha1-P+EzzTyCKC5VD8myORdqkge3hOs=", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-discard-empty": { + "version": "4.0.1", + "resolved": "https://registry.nlark.com/postcss-discard-empty/download/postcss-discard-empty-4.0.1.tgz?cache=0&sync_timestamp=1621449733074&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-discard-empty%2Fdownload%2Fpostcss-discard-empty-4.0.1.tgz", + "integrity": "sha1-yMlR6fc+2UKAGUWERKAq2Qu592U=", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-discard-overridden": { + "version": "4.0.1", + "resolved": "https://registry.nlark.com/postcss-discard-overridden/download/postcss-discard-overridden-4.0.1.tgz?cache=0&sync_timestamp=1621449732464&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-discard-overridden%2Fdownload%2Fpostcss-discard-overridden-4.0.1.tgz", + "integrity": "sha1-ZSrvipZybwKfXj4AFG7npOdV/1c=", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-load-config": { + "version": "2.1.2", + "resolved": "https://registry.nlark.com/postcss-load-config/download/postcss-load-config-2.1.2.tgz?cache=0&sync_timestamp=1618847231779&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-load-config%2Fdownload%2Fpostcss-load-config-2.1.2.tgz", + "integrity": "sha1-xepQTyxK7zPHNZo03jVzdyrXUCo=", + "dev": true, + "requires": { + "cosmiconfig": "^5.0.0", + "import-cwd": "^2.0.0" + } + }, + "postcss-loader": { + "version": "3.0.0", + "resolved": "https://registry.nlark.com/postcss-loader/download/postcss-loader-3.0.0.tgz", + "integrity": "sha1-a5eUPkfHLYRfqeA/Jzdz1OjdbC0=", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "postcss": "^7.0.0", + "postcss-load-config": "^2.0.0", + "schema-utils": "^1.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-1.0.0.tgz", + "integrity": "sha1-C3mpMgTXtgDUsoUNH2bCo0lRx3A=", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "postcss-merge-longhand": { + "version": "4.0.11", + "resolved": "https://registry.nlark.com/postcss-merge-longhand/download/postcss-merge-longhand-4.0.11.tgz?cache=0&sync_timestamp=1621449731452&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-merge-longhand%2Fdownload%2Fpostcss-merge-longhand-4.0.11.tgz", + "integrity": "sha1-YvSaE+Sg7gTnuY9CuxYGLKJUniQ=", + "dev": true, + "requires": { + "css-color-names": "0.0.4", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "stylehacks": "^4.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.nlark.com/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-value-parser%2Fdownload%2Fpostcss-value-parser-3.3.1.tgz", + "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", + "dev": true + } + } + }, + "postcss-merge-rules": { + "version": "4.0.3", + "resolved": "https://registry.nlark.com/postcss-merge-rules/download/postcss-merge-rules-4.0.3.tgz", + "integrity": "sha1-NivqT/Wh+Y5AdacTxsslrv75plA=", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "cssnano-util-same-parent": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0", + "vendors": "^1.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.nlark.com/postcss-selector-parser/download/postcss-selector-parser-3.1.2.tgz?cache=0&sync_timestamp=1620752939806&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-selector-parser%2Fdownload%2Fpostcss-selector-parser-3.1.2.tgz", + "integrity": "sha1-sxD1xMD9r3b5SQK7qjDbaqhPUnA=", + "dev": true, + "requires": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-minify-font-values": { + "version": "4.0.2", + "resolved": "https://registry.nlark.com/postcss-minify-font-values/download/postcss-minify-font-values-4.0.2.tgz?cache=0&sync_timestamp=1621449734134&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-minify-font-values%2Fdownload%2Fpostcss-minify-font-values-4.0.2.tgz", + "integrity": "sha1-zUw0TM5HQ0P6xdgiBqssvLiv1aY=", + "dev": true, + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.nlark.com/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-value-parser%2Fdownload%2Fpostcss-value-parser-3.3.1.tgz", + "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", + "dev": true + } + } + }, + "postcss-minify-gradients": { + "version": "4.0.2", + "resolved": "https://registry.nlark.com/postcss-minify-gradients/download/postcss-minify-gradients-4.0.2.tgz", + "integrity": "sha1-k7KcL/UJnFNe7NpWxKpuZlpmNHE=", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "is-color-stop": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.nlark.com/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-value-parser%2Fdownload%2Fpostcss-value-parser-3.3.1.tgz", + "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", + "dev": true + } + } + }, + "postcss-minify-params": { + "version": "4.0.2", + "resolved": "https://registry.nlark.com/postcss-minify-params/download/postcss-minify-params-4.0.2.tgz?cache=0&sync_timestamp=1621449735393&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-minify-params%2Fdownload%2Fpostcss-minify-params-4.0.2.tgz", + "integrity": "sha1-a5zvAwwR41Jh+V9hjJADbWgNuHQ=", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.0", + "browserslist": "^4.0.0", + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "uniqs": "^2.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.nlark.com/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-value-parser%2Fdownload%2Fpostcss-value-parser-3.3.1.tgz", + "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", + "dev": true + } + } + }, + "postcss-minify-selectors": { + "version": "4.0.2", + "resolved": "https://registry.nlark.com/postcss-minify-selectors/download/postcss-minify-selectors-4.0.2.tgz?cache=0&sync_timestamp=1621449558355&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-minify-selectors%2Fdownload%2Fpostcss-minify-selectors-4.0.2.tgz", + "integrity": "sha1-4uXrQL/uUA0M2SQ1APX46kJi+9g=", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.nlark.com/postcss-selector-parser/download/postcss-selector-parser-3.1.2.tgz?cache=0&sync_timestamp=1620752939806&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-selector-parser%2Fdownload%2Fpostcss-selector-parser-3.1.2.tgz", + "integrity": "sha1-sxD1xMD9r3b5SQK7qjDbaqhPUnA=", + "dev": true, + "requires": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-modules": { + "version": "4.0.0", + "resolved": "https://registry.npm.taobao.org/postcss-modules/download/postcss-modules-4.0.0.tgz", + "integrity": "sha1-K8fydquI8/Gw+t9svXdy1DtfO5s=", + "dev": true, + "requires": { + "generic-names": "^2.0.1", + "icss-replace-symbols": "^1.1.0", + "lodash.camelcase": "^4.3.0", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "string-hash": "^1.1.1" + }, + "dependencies": { + "icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npm.taobao.org/icss-utils/download/icss-utils-5.1.0.tgz?cache=0&sync_timestamp=1605801291394&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ficss-utils%2Fdownload%2Ficss-utils-5.1.0.tgz", + "integrity": "sha1-xr5oWKvQE9do6YNmrkfiXViHsa4=", + "dev": true + }, + "postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/postcss-modules-extract-imports/download/postcss-modules-extract-imports-3.0.0.tgz?cache=0&sync_timestamp=1602588245463&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-modules-extract-imports%2Fdownload%2Fpostcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha1-zaHwR8CugMl9vijD52pDuIAldB0=", + "dev": true + }, + "postcss-modules-local-by-default": { + "version": "4.0.0", + "resolved": "https://registry.nlark.com/postcss-modules-local-by-default/download/postcss-modules-local-by-default-4.0.0.tgz", + "integrity": "sha1-67tU+uFZjuz99pGgKz/zs5ClpRw=", + "dev": true, + "requires": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + } + }, + "postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/postcss-modules-scope/download/postcss-modules-scope-3.0.0.tgz?cache=0&sync_timestamp=1602593260387&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-modules-scope%2Fdownload%2Fpostcss-modules-scope-3.0.0.tgz", + "integrity": "sha1-nvMVFFbTu/oSDKRImN/Kby+gHwY=", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.4" + } + }, + "postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.nlark.com/postcss-modules-values/download/postcss-modules-values-4.0.0.tgz", + "integrity": "sha1-18Xn5ow7s8myfL9Iyguz/7RgLJw=", + "dev": true, + "requires": { + "icss-utils": "^5.0.0" + } + } + } + }, + "postcss-modules-extract-imports": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/postcss-modules-extract-imports/download/postcss-modules-extract-imports-2.0.0.tgz?cache=0&sync_timestamp=1602588245463&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-modules-extract-imports%2Fdownload%2Fpostcss-modules-extract-imports-2.0.0.tgz", + "integrity": "sha1-gYcZoa4doyX5gyRGsBE27rSTzX4=", + "dev": true, + "requires": { + "postcss": "^7.0.5" + } + }, + "postcss-modules-local-by-default": { + "version": "3.0.3", + "resolved": "https://registry.nlark.com/postcss-modules-local-by-default/download/postcss-modules-local-by-default-3.0.3.tgz", + "integrity": "sha1-uxTgzHgnnVBNvcv9fgyiiZP/u7A=", + "dev": true, + "requires": { + "icss-utils": "^4.1.1", + "postcss": "^7.0.32", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + } + }, + "postcss-modules-scope": { + "version": "2.2.0", + "resolved": "https://registry.npm.taobao.org/postcss-modules-scope/download/postcss-modules-scope-2.2.0.tgz?cache=0&sync_timestamp=1602593260387&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-modules-scope%2Fdownload%2Fpostcss-modules-scope-2.2.0.tgz", + "integrity": "sha1-OFyuATzHdD9afXYC0Qc6iequYu4=", + "dev": true, + "requires": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^6.0.0" + } + }, + "postcss-modules-values": { + "version": "3.0.0", + "resolved": "https://registry.nlark.com/postcss-modules-values/download/postcss-modules-values-3.0.0.tgz", + "integrity": "sha1-W1AA1uuuKbQlUwG0o6VFdEI+fxA=", + "dev": true, + "requires": { + "icss-utils": "^4.0.0", + "postcss": "^7.0.6" + } + }, + "postcss-normalize-charset": { + "version": "4.0.1", + "resolved": "https://registry.nlark.com/postcss-normalize-charset/download/postcss-normalize-charset-4.0.1.tgz?cache=0&sync_timestamp=1621449558308&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-normalize-charset%2Fdownload%2Fpostcss-normalize-charset-4.0.1.tgz", + "integrity": "sha1-izWt067oOhNrBHHg1ZvlilAoXdQ=", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-normalize-display-values": { + "version": "4.0.2", + "resolved": "https://registry.nlark.com/postcss-normalize-display-values/download/postcss-normalize-display-values-4.0.2.tgz?cache=0&sync_timestamp=1621449652268&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-normalize-display-values%2Fdownload%2Fpostcss-normalize-display-values-4.0.2.tgz", + "integrity": "sha1-Db4EpM6QY9RmftK+R2u4MMglk1o=", + "dev": true, + "requires": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.nlark.com/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-value-parser%2Fdownload%2Fpostcss-value-parser-3.3.1.tgz", + "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", + "dev": true + } + } + }, + "postcss-normalize-positions": { + "version": "4.0.2", + "resolved": "https://registry.nlark.com/postcss-normalize-positions/download/postcss-normalize-positions-4.0.2.tgz?cache=0&sync_timestamp=1621449826472&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-normalize-positions%2Fdownload%2Fpostcss-normalize-positions-4.0.2.tgz", + "integrity": "sha1-BfdX+E8mBDc3g2ipH4ky1LECkX8=", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.nlark.com/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-value-parser%2Fdownload%2Fpostcss-value-parser-3.3.1.tgz", + "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", + "dev": true + } + } + }, + "postcss-normalize-repeat-style": { + "version": "4.0.2", + "resolved": "https://registry.nlark.com/postcss-normalize-repeat-style/download/postcss-normalize-repeat-style-4.0.2.tgz?cache=0&sync_timestamp=1621449651580&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-normalize-repeat-style%2Fdownload%2Fpostcss-normalize-repeat-style-4.0.2.tgz", + "integrity": "sha1-xOu8KJ85kaAo1EdRy90RkYsXkQw=", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.nlark.com/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-value-parser%2Fdownload%2Fpostcss-value-parser-3.3.1.tgz", + "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", + "dev": true + } + } + }, + "postcss-normalize-string": { + "version": "4.0.2", + "resolved": "https://registry.nlark.com/postcss-normalize-string/download/postcss-normalize-string-4.0.2.tgz?cache=0&sync_timestamp=1621449646930&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-normalize-string%2Fdownload%2Fpostcss-normalize-string-4.0.2.tgz", + "integrity": "sha1-zUTECrB6DHo23F6Zqs4eyk7CaQw=", + "dev": true, + "requires": { + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.nlark.com/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-value-parser%2Fdownload%2Fpostcss-value-parser-3.3.1.tgz", + "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", + "dev": true + } + } + }, + "postcss-normalize-timing-functions": { + "version": "4.0.2", + "resolved": "https://registry.nlark.com/postcss-normalize-timing-functions/download/postcss-normalize-timing-functions-4.0.2.tgz?cache=0&sync_timestamp=1621449827577&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-normalize-timing-functions%2Fdownload%2Fpostcss-normalize-timing-functions-4.0.2.tgz", + "integrity": "sha1-jgCcoqOUnNr4rSPmtquZy159KNk=", + "dev": true, + "requires": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.nlark.com/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-value-parser%2Fdownload%2Fpostcss-value-parser-3.3.1.tgz", + "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", + "dev": true + } + } + }, + "postcss-normalize-unicode": { + "version": "4.0.1", + "resolved": "https://registry.nlark.com/postcss-normalize-unicode/download/postcss-normalize-unicode-4.0.1.tgz?cache=0&sync_timestamp=1621449825612&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-normalize-unicode%2Fdownload%2Fpostcss-normalize-unicode-4.0.1.tgz", + "integrity": "sha1-hBvUj9zzAZrUuqdJOj02O1KuHPs=", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.nlark.com/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-value-parser%2Fdownload%2Fpostcss-value-parser-3.3.1.tgz", + "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", + "dev": true + } + } + }, + "postcss-normalize-url": { + "version": "4.0.1", + "resolved": "https://registry.nlark.com/postcss-normalize-url/download/postcss-normalize-url-4.0.1.tgz?cache=0&sync_timestamp=1621449733814&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-normalize-url%2Fdownload%2Fpostcss-normalize-url-4.0.1.tgz", + "integrity": "sha1-EOQ3+GvHx+WPe5ZS7YeNqqlfquE=", + "dev": true, + "requires": { + "is-absolute-url": "^2.0.0", + "normalize-url": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.nlark.com/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-value-parser%2Fdownload%2Fpostcss-value-parser-3.3.1.tgz", + "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", + "dev": true + } + } + }, + "postcss-normalize-whitespace": { + "version": "4.0.2", + "resolved": "https://registry.nlark.com/postcss-normalize-whitespace/download/postcss-normalize-whitespace-4.0.2.tgz?cache=0&sync_timestamp=1621449646853&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-normalize-whitespace%2Fdownload%2Fpostcss-normalize-whitespace-4.0.2.tgz", + "integrity": "sha1-vx1AcP5Pzqh9E0joJdjMDF+qfYI=", + "dev": true, + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.nlark.com/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-value-parser%2Fdownload%2Fpostcss-value-parser-3.3.1.tgz", + "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", + "dev": true + } + } + }, + "postcss-ordered-values": { + "version": "4.1.2", + "resolved": "https://registry.nlark.com/postcss-ordered-values/download/postcss-ordered-values-4.1.2.tgz?cache=0&sync_timestamp=1621449735687&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-ordered-values%2Fdownload%2Fpostcss-ordered-values-4.1.2.tgz", + "integrity": "sha1-DPdcgg7H1cTSgBiVWeC1ceusDu4=", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.nlark.com/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-value-parser%2Fdownload%2Fpostcss-value-parser-3.3.1.tgz", + "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", + "dev": true + } + } + }, + "postcss-reduce-initial": { + "version": "4.0.3", + "resolved": "https://registry.nlark.com/postcss-reduce-initial/download/postcss-reduce-initial-4.0.3.tgz?cache=0&sync_timestamp=1621449728984&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-reduce-initial%2Fdownload%2Fpostcss-reduce-initial-4.0.3.tgz", + "integrity": "sha1-f9QuvqXpyBRgljniwuhK4nC6SN8=", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0" + } + }, + "postcss-reduce-transforms": { + "version": "4.0.2", + "resolved": "https://registry.nlark.com/postcss-reduce-transforms/download/postcss-reduce-transforms-4.0.2.tgz?cache=0&sync_timestamp=1621449730895&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-reduce-transforms%2Fdownload%2Fpostcss-reduce-transforms-4.0.2.tgz", + "integrity": "sha1-F++kBerMbge+NBSlyi0QdGgdTik=", + "dev": true, + "requires": { + "cssnano-util-get-match": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.nlark.com/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-value-parser%2Fdownload%2Fpostcss-value-parser-3.3.1.tgz", + "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", + "dev": true + } + } + }, + "postcss-selector-parser": { + "version": "6.0.6", + "resolved": "https://registry.nlark.com/postcss-selector-parser/download/postcss-selector-parser-6.0.6.tgz?cache=0&sync_timestamp=1620752939806&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-selector-parser%2Fdownload%2Fpostcss-selector-parser-6.0.6.tgz", + "integrity": "sha1-LFu6gXSsL2mBq2MaQqsO5UrzMuo=", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "postcss-svgo": { + "version": "4.0.3", + "resolved": "https://registry.nlark.com/postcss-svgo/download/postcss-svgo-4.0.3.tgz", + "integrity": "sha1-NDos26yVBdQWJD1Jb3JPOIlMlB4=", + "dev": true, + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "svgo": "^1.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.nlark.com/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-value-parser%2Fdownload%2Fpostcss-value-parser-3.3.1.tgz", + "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", + "dev": true + } + } + }, + "postcss-unique-selectors": { + "version": "4.0.1", + "resolved": "https://registry.nlark.com/postcss-unique-selectors/download/postcss-unique-selectors-4.0.1.tgz?cache=0&sync_timestamp=1621449730035&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-unique-selectors%2Fdownload%2Fpostcss-unique-selectors-4.0.1.tgz", + "integrity": "sha1-lEaRHzKJv9ZMbWgPBzwDsfnuS6w=", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.0", + "postcss": "^7.0.0", + "uniqs": "^2.0.0" + } + }, + "postcss-value-parser": { + "version": "4.1.0", + "resolved": "https://registry.nlark.com/postcss-value-parser/download/postcss-value-parser-4.1.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-value-parser%2Fdownload%2Fpostcss-value-parser-4.1.0.tgz", + "integrity": "sha1-RD9qIM7WSBor2k+oUypuVdeJoss=", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.nlark.com/prelude-ls/download/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.nlark.com/prepend-http/download/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true + }, + "prettier": { + "version": "1.19.1", + "resolved": "https://registry.nlark.com/prettier/download/prettier-1.19.1.tgz?cache=0&sync_timestamp=1620594183343&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fprettier%2Fdownload%2Fprettier-1.19.1.tgz", + "integrity": "sha1-99f1/4qc2HKnvkyhQglZVqYHl8s=", + "dev": true, + "optional": true + }, + "pretty-error": { + "version": "2.1.2", + "resolved": "https://registry.nlark.com/pretty-error/download/pretty-error-2.1.2.tgz", + "integrity": "sha1-von4LYGxyG7I/fvDhQRYgnJ/k7Y=", + "dev": true, + "requires": { + "lodash": "^4.17.20", + "renderkid": "^2.0.4" + } + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npm.taobao.org/process/download/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npm.taobao.org/process-nextick-args/download/process-nextick-args-2.0.1.tgz", + "integrity": "sha1-eCDZsWEgzFXKmud5JoCufbptf+I=", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npm.taobao.org/progress/download/progress-2.0.3.tgz?cache=0&sync_timestamp=1599054255267&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fprogress%2Fdownload%2Fprogress-2.0.3.tgz", + "integrity": "sha1-foz42PW48jnBvGi+tOt4Vn1XLvg=", + "dev": true + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.nlark.com/promise-inflight/download/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true + }, + "proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.nlark.com/proxy-addr/download/proxy-addr-2.0.6.tgz", + "integrity": "sha1-/cIzZQVEfT8vLGOO0nLK9hS7sr8=", + "dev": true, + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + } + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.nlark.com/prr/download/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/pseudomap/download/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npm.taobao.org/psl/download/psl-1.8.0.tgz", + "integrity": "sha1-kyb4vPsBOtzABf3/BWrM4CDlHCQ=", + "dev": true + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npm.taobao.org/public-encrypt/download/public-encrypt-4.0.3.tgz", + "integrity": "sha1-T8ydd6B+SLp1J+fL4N4z0HATMeA=", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npm.taobao.org/bn.js/download/bn.js-4.12.0.tgz", + "integrity": "sha1-d1s/J477uXGO7HNh9IP7Nvu/6og=", + "dev": true + } + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/pump/download/pump-3.0.0.tgz", + "integrity": "sha1-tKIRaBW94vTh6mAjVOjHVWUQemQ=", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npm.taobao.org/pumpify/download/pumpify-1.5.1.tgz", + "integrity": "sha1-NlE74karJ1cLGjdKXOJ4v9dDcM4=", + "dev": true, + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npm.taobao.org/pump/download/pump-2.0.1.tgz", + "integrity": "sha1-Ejma3W5M91Jtlzy8i1zi4pCLOQk=", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.nlark.com/punycode/download/punycode-2.1.1.tgz", + "integrity": "sha1-tYsBCsQMIsVldhbI0sLALHv0eew=", + "dev": true + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npm.taobao.org/q/download/q-1.5.1.tgz?cache=0&sync_timestamp=1599054212574&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fq%2Fdownload%2Fq-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "dev": true + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.nlark.com/qs/download/qs-6.5.2.tgz", + "integrity": "sha1-yzroBuh0BERYTvFUzo7pjUA/PjY=", + "dev": true + }, + "query-string": { + "version": "4.3.4", + "resolved": "https://registry.npm.taobao.org/query-string/download/query-string-4.3.4.tgz", + "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", + "dev": true, + "requires": { + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npm.taobao.org/querystring/download/querystring-0.2.0.tgz?cache=0&sync_timestamp=1613399913000&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fquerystring%2Fdownload%2Fquerystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.nlark.com/querystring-es3/download/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "dev": true + }, + "querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npm.taobao.org/querystringify/download/querystringify-2.2.0.tgz", + "integrity": "sha1-M0WUG0FTy50ILY7uTNogFqmu9/Y=", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npm.taobao.org/randombytes/download/randombytes-2.1.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frandombytes%2Fdownload%2Frandombytes-2.1.0.tgz", + "integrity": "sha1-32+ENy8CcNxlzfYpE0mrekc9Tyo=", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.nlark.com/randomfill/download/randomfill-1.0.4.tgz", + "integrity": "sha1-ySGW/IarQr6YPxvzF3giSTHWFFg=", + "dev": true, + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npm.taobao.org/range-parser/download/range-parser-1.2.1.tgz", + "integrity": "sha1-PPNwI9GZ4cJNGlW4SADC8+ZGgDE=", + "dev": true + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.nlark.com/raw-body/download/raw-body-2.4.0.tgz", + "integrity": "sha1-oc5vucm8NWylLoklarWQWeE9AzI=", + "dev": true, + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npm.taobao.org/read-pkg/download/read-pkg-5.2.0.tgz", + "integrity": "sha1-e/KVQ4yloz5WzTDgU7NO5yUMk8w=", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.nlark.com/readable-stream/download/readable-stream-2.3.7.tgz", + "integrity": "sha1-Hsoc9xGu+BTAT2IlKjamL2yyO1c=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "3.5.0", + "resolved": "https://registry.nlark.com/readdirp/download/readdirp-3.5.0.tgz", + "integrity": "sha1-m6dMAZsV02UnjS6Ru4xI17TULJ4=", + "dev": true, + "optional": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npm.taobao.org/regenerate/download/regenerate-1.4.2.tgz?cache=0&sync_timestamp=1604218353677&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fregenerate%2Fdownload%2Fregenerate-1.4.2.tgz", + "integrity": "sha1-uTRtiCfo9aMve6KWN9OYtpAUhIo=", + "dev": true + }, + "regenerate-unicode-properties": { + "version": "8.2.0", + "resolved": "https://registry.nlark.com/regenerate-unicode-properties/download/regenerate-unicode-properties-8.2.0.tgz", + "integrity": "sha1-5d5xEdZV57pgwFfb6f83yH5lzew=", + "dev": true, + "requires": { + "regenerate": "^1.4.0" + } + }, + "regenerator-runtime": { + "version": "0.13.7", + "resolved": "https://registry.npm.taobao.org/regenerator-runtime/download/regenerator-runtime-0.13.7.tgz", + "integrity": "sha1-ysLazIoepnX+qrrriugziYrkb1U=", + "dev": true + }, + "regenerator-transform": { + "version": "0.14.5", + "resolved": "https://registry.nlark.com/regenerator-transform/download/regenerator-transform-0.14.5.tgz", + "integrity": "sha1-yY2hVGg2ccnE3LFuznNlF+G3/rQ=", + "dev": true, + "requires": { + "@babel/runtime": "^7.8.4" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.nlark.com/regex-not/download/regex-not-1.0.2.tgz", + "integrity": "sha1-H07OJ+ALC2XgJHpoEOaoXYOldSw=", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "regexp.prototype.flags": { + "version": "1.3.1", + "resolved": "https://registry.nlark.com/regexp.prototype.flags/download/regexp.prototype.flags-1.3.1.tgz", + "integrity": "sha1-fvNSro0VnnWMDq3Kb4/LTu8HviY=", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.nlark.com/regexpp/download/regexpp-2.0.1.tgz", + "integrity": "sha1-jRnTHPYySCtYkEn4KB+T28uk0H8=", + "dev": true + }, + "regexpu-core": { + "version": "4.7.1", + "resolved": "https://registry.npm.taobao.org/regexpu-core/download/regexpu-core-4.7.1.tgz?cache=0&sync_timestamp=1600413461940&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fregexpu-core%2Fdownload%2Fregexpu-core-4.7.1.tgz", + "integrity": "sha1-LepamgcjMpj78NuR+pq8TG4PitY=", + "dev": true, + "requires": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.2.0", + "regjsgen": "^0.5.1", + "regjsparser": "^0.6.4", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.2.0" + } + }, + "regjsgen": { + "version": "0.5.2", + "resolved": "https://registry.nlark.com/regjsgen/download/regjsgen-0.5.2.tgz", + "integrity": "sha1-kv8pX7He7L9uzaslQ9IH6RqjNzM=", + "dev": true + }, + "regjsparser": { + "version": "0.6.9", + "resolved": "https://registry.npm.taobao.org/regjsparser/download/regjsparser-0.6.9.tgz?cache=0&sync_timestamp=1616544864193&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fregjsparser%2Fdownload%2Fregjsparser-0.6.9.tgz", + "integrity": "sha1-tInu98mizkNydicBFCnPgzpxg+Y=", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.nlark.com/jsesc/download/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + } + } + }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npm.taobao.org/relateurl/download/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", + "dev": true + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.nlark.com/remove-trailing-separator/download/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "renderkid": { + "version": "2.0.5", + "resolved": "https://registry.npm.taobao.org/renderkid/download/renderkid-2.0.5.tgz?cache=0&sync_timestamp=1609588663632&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frenderkid%2Fdownload%2Frenderkid-2.0.5.tgz", + "integrity": "sha1-SDsaxZxmAaswp6WWpZZcq8z90KU=", + "dev": true, + "requires": { + "css-select": "^2.0.2", + "dom-converter": "^0.2", + "htmlparser2": "^3.10.1", + "lodash": "^4.17.20", + "strip-ansi": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.nlark.com/ansi-regex/download/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-3.0.1.tgz?cache=0&sync_timestamp=1618553320591&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npm.taobao.org/repeat-element/download/repeat-element-1.1.4.tgz", + "integrity": "sha1-vmgVIIR6tYx1aKx1+/rSjtQtOek=", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npm.taobao.org/repeat-string/download/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.nlark.com/request/download/request-2.88.2.tgz", + "integrity": "sha1-1zyRhzHLWofaBH4gcjQUb2ZNErM=", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.nlark.com/require-directory/download/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/require-main-filename/download/require-main-filename-2.0.0.tgz", + "integrity": "sha1-0LMp7MfMD2Fkn2IhW+aa9UqomJs=", + "dev": true + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/requires-port/download/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "resolve": { + "version": "1.20.0", + "resolved": "https://registry.nlark.com/resolve/download/resolve-1.20.0.tgz", + "integrity": "sha1-YpoBP7P3B1XW8LeTXMHCxTeLGXU=", + "dev": true, + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.nlark.com/resolve-cwd/download/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.nlark.com/resolve-from/download/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.nlark.com/resolve-url/download/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.nlark.com/restore-cursor/download/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npm.taobao.org/ret/download/ret-0.1.15.tgz", + "integrity": "sha1-uKSCXVvbH8P29Twrwz+BOIaBx7w=", + "dev": true + }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.nlark.com/retry/download/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", + "dev": true + }, + "rgb-regex": { + "version": "1.0.1", + "resolved": "https://registry.npm.taobao.org/rgb-regex/download/rgb-regex-1.0.1.tgz", + "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=", + "dev": true + }, + "rgba-regex": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/rgba-regex/download/rgba-regex-1.0.0.tgz", + "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=", + "dev": true + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npm.taobao.org/rimraf/download/rimraf-2.7.1.tgz?cache=0&sync_timestamp=1614946161596&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frimraf%2Fdownload%2Frimraf-2.7.1.tgz", + "integrity": "sha1-NXl/E6f9rcVmFCwp1PB8ytSD4+w=", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.nlark.com/ripemd160/download/ripemd160-2.0.2.tgz", + "integrity": "sha1-ocGm9iR1FXe6XQeRTLyShQWFiQw=", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.nlark.com/run-async/download/run-async-2.4.1.tgz", + "integrity": "sha1-hEDsz5nqPnC9QJ1JqriOEMGJpFU=", + "dev": true + }, + "run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npm.taobao.org/run-queue/download/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "dev": true, + "requires": { + "aproba": "^1.1.1" + } + }, + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.nlark.com/rxjs/download/rxjs-6.6.7.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Frxjs%2Fdownload%2Frxjs-6.6.7.tgz", + "integrity": "sha1-kKwBisq/SRv2UEQjXVhjxNq4BMk=", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.nlark.com/safe-buffer/download/safe-buffer-5.1.2.tgz", + "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=", + "dev": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.nlark.com/safe-regex/download/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.nlark.com/safer-buffer/download/safer-buffer-2.1.2.tgz", + "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=", + "dev": true + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npm.taobao.org/sax/download/sax-1.2.4.tgz", + "integrity": "sha1-KBYjTiN4vdxOU1T6tcqold9xANk=", + "dev": true + }, + "schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-2.7.1.tgz", + "integrity": "sha1-HKTzLRskxZDCA7jnpQvw6kzTlNc=", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + } + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.nlark.com/select-hose/download/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", + "dev": true + }, + "selfsigned": { + "version": "1.10.11", + "resolved": "https://registry.nlark.com/selfsigned/download/selfsigned-1.10.11.tgz", + "integrity": "sha1-JJKc2Qb+D0S20B+yOZmnOVN6y+k=", + "dev": true, + "requires": { + "node-forge": "^0.10.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.nlark.com/semver/download/semver-6.3.0.tgz?cache=0&sync_timestamp=1618847119601&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fsemver%2Fdownload%2Fsemver-6.3.0.tgz", + "integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=", + "dev": true + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npm.taobao.org/send/download/send-0.17.1.tgz", + "integrity": "sha1-wdiwWfeQD3Rm3Uk4vcROEd2zdsg=", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.nlark.com/debug/download/debug-2.6.9.tgz?cache=0&sync_timestamp=1618847042350&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdebug%2Fdownload%2Fdebug-2.6.9.tgz", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "dev": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz?cache=0&sync_timestamp=1607433950466&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npm.taobao.org/mime/download/mime-1.6.0.tgz", + "integrity": "sha1-Ms2eXGRVO9WNGaVor0Uqz/BJgbE=", + "dev": true + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.1.tgz?cache=0&sync_timestamp=1607433950466&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.1.1.tgz", + "integrity": "sha1-MKWGTrPrsKZvLr5tcnrwagnYbgo=", + "dev": true + } + } + }, + "serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npm.taobao.org/serialize-javascript/download/serialize-javascript-4.0.0.tgz?cache=0&sync_timestamp=1599742605902&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fserialize-javascript%2Fdownload%2Fserialize-javascript-4.0.0.tgz", + "integrity": "sha1-tSXhI4SJpez8Qq+sw/6Z5mb0sao=", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.nlark.com/serve-index/download/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.nlark.com/debug/download/debug-2.6.9.tgz?cache=0&sync_timestamp=1618847042350&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdebug%2Fdownload%2Fdebug-2.6.9.tgz", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npm.taobao.org/http-errors/download/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.nlark.com/inherits/download/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz?cache=0&sync_timestamp=1607433950466&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.1.0.tgz", + "integrity": "sha1-0L2FU2iHtv58DYGMuWLZ2RxU5lY=", + "dev": true + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npm.taobao.org/serve-static/download/serve-static-1.14.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fserve-static%2Fdownload%2Fserve-static-1.14.1.tgz", + "integrity": "sha1-Zm5jbcTwEPfvKZcKiKZ0MgiYsvk=", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.nlark.com/set-blocking/download/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.nlark.com/set-value/download/set-value-2.0.1.tgz", + "integrity": "sha1-oY1AUw5vB95CKMfe/kInr4ytAFs=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.nlark.com/extend-shallow/download/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npm.taobao.org/setimmediate/download/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.1.1.tgz", + "integrity": "sha1-fpWsskqpL1iF4KvvW6ExMw1K5oM=", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npm.taobao.org/sha.js/download/sha.js-2.4.11.tgz", + "integrity": "sha1-N6XPC4HsvGlD3hCbopYNGyZYSuc=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npm.taobao.org/shebang-command/download/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/shebang-regex/download/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "shell-quote": { + "version": "1.7.2", + "resolved": "https://registry.npm.taobao.org/shell-quote/download/shell-quote-1.7.2.tgz", + "integrity": "sha1-Z6fQLHbJ2iT5nSCAj8re0ODgS+I=", + "dev": true + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npm.taobao.org/signal-exit/download/signal-exit-3.0.3.tgz?cache=0&sync_timestamp=1614858571178&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsignal-exit%2Fdownload%2Fsignal-exit-3.0.3.tgz", + "integrity": "sha1-oUEMLt2PB3sItOJTyOrPyvBXRhw=", + "dev": true + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.nlark.com/simple-swizzle/download/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "dev": true, + "requires": { + "is-arrayish": "^0.3.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npm.taobao.org/is-arrayish/download/is-arrayish-0.3.2.tgz", + "integrity": "sha1-RXSirlb3qyBolvtDHq7tBm/fjwM=", + "dev": true + } + } + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.nlark.com/slash/download/slash-2.0.0.tgz", + "integrity": "sha1-3lUoUaF1nfOo8gZTVEL17E3eq0Q=", + "dev": true + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npm.taobao.org/slice-ansi/download/slice-ansi-2.1.0.tgz?cache=0&sync_timestamp=1618555008681&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fslice-ansi%2Fdownload%2Fslice-ansi-2.1.0.tgz", + "integrity": "sha1-ys12k0YaY3pXiNkqfdT7oGjoFjY=", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-2.0.0.tgz?cache=0&sync_timestamp=1618552489864&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-fullwidth-code-point%2Fdownload%2Fis-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + } + } + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npm.taobao.org/snapdragon/download/snapdragon-0.8.2.tgz", + "integrity": "sha1-ZJIufFZbDhQgS6GqfWlkJ40lGC0=", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.nlark.com/debug/download/debug-2.6.9.tgz?cache=0&sync_timestamp=1618847042350&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdebug%2Fdownload%2Fdebug-2.6.9.tgz", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.nlark.com/extend-shallow/download/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz?cache=0&sync_timestamp=1607433950466&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npm.taobao.org/snapdragon-node/download/snapdragon-node-2.1.1.tgz", + "integrity": "sha1-bBdfhv8UvbByRWPo88GwIaKGhTs=", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.nlark.com/is-accessor-descriptor/download/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.nlark.com/is-data-descriptor/download/is-data-descriptor-1.0.0.tgz", + "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/is-descriptor/download/is-descriptor-1.0.2.tgz", + "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.nlark.com/snapdragon-util/download/snapdragon-util-3.0.1.tgz", + "integrity": "sha1-+VZHlIbyrNeXAGk/b3uAXkWrVuI=", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.nlark.com/kind-of/download/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "sockjs": { + "version": "0.3.21", + "resolved": "https://registry.nlark.com/sockjs/download/sockjs-0.3.21.tgz", + "integrity": "sha1-s0/7mOeWkwtgoM+hGQTWozmn1Bc=", + "dev": true, + "requires": { + "faye-websocket": "^0.11.3", + "uuid": "^3.4.0", + "websocket-driver": "^0.7.4" + } + }, + "sockjs-client": { + "version": "1.5.1", + "resolved": "https://registry.npm.taobao.org/sockjs-client/download/sockjs-client-1.5.1.tgz?cache=0&sync_timestamp=1616686717128&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsockjs-client%2Fdownload%2Fsockjs-client-1.5.1.tgz", + "integrity": "sha1-JWkI9tWt+5Tau9vQLGY2LMoPnqY=", + "dev": true, + "requires": { + "debug": "^3.2.6", + "eventsource": "^1.0.7", + "faye-websocket": "^0.11.3", + "inherits": "^2.0.4", + "json3": "^3.3.3", + "url-parse": "^1.5.1" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.nlark.com/debug/download/debug-3.2.7.tgz?cache=0&sync_timestamp=1618847042350&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdebug%2Fdownload%2Fdebug-3.2.7.tgz", + "integrity": "sha1-clgLfpFF+zm2Z2+cXl+xALk0F5o=", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.nlark.com/sort-keys/download/sort-keys-1.1.2.tgz", + "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", + "dev": true, + "requires": { + "is-plain-obj": "^1.0.0" + }, + "dependencies": { + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npm.taobao.org/is-plain-obj/download/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + } + } + }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.nlark.com/source-list-map/download/source-list-map-2.0.1.tgz", + "integrity": "sha1-OZO9hzv8SEecyp6jpUeDXHwVSzQ=", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-js": { + "version": "0.6.2", + "resolved": "https://registry.npm.taobao.org/source-map-js/download/source-map-js-0.6.2.tgz", + "integrity": "sha1-C7XeYxtBz72mz7qL0FqA79/SOF4=", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npm.taobao.org/source-map-resolve/download/source-map-resolve-0.5.3.tgz", + "integrity": "sha1-GQhmvs51U+H48mei7oLGBrVQmho=", + "dev": true, + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.nlark.com/source-map-support/download/source-map-support-0.5.19.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fsource-map-support%2Fdownload%2Fsource-map-support-0.5.19.tgz", + "integrity": "sha1-qYti+G3K9PZzmWSMCFKRq56P7WE=", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "dev": true + } + } + }, + "source-map-url": { + "version": "0.4.1", + "resolved": "https://registry.nlark.com/source-map-url/download/source-map-url-0.4.1.tgz", + "integrity": "sha1-CvZmBadFpaL5HPG7+KevvCg97FY=", + "dev": true + }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npm.taobao.org/sourcemap-codec/download/sourcemap-codec-1.4.8.tgz", + "integrity": "sha1-6oBL2UhXQC5pktBaOO8a41qatMQ=", + "dev": true + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npm.taobao.org/spdx-correct/download/spdx-correct-3.1.1.tgz", + "integrity": "sha1-3s6BrJweZxPl99G28X1Gj6U9iak=", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.nlark.com/spdx-exceptions/download/spdx-exceptions-2.3.0.tgz", + "integrity": "sha1-PyjOGnegA3JoPq3kpDMYNSeiFj0=", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npm.taobao.org/spdx-expression-parse/download/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha1-z3D1BILu/cmOPOCmgz5KU87rpnk=", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.9", + "resolved": "https://registry.nlark.com/spdx-license-ids/download/spdx-license-ids-3.0.9.tgz?cache=0&sync_timestamp=1621652583280&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fspdx-license-ids%2Fdownload%2Fspdx-license-ids-3.0.9.tgz", + "integrity": "sha1-illRNd75WSvaaXCUdPHL7qfCRn8=", + "dev": true + }, + "spdy": { + "version": "4.0.2", + "resolved": "https://registry.npm.taobao.org/spdy/download/spdy-4.0.2.tgz", + "integrity": "sha1-t09GYgOj7aRSwCSSuR+56EonZ3s=", + "dev": true, + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + } + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/spdy-transport/download/spdy-transport-3.0.0.tgz", + "integrity": "sha1-ANSGOmQArXXfkzYaFghgXl3NzzE=", + "dev": true, + "requires": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.nlark.com/readable-stream/download/readable-stream-3.6.0.tgz", + "integrity": "sha1-M3u9o63AcGvT4CRCaihtS0sskZg=", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npm.taobao.org/split-string/download/split-string-3.1.0.tgz", + "integrity": "sha1-fLCd2jqGWFcFxks5pkZgOGguj+I=", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.nlark.com/sprintf-js/download/sprintf-js-1.0.3.tgz?cache=0&sync_timestamp=1618847174560&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fsprintf-js%2Fdownload%2Fsprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npm.taobao.org/sshpk/download/sshpk-1.16.1.tgz", + "integrity": "sha1-+2YcC+8ps520B2nuOfpwCT1vaHc=", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "ssri": { + "version": "6.0.2", + "resolved": "https://registry.nlark.com/ssri/download/ssri-6.0.2.tgz?cache=0&sync_timestamp=1621364626710&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fssri%2Fdownload%2Fssri-6.0.2.tgz", + "integrity": "sha1-FXk5E08gRk5zAd26PpD/qPdyisU=", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "stable": { + "version": "0.1.8", + "resolved": "https://registry.npm.taobao.org/stable/download/stable-0.1.8.tgz", + "integrity": "sha1-g26zyDgv4pNv6vVEYxAXzn1Ho88=", + "dev": true + }, + "stackframe": { + "version": "1.2.0", + "resolved": "https://registry.npm.taobao.org/stackframe/download/stackframe-1.2.0.tgz", + "integrity": "sha1-UkKUktY8YuuYmATBFVLj0i53kwM=", + "dev": true + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npm.taobao.org/static-extend/download/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npm.taobao.org/statuses/download/statuses-1.5.0.tgz?cache=0&sync_timestamp=1609654014762&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstatuses%2Fdownload%2Fstatuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true + }, + "stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npm.taobao.org/stream-browserify/download/stream-browserify-2.0.2.tgz", + "integrity": "sha1-h1IdOKRKp+6RzhzSpH3wy0ndZgs=", + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "stream-each": { + "version": "1.2.3", + "resolved": "https://registry.npm.taobao.org/stream-each/download/stream-each-1.2.3.tgz", + "integrity": "sha1-6+J6DDibBPvMIzZClS4Qcxr6m64=", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npm.taobao.org/stream-http/download/stream-http-2.8.3.tgz?cache=0&sync_timestamp=1618430946341&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstream-http%2Fdownload%2Fstream-http-2.8.3.tgz", + "integrity": "sha1-stJCRpKIpaJ+xP6JM6z2I95lFPw=", + "dev": true, + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npm.taobao.org/stream-shift/download/stream-shift-1.0.1.tgz", + "integrity": "sha1-1wiCgVWasneEJCebCHfaPDktWj0=", + "dev": true + }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npm.taobao.org/strict-uri-encode/download/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", + "dev": true + }, + "string-hash": { + "version": "1.1.3", + "resolved": "https://registry.npm.taobao.org/string-hash/download/string-hash-1.1.3.tgz", + "integrity": "sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs=", + "dev": true + }, + "string-width": { + "version": "4.2.2", + "resolved": "https://registry.nlark.com/string-width/download/string-width-4.2.2.tgz", + "integrity": "sha1-2v1PlVmnWFz7pSnGoKT3NIjr1MU=", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npm.taobao.org/string.prototype.trimend/download/string.prototype.trimend-1.0.4.tgz?cache=0&sync_timestamp=1614127461586&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstring.prototype.trimend%2Fdownload%2Fstring.prototype.trimend-1.0.4.tgz", + "integrity": "sha1-51rpDClCxjUEaGwYsoe0oLGkX4A=", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npm.taobao.org/string.prototype.trimstart/download/string.prototype.trimstart-1.0.4.tgz?cache=0&sync_timestamp=1614127357785&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstring.prototype.trimstart%2Fdownload%2Fstring.prototype.trimstart-1.0.4.tgz", + "integrity": "sha1-s2OZr0qymZtMnGSL16P7K7Jv7u0=", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npm.taobao.org/string_decoder/download/string_decoder-1.1.1.tgz", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-6.0.0.tgz?cache=0&sync_timestamp=1618553320591&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-6.0.0.tgz", + "integrity": "sha1-CxVx3XZpzNTz4G4U7x7tJiJa5TI=", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.nlark.com/ansi-regex/download/ansi-regex-5.0.0.tgz", + "integrity": "sha1-OIU59VF5vzkznIGvMKZU1p+Hy3U=", + "dev": true + } + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.nlark.com/strip-eof/download/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.nlark.com/strip-final-newline/download/strip-final-newline-2.0.0.tgz", + "integrity": "sha1-ibhS+y/L6Tb29LMYevsKEsGrWK0=", + "dev": true + }, + "strip-indent": { + "version": "2.0.0", + "resolved": "https://registry.nlark.com/strip-indent/download/strip-indent-2.0.0.tgz?cache=0&sync_timestamp=1620053310624&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fstrip-indent%2Fdownload%2Fstrip-indent-2.0.0.tgz", + "integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npm.taobao.org/strip-json-comments/download/strip-json-comments-3.1.1.tgz", + "integrity": "sha1-MfEoGzgyYwQ0gxwxDAHMzajL4AY=", + "dev": true + }, + "stylehacks": { + "version": "4.0.3", + "resolved": "https://registry.nlark.com/stylehacks/download/stylehacks-4.0.3.tgz?cache=0&sync_timestamp=1621449652268&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fstylehacks%2Fdownload%2Fstylehacks-4.0.3.tgz", + "integrity": "sha1-Zxj8r00eB9ihMYaQiB6NlnJqcdU=", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.nlark.com/postcss-selector-parser/download/postcss-selector-parser-3.1.2.tgz?cache=0&sync_timestamp=1620752939806&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-selector-parser%2Fdownload%2Fpostcss-selector-parser-3.1.2.tgz", + "integrity": "sha1-sxD1xMD9r3b5SQK7qjDbaqhPUnA=", + "dev": true, + "requires": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "stylus": { + "version": "0.54.8", + "resolved": "https://registry.nlark.com/stylus/download/stylus-0.54.8.tgz", + "integrity": "sha1-PaPmWWa8Vnp7BEv+DuzmU+CZ0Uc=", + "dev": true, + "requires": { + "css-parse": "~2.0.0", + "debug": "~3.1.0", + "glob": "^7.1.6", + "mkdirp": "~1.0.4", + "safer-buffer": "^2.1.2", + "sax": "~1.2.4", + "semver": "^6.3.0", + "source-map": "^0.7.3" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.nlark.com/debug/download/debug-3.1.0.tgz?cache=0&sync_timestamp=1618847042350&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdebug%2Fdownload%2Fdebug-3.1.0.tgz", + "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npm.taobao.org/mkdirp/download/mkdirp-1.0.4.tgz", + "integrity": "sha1-PrXtYmInVteaXw4qIh3+utdcL34=", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz?cache=0&sync_timestamp=1607433950466&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.7.3.tgz", + "integrity": "sha1-UwL4FpAxc1ImVECS5kmB91F1A4M=", + "dev": true + } + } + }, + "stylus-loader": { + "version": "3.0.2", + "resolved": "https://registry.nlark.com/stylus-loader/download/stylus-loader-3.0.2.tgz", + "integrity": "sha1-J6cGQgsFo44DjnyssVNXjUUFE8Y=", + "dev": true, + "requires": { + "loader-utils": "^1.0.2", + "lodash.clonedeep": "^4.5.0", + "when": "~3.6.x" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.nlark.com/supports-color/download/supports-color-5.5.0.tgz?cache=0&sync_timestamp=1622293670728&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fsupports-color%2Fdownload%2Fsupports-color-5.5.0.tgz", + "integrity": "sha1-4uaaRKyHcveKHsCzW2id9lMO/I8=", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "svg-tags": { + "version": "1.0.0", + "resolved": "https://registry.nlark.com/svg-tags/download/svg-tags-1.0.0.tgz", + "integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=", + "dev": true + }, + "svgo": { + "version": "1.3.2", + "resolved": "https://registry.nlark.com/svgo/download/svgo-1.3.2.tgz", + "integrity": "sha1-ttxRHAYzRsnkFbgeQ0ARRbltQWc=", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "coa": "^2.0.2", + "css-select": "^2.0.0", + "css-select-base-adapter": "^0.1.1", + "css-tree": "1.0.0-alpha.37", + "csso": "^4.0.2", + "js-yaml": "^3.13.1", + "mkdirp": "~0.5.1", + "object.values": "^1.1.0", + "sax": "~1.2.4", + "stable": "^0.1.8", + "unquote": "~1.1.1", + "util.promisify": "~1.0.0" + } + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.nlark.com/table/download/table-5.4.6.tgz", + "integrity": "sha1-EpLRlQDOP4YFOwXw6Ofko7shB54=", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.nlark.com/emoji-regex/download/emoji-regex-7.0.3.tgz", + "integrity": "sha1-kzoEBShgyF6DwSJHnEdIqOTHIVY=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-2.0.0.tgz?cache=0&sync_timestamp=1618552489864&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-fullwidth-code-point%2Fdownload%2Fis-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.nlark.com/string-width/download/string-width-3.1.0.tgz", + "integrity": "sha1-InZ74htirxCBV0MG9prFG2IgOWE=", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-5.2.0.tgz?cache=0&sync_timestamp=1618553320591&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-5.2.0.tgz", + "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npm.taobao.org/tapable/download/tapable-1.1.3.tgz", + "integrity": "sha1-ofzMBrWNth/XpF2i2kT186Pme6I=", + "dev": true + }, + "terser": { + "version": "4.8.0", + "resolved": "https://registry.nlark.com/terser/download/terser-4.8.0.tgz", + "integrity": "sha1-YwVjQ9fHC7KfOvZlhlpG/gOg3xc=", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "dev": true + } + } + }, + "terser-webpack-plugin": { + "version": "1.4.5", + "resolved": "https://registry.nlark.com/terser-webpack-plugin/download/terser-webpack-plugin-1.4.5.tgz?cache=0&sync_timestamp=1620830646135&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fterser-webpack-plugin%2Fdownload%2Fterser-webpack-plugin-1.4.5.tgz", + "integrity": "sha1-oheu+uozDnNP+sthIOwfoxLWBAs=", + "dev": true, + "requires": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + }, + "dependencies": { + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npm.taobao.org/find-cache-dir/download/find-cache-dir-2.1.0.tgz", + "integrity": "sha1-jQ+UzRP+Q8bHwmGg2GEVypGMBfc=", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.nlark.com/find-up/download/find-up-3.0.0.tgz?cache=0&sync_timestamp=1618846778775&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ffind-up%2Fdownload%2Ffind-up-3.0.0.tgz", + "integrity": "sha1-SRafHXmTQwZG2mHsxa41XCHJe3M=", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/locate-path/download/locate-path-3.0.0.tgz", + "integrity": "sha1-2+w7OrdZdYBxtY/ln8QYca8hQA4=", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npm.taobao.org/make-dir/download/make-dir-2.1.0.tgz", + "integrity": "sha1-XwMQ4YuL6JjMBwCSlaMK5B6R5vU=", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.nlark.com/p-locate/download/p-locate-3.0.0.tgz", + "integrity": "sha1-Mi1poFwCZLJZl9n0DNiokasAZKQ=", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.nlark.com/path-exists/download/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/pkg-dir/download/pkg-dir-3.0.0.tgz?cache=0&sync_timestamp=1602859045787&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpkg-dir%2Fdownload%2Fpkg-dir-3.0.0.tgz", + "integrity": "sha1-J0kCDyOe2ZCIGx9xIQ1R62UjvqM=", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-1.0.0.tgz", + "integrity": "sha1-C3mpMgTXtgDUsoUNH2bCo0lRx3A=", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.nlark.com/semver/download/semver-5.7.1.tgz?cache=0&sync_timestamp=1618847119601&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fsemver%2Fdownload%2Fsemver-5.7.1.tgz", + "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "dev": true + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.nlark.com/text-table/download/text-table-0.2.0.tgz?cache=0&sync_timestamp=1618847142316&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ftext-table%2Fdownload%2Ftext-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "thenify": { + "version": "3.3.1", + "resolved": "https://registry.nlark.com/thenify/download/thenify-3.3.1.tgz", + "integrity": "sha1-iTLmhqQGYDigFt2eLKRq3Zg4qV8=", + "dev": true, + "requires": { + "any-promise": "^1.0.0" + } + }, + "thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.nlark.com/thenify-all/download/thenify-all-1.6.0.tgz", + "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", + "dev": true, + "requires": { + "thenify": ">= 3.1.0 < 4" + } + }, + "thread-loader": { + "version": "2.1.3", + "resolved": "https://registry.nlark.com/thread-loader/download/thread-loader-2.1.3.tgz", + "integrity": "sha1-y9LBOfwrLebp0o9iKGq3cMGsvdo=", + "dev": true, + "requires": { + "loader-runner": "^2.3.1", + "loader-utils": "^1.1.0", + "neo-async": "^2.6.0" + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.nlark.com/through/download/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npm.taobao.org/through2/download/through2-2.0.5.tgz", + "integrity": "sha1-AcHjnrMdB8t9A6lqcIIyYLIxMs0=", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "thunky": { + "version": "1.1.0", + "resolved": "https://registry.nlark.com/thunky/download/thunky-1.1.0.tgz", + "integrity": "sha1-Wrr3FKlAXbBQRzK7zNLO3Z75U30=", + "dev": true + }, + "timers-browserify": { + "version": "2.0.12", + "resolved": "https://registry.nlark.com/timers-browserify/download/timers-browserify-2.0.12.tgz", + "integrity": "sha1-RKRcEfv0B/NPl7zNFXfGUjYbAO4=", + "dev": true, + "requires": { + "setimmediate": "^1.0.4" + } + }, + "timsort": { + "version": "0.3.0", + "resolved": "https://registry.nlark.com/timsort/download/timsort-0.3.0.tgz", + "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", + "dev": true + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npm.taobao.org/tmp/download/tmp-0.0.33.tgz", + "integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npm.taobao.org/to-arraybuffer/download/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.nlark.com/to-fast-properties/download/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.nlark.com/to-object-path/download/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.nlark.com/kind-of/download/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.nlark.com/to-regex/download/to-regex-3.0.2.tgz", + "integrity": "sha1-E8/dmzNlUvMLUfM6iuG0Knp1mc4=", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.nlark.com/to-regex-range/download/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/toidentifier/download/toidentifier-1.0.0.tgz", + "integrity": "sha1-fhvjRw8ed5SLxD2Uo8j013UrpVM=", + "dev": true + }, + "toposort": { + "version": "1.0.7", + "resolved": "https://registry.npm.taobao.org/toposort/download/toposort-1.0.7.tgz", + "integrity": "sha1-LmhELZ9k7HILjMieZEOsbKqVACk=", + "dev": true + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npm.taobao.org/tough-cookie/download/tough-cookie-2.5.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ftough-cookie%2Fdownload%2Ftough-cookie-2.5.0.tgz", + "integrity": "sha1-zZ+yoKodWhK0c72fuW+j3P9lreI=", + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tryer": { + "version": "1.0.1", + "resolved": "https://registry.nlark.com/tryer/download/tryer-1.0.1.tgz", + "integrity": "sha1-8shUBoALmw90yfdGW4HqrSQSUvg=", + "dev": true + }, + "ts-pnp": { + "version": "1.2.0", + "resolved": "https://registry.npm.taobao.org/ts-pnp/download/ts-pnp-1.2.0.tgz", + "integrity": "sha1-pQCtCEsHmPHDBxrzkeZZEshrypI=", + "dev": true + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.nlark.com/tslib/download/tslib-1.14.1.tgz?cache=0&sync_timestamp=1618846758811&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ftslib%2Fdownload%2Ftslib-1.14.1.tgz", + "integrity": "sha1-zy04vcNKE0vK8QkcQfZhni9nLQA=", + "dev": true + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npm.taobao.org/tty-browserify/download/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.nlark.com/tunnel-agent/download/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npm.taobao.org/tweetnacl/download/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.nlark.com/type-check/download/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.nlark.com/type-fest/download/type-fest-0.6.0.tgz?cache=0&sync_timestamp=1621402446336&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ftype-fest%2Fdownload%2Ftype-fest-0.6.0.tgz", + "integrity": "sha1-jSojcNPfiG61yQraHFv2GIrPg4s=", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.nlark.com/type-is/download/type-is-1.6.18.tgz", + "integrity": "sha1-TlUs0F3wlGfcvE73Od6J8s83wTE=", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npm.taobao.org/typedarray/download/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "uglify-js": { + "version": "3.4.10", + "resolved": "https://registry.nlark.com/uglify-js/download/uglify-js-3.4.10.tgz?cache=0&sync_timestamp=1622033899313&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fuglify-js%2Fdownload%2Fuglify-js-3.4.10.tgz", + "integrity": "sha1-mtlWPY6zrN+404WX0q8dgV9qdV8=", + "dev": true, + "requires": { + "commander": "~2.19.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "commander": { + "version": "2.19.0", + "resolved": "https://registry.nlark.com/commander/download/commander-2.19.0.tgz?cache=0&sync_timestamp=1622446257852&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fcommander%2Fdownload%2Fcommander-2.19.0.tgz", + "integrity": "sha1-9hmKqE5bg8RgVLlN3tv+1e6f8So=", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "dev": true + } + } + }, + "unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.nlark.com/unbox-primitive/download/unbox-primitive-1.0.1.tgz", + "integrity": "sha1-CF4hViXsMWJXTciFmr7nilmxRHE=", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + } + }, + "unicode-canonical-property-names-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.nlark.com/unicode-canonical-property-names-ecmascript/download/unicode-canonical-property-names-ecmascript-1.0.4.tgz", + "integrity": "sha1-JhmADEyCWADv3YNDr33Zkzy+KBg=", + "dev": true + }, + "unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npm.taobao.org/unicode-match-property-ecmascript/download/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha1-jtKjJWmWG86SJ9Cc0/+7j+1fAgw=", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "1.2.0", + "resolved": "https://registry.npm.taobao.org/unicode-match-property-value-ecmascript/download/unicode-match-property-value-ecmascript-1.2.0.tgz", + "integrity": "sha1-DZH2AO7rMJaqlisdb8iIduZOpTE=", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "1.1.0", + "resolved": "https://registry.npm.taobao.org/unicode-property-aliases-ecmascript/download/unicode-property-aliases-ecmascript-1.1.0.tgz", + "integrity": "sha1-3Vepn2IHvt/0Yoq++5TFDblByPQ=", + "dev": true + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.nlark.com/union-value/download/union-value-1.0.1.tgz", + "integrity": "sha1-C2/nuDWuzaYcbqTU8CwUIh4QmEc=", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "uniq": { + "version": "1.0.1", + "resolved": "https://registry.nlark.com/uniq/download/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", + "dev": true + }, + "uniqs": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/uniqs/download/uniqs-2.0.0.tgz", + "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=", + "dev": true + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npm.taobao.org/unique-filename/download/unique-filename-1.1.1.tgz", + "integrity": "sha1-HWl2k2mtoFgxA6HmrodoG1ZXMjA=", + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.nlark.com/unique-slug/download/unique-slug-2.0.2.tgz", + "integrity": "sha1-uqvOkQg/xk6UWw861hPiZPfNTmw=", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npm.taobao.org/universalify/download/universalify-0.1.2.tgz?cache=0&sync_timestamp=1603180037346&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Funiversalify%2Fdownload%2Funiversalify-0.1.2.tgz", + "integrity": "sha1-tkb2m+OULavOzJ1mOcgNwQXvqmY=", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/unpipe/download/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "unquote": { + "version": "1.1.1", + "resolved": "https://registry.nlark.com/unquote/download/unquote-1.1.1.tgz", + "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", + "dev": true + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/unset-value/download/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npm.taobao.org/has-value/download/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npm.taobao.org/isobject/download/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npm.taobao.org/has-values/download/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + } + } + }, + "upath": { + "version": "1.2.0", + "resolved": "https://registry.npm.taobao.org/upath/download/upath-1.2.0.tgz", + "integrity": "sha1-j2bbzVWog6za5ECK+LA1pQRMGJQ=", + "dev": true + }, + "upper-case": { + "version": "1.1.3", + "resolved": "https://registry.nlark.com/upper-case/download/upper-case-1.1.3.tgz", + "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=", + "dev": true + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npm.taobao.org/uri-js/download/uri-js-4.4.1.tgz?cache=0&sync_timestamp=1610237742114&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Furi-js%2Fdownload%2Furi-js-4.4.1.tgz", + "integrity": "sha1-mxpSWVIlhZ5V9mnZKPiMbFfyp34=", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.nlark.com/urix/download/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.nlark.com/url/download/url-0.11.0.tgz?cache=0&sync_timestamp=1618847135337&other_urls=https%3A%2F%2Fregistry.nlark.com%2Furl%2Fdownload%2Furl-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.nlark.com/punycode/download/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + } + } + }, + "url-loader": { + "version": "2.3.0", + "resolved": "https://registry.nlark.com/url-loader/download/url-loader-2.3.0.tgz", + "integrity": "sha1-4OLvZY8APvuMpBsPP/v3a6uIZYs=", + "dev": true, + "requires": { + "loader-utils": "^1.2.3", + "mime": "^2.4.4", + "schema-utils": "^2.5.0" + } + }, + "url-parse": { + "version": "1.5.1", + "resolved": "https://registry.npm.taobao.org/url-parse/download/url-parse-1.5.1.tgz?cache=0&sync_timestamp=1613659652440&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Furl-parse%2Fdownload%2Furl-parse-1.5.1.tgz", + "integrity": "sha1-1fqYkK+KXh8nSiyYN2UQ9kJfbjs=", + "dev": true, + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.nlark.com/use/download/use-3.1.1.tgz", + "integrity": "sha1-1QyMrHmhn7wg8pEfVuuXP04QBw8=", + "dev": true + }, + "util": { + "version": "0.11.1", + "resolved": "https://registry.nlark.com/util/download/util-0.11.1.tgz?cache=0&sync_timestamp=1622213047493&other_urls=https%3A%2F%2Fregistry.nlark.com%2Futil%2Fdownload%2Futil-0.11.1.tgz", + "integrity": "sha1-MjZzNyDsZLsn9uJvQhqqLhtYjWE=", + "dev": true, + "requires": { + "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.nlark.com/inherits/download/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.nlark.com/util-deprecate/download/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "util.promisify": { + "version": "1.0.1", + "resolved": "https://registry.npm.taobao.org/util.promisify/download/util.promisify-1.0.1.tgz?cache=0&sync_timestamp=1610159895694&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Futil.promisify%2Fdownload%2Futil.promisify-1.0.1.tgz", + "integrity": "sha1-a693dLgO6w91INi4HQeYKlmruu4=", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.2", + "has-symbols": "^1.0.1", + "object.getownpropertydescriptors": "^2.1.0" + } + }, + "utila": { + "version": "0.4.0", + "resolved": "https://registry.nlark.com/utila/download/utila-0.4.0.tgz", + "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", + "dev": true + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.nlark.com/utils-merge/download/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.nlark.com/uuid/download/uuid-3.4.0.tgz?cache=0&sync_timestamp=1622213185460&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fuuid%2Fdownload%2Fuuid-3.4.0.tgz", + "integrity": "sha1-sj5DWK+oogL+ehAK8fX4g/AgB+4=", + "dev": true + }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.nlark.com/v8-compile-cache/download/v8-compile-cache-2.3.0.tgz", + "integrity": "sha1-LeGWGMZtwkfc+2+ZM4A12CRaLO4=", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.nlark.com/validate-npm-package-license/download/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha1-/JH2uce6FchX9MssXe/uw51PQQo=", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.nlark.com/vary/download/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true + }, + "vendors": { + "version": "1.0.4", + "resolved": "https://registry.nlark.com/vendors/download/vendors-1.0.4.tgz", + "integrity": "sha1-4rgApT56Kbk1BsPPQRANFsTErY4=", + "dev": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npm.taobao.org/verror/download/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.nlark.com/vm-browserify/download/vm-browserify-1.1.2.tgz", + "integrity": "sha1-eGQcSIuObKkadfUR56OzKobl3aA=", + "dev": true + }, + "vue": { + "version": "3.0.11", + "resolved": "https://registry.nlark.com/vue/download/vue-3.0.11.tgz?cache=0&sync_timestamp=1622239280610&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fvue%2Fdownload%2Fvue-3.0.11.tgz", + "integrity": "sha1-yC+VlMv03MhpJB1MjdPgjZqPS18=", + "requires": { + "@vue/compiler-dom": "3.0.11", + "@vue/runtime-dom": "3.0.11", + "@vue/shared": "3.0.11" + } + }, + "vue-eslint-parser": { + "version": "7.6.0", + "resolved": "https://registry.nlark.com/vue-eslint-parser/download/vue-eslint-parser-7.6.0.tgz", + "integrity": "sha1-AeoaKTL1gf8kQzZWXXEoAfj3JWE=", + "dev": true, + "requires": { + "debug": "^4.1.1", + "eslint-scope": "^5.0.0", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.2.1", + "esquery": "^1.4.0", + "lodash": "^4.17.15" + }, + "dependencies": { + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npm.taobao.org/eslint-scope/download/eslint-scope-5.1.1.tgz?cache=0&sync_timestamp=1599933693172&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Feslint-scope%2Fdownload%2Feslint-scope-5.1.1.tgz", + "integrity": "sha1-54blmmbLkrP2wfsNUIqrF0hI9Iw=", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + } + } + }, + "vue-hot-reload-api": { + "version": "2.3.4", + "resolved": "https://registry.npm.taobao.org/vue-hot-reload-api/download/vue-hot-reload-api-2.3.4.tgz", + "integrity": "sha1-UylVzB6yCKPZkLOp+acFdGV+CPI=", + "dev": true + }, + "vue-loader": { + "version": "15.9.7", + "resolved": "https://registry.nlark.com/vue-loader/download/vue-loader-15.9.7.tgz", + "integrity": "sha1-FbBXdcPgw4QHZ5OTws5t9nOwEEQ=", + "dev": true, + "requires": { + "@vue/component-compiler-utils": "^3.1.0", + "hash-sum": "^1.0.2", + "loader-utils": "^1.1.0", + "vue-hot-reload-api": "^2.3.0", + "vue-style-loader": "^4.1.0" + }, + "dependencies": { + "hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/hash-sum/download/hash-sum-1.0.2.tgz", + "integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=", + "dev": true + } + } + }, + "vue-loader-v16": { + "version": "npm:vue-loader@16.2.0", + "resolved": "https://registry.nlark.com/vue-loader/download/vue-loader-16.2.0.tgz", + "integrity": "sha1-BGpTMI3Ufljv4g3ewe3sAnzjtG4=", + "dev": true, + "optional": true, + "requires": { + "chalk": "^4.1.0", + "hash-sum": "^2.0.0", + "loader-utils": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.nlark.com/ansi-styles/download/ansi-styles-4.3.0.tgz", + "integrity": "sha1-7dgDYornHATIWuegkG7a00tkiTc=", + "dev": true, + "optional": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.nlark.com/chalk/download/chalk-4.1.1.tgz?cache=0&sync_timestamp=1618995367379&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fchalk%2Fdownload%2Fchalk-4.1.1.tgz", + "integrity": "sha1-yAs/qyi/Y3HmhjMl7uZ+YYt35q0=", + "dev": true, + "optional": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz", + "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=", + "dev": true, + "optional": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.nlark.com/color-name/download/color-name-1.1.4.tgz", + "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=", + "dev": true, + "optional": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npm.taobao.org/has-flag/download/has-flag-4.0.0.tgz?cache=0&sync_timestamp=1618559676170&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhas-flag%2Fdownload%2Fhas-flag-4.0.0.tgz", + "integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s=", + "dev": true, + "optional": true + }, + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.nlark.com/loader-utils/download/loader-utils-2.0.0.tgz?cache=0&sync_timestamp=1618846812625&other_urls=https%3A%2F%2Fregistry.nlark.com%2Floader-utils%2Fdownload%2Floader-utils-2.0.0.tgz", + "integrity": "sha1-5MrOW4FtQloWa18JfhDNErNgZLA=", + "dev": true, + "optional": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.nlark.com/supports-color/download/supports-color-7.2.0.tgz?cache=0&sync_timestamp=1622293670728&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fsupports-color%2Fdownload%2Fsupports-color-7.2.0.tgz", + "integrity": "sha1-G33NyzK4E4gBs+R4umpRyqiWSNo=", + "dev": true, + "optional": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "vue-router": { + "version": "4.0.8", + "resolved": "https://registry.nlark.com/vue-router/download/vue-router-4.0.8.tgz?cache=0&sync_timestamp=1620899536020&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fvue-router%2Fdownload%2Fvue-router-4.0.8.tgz", + "integrity": "sha1-VdQpCjEiRE7byRo80kkrsdDO9JQ=", + "requires": { + "@vue/devtools-api": "^6.0.0-beta.10" + } + }, + "vue-style-loader": { + "version": "4.1.3", + "resolved": "https://registry.nlark.com/vue-style-loader/download/vue-style-loader-4.1.3.tgz", + "integrity": "sha1-bVWGOlH6dXqyTonZNxRlByqnvDU=", + "dev": true, + "requires": { + "hash-sum": "^1.0.2", + "loader-utils": "^1.0.2" + }, + "dependencies": { + "hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/hash-sum/download/hash-sum-1.0.2.tgz", + "integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=", + "dev": true + } + } + }, + "vue-template-es2015-compiler": { + "version": "1.9.1", + "resolved": "https://registry.npm.taobao.org/vue-template-es2015-compiler/download/vue-template-es2015-compiler-1.9.1.tgz", + "integrity": "sha1-HuO8mhbsv1EYvjNLsV+cRvgvWCU=", + "dev": true + }, + "vuex": { + "version": "4.0.1", + "resolved": "https://registry.nlark.com/vuex/download/vuex-4.0.1.tgz", + "integrity": "sha1-6DxUHW8xFzlp76uyxdHEZbaCiH4=", + "requires": { + "@vue/devtools-api": "^6.0.0-beta.11" + } + }, + "watchpack": { + "version": "1.7.5", + "resolved": "https://registry.nlark.com/watchpack/download/watchpack-1.7.5.tgz?cache=0&sync_timestamp=1621437868630&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fwatchpack%2Fdownload%2Fwatchpack-1.7.5.tgz", + "integrity": "sha1-EmfmxV4Lm1vkTCAjrtVDeiwmxFM=", + "dev": true, + "requires": { + "chokidar": "^3.4.1", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0", + "watchpack-chokidar2": "^2.0.1" + } + }, + "watchpack-chokidar2": { + "version": "2.0.1", + "resolved": "https://registry.nlark.com/watchpack-chokidar2/download/watchpack-chokidar2-2.0.1.tgz", + "integrity": "sha1-OFAAcu5uzmbzdpk2lQ6hdxvhyVc=", + "dev": true, + "optional": true, + "requires": { + "chokidar": "^2.1.8" + }, + "dependencies": { + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.nlark.com/anymatch/download/anymatch-2.0.0.tgz", + "integrity": "sha1-vLJLTzeTTZqnrBe0ra+J58du8us=", + "dev": true, + "optional": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npm.taobao.org/normalize-path/download/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "optional": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.nlark.com/binary-extensions/download/binary-extensions-1.13.1.tgz", + "integrity": "sha1-WYr+VHVbKGilMw0q/51Ou1Mgm2U=", + "dev": true, + "optional": true + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.nlark.com/chokidar/download/chokidar-2.1.8.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fchokidar%2Fdownload%2Fchokidar-2.1.8.tgz", + "integrity": "sha1-gEs6e2qZNYw8XGHnHYco8EHP+Rc=", + "dev": true, + "optional": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npm.taobao.org/fsevents/download/fsevents-1.2.13.tgz", + "integrity": "sha1-8yXLBFVZJCi88Rs4M3DvcOO/zDg=", + "dev": true, + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.nlark.com/glob-parent/download/glob-parent-3.1.0.tgz?cache=0&sync_timestamp=1620073321855&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fglob-parent%2Fdownload%2Fglob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "optional": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npm.taobao.org/is-glob/download/is-glob-3.1.0.tgz?cache=0&sync_timestamp=1598237815612&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-glob%2Fdownload%2Fis-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "optional": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.nlark.com/is-binary-path/download/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "optional": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.nlark.com/readdirp/download/readdirp-2.2.1.tgz", + "integrity": "sha1-DodiKjMlqjPokihcr4tOhGUppSU=", + "dev": true, + "optional": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + } + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npm.taobao.org/wbuf/download/wbuf-1.7.3.tgz", + "integrity": "sha1-wdjRSTFtPqhShIiVy2oL/oh7h98=", + "dev": true, + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.nlark.com/wcwidth/download/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "dev": true, + "requires": { + "defaults": "^1.0.3" + } + }, + "webpack": { + "version": "4.46.0", + "resolved": "https://registry.nlark.com/webpack/download/webpack-4.46.0.tgz?cache=0&sync_timestamp=1622151377755&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fwebpack%2Fdownload%2Fwebpack-4.46.0.tgz", + "integrity": "sha1-v5tEBOogoHNgXgoBHRiNd8tq1UI=", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/wasm-edit": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "acorn": "^6.4.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^4.5.0", + "eslint-scope": "^4.0.3", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.3", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", + "schema-utils": "^1.0.0", + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.3", + "watchpack": "^1.7.4", + "webpack-sources": "^1.4.1" + }, + "dependencies": { + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-1.0.0.tgz", + "integrity": "sha1-C3mpMgTXtgDUsoUNH2bCo0lRx3A=", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "webpack-bundle-analyzer": { + "version": "3.9.0", + "resolved": "https://registry.nlark.com/webpack-bundle-analyzer/download/webpack-bundle-analyzer-3.9.0.tgz?cache=0&sync_timestamp=1621259099265&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fwebpack-bundle-analyzer%2Fdownload%2Fwebpack-bundle-analyzer-3.9.0.tgz", + "integrity": "sha1-9vlNsQj7V05BWtMT3kGicH0z7zw=", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1", + "bfj": "^6.1.1", + "chalk": "^2.4.1", + "commander": "^2.18.0", + "ejs": "^2.6.1", + "express": "^4.16.3", + "filesize": "^3.6.1", + "gzip-size": "^5.0.0", + "lodash": "^4.17.19", + "mkdirp": "^0.5.1", + "opener": "^1.5.1", + "ws": "^6.0.0" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.nlark.com/acorn/download/acorn-7.4.1.tgz", + "integrity": "sha1-/q7SVZc9LndVW4PbwIhRpsY1IPo=", + "dev": true + } + } + }, + "webpack-chain": { + "version": "6.5.1", + "resolved": "https://registry.npm.taobao.org/webpack-chain/download/webpack-chain-6.5.1.tgz", + "integrity": "sha1-TycoTLu2N+PI+970Pu9YjU2GEgY=", + "dev": true, + "requires": { + "deepmerge": "^1.5.2", + "javascript-stringify": "^2.0.1" + } + }, + "webpack-dev-middleware": { + "version": "3.7.3", + "resolved": "https://registry.nlark.com/webpack-dev-middleware/download/webpack-dev-middleware-3.7.3.tgz?cache=0&sync_timestamp=1621437646566&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fwebpack-dev-middleware%2Fdownload%2Fwebpack-dev-middleware-3.7.3.tgz", + "integrity": "sha1-Bjk3KxQyYuK4SrldO5GnWXBhwsU=", + "dev": true, + "requires": { + "memory-fs": "^0.4.1", + "mime": "^2.4.4", + "mkdirp": "^0.5.1", + "range-parser": "^1.2.1", + "webpack-log": "^2.0.0" + } + }, + "webpack-dev-server": { + "version": "3.11.2", + "resolved": "https://registry.nlark.com/webpack-dev-server/download/webpack-dev-server-3.11.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fwebpack-dev-server%2Fdownload%2Fwebpack-dev-server-3.11.2.tgz", + "integrity": "sha1-aV687Xakkp8NXef9c/r+GF/jNwg=", + "dev": true, + "requires": { + "ansi-html": "0.0.7", + "bonjour": "^3.5.0", + "chokidar": "^2.1.8", + "compression": "^1.7.4", + "connect-history-api-fallback": "^1.6.0", + "debug": "^4.1.1", + "del": "^4.1.1", + "express": "^4.17.1", + "html-entities": "^1.3.1", + "http-proxy-middleware": "0.19.1", + "import-local": "^2.0.0", + "internal-ip": "^4.3.0", + "ip": "^1.1.5", + "is-absolute-url": "^3.0.3", + "killable": "^1.0.1", + "loglevel": "^1.6.8", + "opn": "^5.5.0", + "p-retry": "^3.0.1", + "portfinder": "^1.0.26", + "schema-utils": "^1.0.0", + "selfsigned": "^1.10.8", + "semver": "^6.3.0", + "serve-index": "^1.9.1", + "sockjs": "^0.3.21", + "sockjs-client": "^1.5.0", + "spdy": "^4.0.2", + "strip-ansi": "^3.0.1", + "supports-color": "^6.1.0", + "url": "^0.11.0", + "webpack-dev-middleware": "^3.7.2", + "webpack-log": "^2.0.0", + "ws": "^6.2.1", + "yargs": "^13.3.2" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.nlark.com/ansi-regex/download/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.nlark.com/anymatch/download/anymatch-2.0.0.tgz", + "integrity": "sha1-vLJLTzeTTZqnrBe0ra+J58du8us=", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npm.taobao.org/normalize-path/download/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.nlark.com/binary-extensions/download/binary-extensions-1.13.1.tgz", + "integrity": "sha1-WYr+VHVbKGilMw0q/51Ou1Mgm2U=", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.nlark.com/camelcase/download/camelcase-5.3.1.tgz", + "integrity": "sha1-48mzFWnhBoEd8kL3FXJaH0xJQyA=", + "dev": true + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.nlark.com/chokidar/download/chokidar-2.1.8.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fchokidar%2Fdownload%2Fchokidar-2.1.8.tgz", + "integrity": "sha1-gEs6e2qZNYw8XGHnHYco8EHP+Rc=", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.nlark.com/cliui/download/cliui-5.0.0.tgz", + "integrity": "sha1-3u/P2y6AB4SqNPRvoI4GhRx7u8U=", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.nlark.com/ansi-regex/download/ansi-regex-4.1.0.tgz", + "integrity": "sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc=", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-5.2.0.tgz?cache=0&sync_timestamp=1618553320591&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-5.2.0.tgz", + "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.nlark.com/emoji-regex/download/emoji-regex-7.0.3.tgz", + "integrity": "sha1-kzoEBShgyF6DwSJHnEdIqOTHIVY=", + "dev": true + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.nlark.com/find-up/download/find-up-3.0.0.tgz?cache=0&sync_timestamp=1618846778775&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ffind-up%2Fdownload%2Ffind-up-3.0.0.tgz", + "integrity": "sha1-SRafHXmTQwZG2mHsxa41XCHJe3M=", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npm.taobao.org/fsevents/download/fsevents-1.2.13.tgz", + "integrity": "sha1-8yXLBFVZJCi88Rs4M3DvcOO/zDg=", + "dev": true, + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.nlark.com/glob-parent/download/glob-parent-3.1.0.tgz?cache=0&sync_timestamp=1620073321855&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fglob-parent%2Fdownload%2Fglob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npm.taobao.org/is-glob/download/is-glob-3.1.0.tgz?cache=0&sync_timestamp=1598237815612&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-glob%2Fdownload%2Fis-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "http-proxy-middleware": { + "version": "0.19.1", + "resolved": "https://registry.nlark.com/http-proxy-middleware/download/http-proxy-middleware-0.19.1.tgz?cache=0&sync_timestamp=1620409720336&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fhttp-proxy-middleware%2Fdownload%2Fhttp-proxy-middleware-0.19.1.tgz", + "integrity": "sha1-GDx9xKoUeRUDBkmMIQza+WCApDo=", + "dev": true, + "requires": { + "http-proxy": "^1.17.0", + "is-glob": "^4.0.0", + "lodash": "^4.17.11", + "micromatch": "^3.1.10" + } + }, + "is-absolute-url": { + "version": "3.0.3", + "resolved": "https://registry.nlark.com/is-absolute-url/download/is-absolute-url-3.0.3.tgz", + "integrity": "sha1-lsaiK2ojkpsR6gr7GDbDatSl1pg=", + "dev": true + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.nlark.com/is-binary-path/download/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-2.0.0.tgz?cache=0&sync_timestamp=1618552489864&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-fullwidth-code-point%2Fdownload%2Fis-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/locate-path/download/locate-path-3.0.0.tgz", + "integrity": "sha1-2+w7OrdZdYBxtY/ln8QYca8hQA4=", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.nlark.com/p-locate/download/p-locate-3.0.0.tgz", + "integrity": "sha1-Mi1poFwCZLJZl9n0DNiokasAZKQ=", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.nlark.com/path-exists/download/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.nlark.com/readdirp/download/readdirp-2.2.1.tgz", + "integrity": "sha1-DodiKjMlqjPokihcr4tOhGUppSU=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-1.0.0.tgz", + "integrity": "sha1-C3mpMgTXtgDUsoUNH2bCo0lRx3A=", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.nlark.com/string-width/download/string-width-3.1.0.tgz", + "integrity": "sha1-InZ74htirxCBV0MG9prFG2IgOWE=", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.nlark.com/ansi-regex/download/ansi-regex-4.1.0.tgz", + "integrity": "sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc=", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-5.2.0.tgz?cache=0&sync_timestamp=1618553320591&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-5.2.0.tgz", + "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-3.0.1.tgz?cache=0&sync_timestamp=1618553320591&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.nlark.com/supports-color/download/supports-color-6.1.0.tgz?cache=0&sync_timestamp=1622293670728&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fsupports-color%2Fdownload%2Fsupports-color-6.1.0.tgz", + "integrity": "sha1-B2Srxpxj1ayELdSGfo0CXogN+PM=", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npm.taobao.org/wrap-ansi/download/wrap-ansi-5.1.0.tgz", + "integrity": "sha1-H9H2cjXVttD+54EFYAG/tpTAOwk=", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.nlark.com/ansi-regex/download/ansi-regex-4.1.0.tgz", + "integrity": "sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc=", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-5.2.0.tgz?cache=0&sync_timestamp=1618553320591&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-5.2.0.tgz", + "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.nlark.com/yargs/download/yargs-13.3.2.tgz?cache=0&sync_timestamp=1620086465147&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fyargs%2Fdownload%2Fyargs-13.3.2.tgz", + "integrity": "sha1-rX/+/sGqWVZayRX4Lcyzipwxot0=", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npm.taobao.org/yargs-parser/download/yargs-parser-13.1.2.tgz", + "integrity": "sha1-Ew8JcC667vJlDVTObj5XBvek+zg=", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "webpack-log": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/webpack-log/download/webpack-log-2.0.0.tgz?cache=0&sync_timestamp=1615477439589&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fwebpack-log%2Fdownload%2Fwebpack-log-2.0.0.tgz", + "integrity": "sha1-W3ko4GN1k/EZ0y9iJ8HgrDHhtH8=", + "dev": true, + "requires": { + "ansi-colors": "^3.0.0", + "uuid": "^3.3.2" + } + }, + "webpack-merge": { + "version": "4.2.2", + "resolved": "https://registry.npm.taobao.org/webpack-merge/download/webpack-merge-4.2.2.tgz?cache=0&sync_timestamp=1608705506214&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fwebpack-merge%2Fdownload%2Fwebpack-merge-4.2.2.tgz", + "integrity": "sha1-onxS6ng9E5iv0gh/VH17nS9DY00=", + "dev": true, + "requires": { + "lodash": "^4.17.15" + } + }, + "webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.nlark.com/webpack-sources/download/webpack-sources-1.4.3.tgz?cache=0&sync_timestamp=1622110325575&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fwebpack-sources%2Fdownload%2Fwebpack-sources-1.4.3.tgz", + "integrity": "sha1-7t2OwLko+/HL/plOItLYkPMwqTM=", + "dev": true, + "requires": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "dev": true + } + } + }, + "websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.nlark.com/websocket-driver/download/websocket-driver-0.7.4.tgz", + "integrity": "sha1-ia1Slbv2S0gKvLox5JU6ynBvV2A=", + "dev": true, + "requires": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npm.taobao.org/websocket-extensions/download/websocket-extensions-0.1.4.tgz", + "integrity": "sha1-f4RzvIOd/YdgituV1+sHUhFXikI=", + "dev": true + }, + "when": { + "version": "3.6.4", + "resolved": "https://registry.npm.taobao.org/when/download/when-3.6.4.tgz", + "integrity": "sha1-RztRfsFZ4rhQBUl6E5g/CVQS404=", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.nlark.com/which/download/which-1.3.1.tgz", + "integrity": "sha1-pFBD1U9YBTFtqNYvn1CRjT2nCwo=", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.nlark.com/which-boxed-primitive/download/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha1-E3V7yJsgmwSf5dhkMOIc9AqJqOY=", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/which-module/download/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.nlark.com/word-wrap/download/word-wrap-1.2.3.tgz", + "integrity": "sha1-YQY29rH3A4kb00dxzLF/uTtHB5w=", + "dev": true + }, + "worker-farm": { + "version": "1.7.0", + "resolved": "https://registry.nlark.com/worker-farm/download/worker-farm-1.7.0.tgz?cache=0&sync_timestamp=1618846953836&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fworker-farm%2Fdownload%2Fworker-farm-1.7.0.tgz", + "integrity": "sha1-JqlMU5G7ypJhUgAvabhKS/dy5ag=", + "dev": true, + "requires": { + "errno": "~0.1.7" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npm.taobao.org/wrap-ansi/download/wrap-ansi-7.0.0.tgz", + "integrity": "sha1-Z+FFz/UQpqaYS98RUpEdadLrnkM=", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.nlark.com/ansi-styles/download/ansi-styles-4.3.0.tgz", + "integrity": "sha1-7dgDYornHATIWuegkG7a00tkiTc=", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz", + "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.nlark.com/color-name/download/color-name-1.1.4.tgz", + "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=", + "dev": true + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.nlark.com/wrappy/download/wrappy-1.0.2.tgz?cache=0&sync_timestamp=1619133505879&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fwrappy%2Fdownload%2Fwrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.nlark.com/write/download/write-1.0.3.tgz", + "integrity": "sha1-CADhRSO5I6OH5BUSPIZWFqrg9cM=", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "ws": { + "version": "6.2.1", + "resolved": "https://registry.nlark.com/ws/download/ws-6.2.1.tgz?cache=0&sync_timestamp=1621962892726&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fws%2Fdownload%2Fws-6.2.1.tgz", + "integrity": "sha1-RC/fCkftZPWbal2P8TD0dI7VJPs=", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npm.taobao.org/xtend/download/xtend-4.0.2.tgz", + "integrity": "sha1-u3J3n1+kZRhrH0OPZ0+jR/2121Q=", + "dev": true + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npm.taobao.org/y18n/download/y18n-4.0.3.tgz?cache=0&sync_timestamp=1617822684820&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fy18n%2Fdownload%2Fy18n-4.0.3.tgz", + "integrity": "sha1-tfJZyCzW4zaSHv17/Yv1YN6e7t8=", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npm.taobao.org/yallist/download/yallist-3.1.1.tgz", + "integrity": "sha1-27fa+b/YusmrRev2ArjLrQ1dCP0=", + "dev": true + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.nlark.com/yargs/download/yargs-16.2.0.tgz?cache=0&sync_timestamp=1620086465147&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fyargs%2Fdownload%2Fyargs-16.2.0.tgz", + "integrity": "sha1-HIK/D2tqZur85+8w43b0mhJHf2Y=", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "dependencies": { + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.nlark.com/cliui/download/cliui-7.0.4.tgz", + "integrity": "sha1-oCZe5lVHb8gHrqnfPfjfd4OAi08=", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npm.taobao.org/y18n/download/y18n-5.0.8.tgz?cache=0&sync_timestamp=1617822684820&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fy18n%2Fdownload%2Fy18n-5.0.8.tgz", + "integrity": "sha1-f0k00PfKjFb5UxSTndzS3ZHOHVU=", + "dev": true + } + } + }, + "yargs-parser": { + "version": "20.2.7", + "resolved": "https://registry.npm.taobao.org/yargs-parser/download/yargs-parser-20.2.7.tgz", + "integrity": "sha1-Yd+FwRPt+1p6TjbriqYO9CPLyQo=", + "dev": true + }, + "yorkie": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/yorkie/download/yorkie-2.0.0.tgz", + "integrity": "sha1-kkEZEtQ1IU4SxRwq4Qk+VLa7g9k=", + "dev": true, + "requires": { + "execa": "^0.8.0", + "is-ci": "^1.0.10", + "normalize-path": "^1.0.0", + "strip-indent": "^2.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npm.taobao.org/cross-spawn/download/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "0.8.0", + "resolved": "https://registry.nlark.com/execa/download/execa-0.8.0.tgz?cache=0&sync_timestamp=1622396637949&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fexeca%2Fdownload%2Fexeca-0.8.0.tgz", + "integrity": "sha1-2NdrvBtVIX7RkP1t1J08d07PyNo=", + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/get-stream/download/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.nlark.com/lru-cache/download/lru-cache-4.1.5.tgz", + "integrity": "sha1-i75Q6oW+1ZvJ4z3KuCNe6bz0Q80=", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "normalize-path": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/normalize-path/download/normalize-path-1.0.0.tgz", + "integrity": "sha1-MtDkcvkf80VwHBWoMRAY07CpA3k=", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npm.taobao.org/yallist/download/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } + } + } + } +} diff --git a/cmd/templates/vue3-js/frontend/package.json.template b/cmd/templates/vue3-js/frontend/package.json.template new file mode 100644 index 000000000..942f672da --- /dev/null +++ b/cmd/templates/vue3-js/frontend/package.json.template @@ -0,0 +1,49 @@ +{ + "name": "{{.NPMProjectName}}", + "version": "1.0.0", + "private": true, + "scripts": { + "serve": "vue-cli-service serve", + "build": "vue-cli-service build", + "lint": "vue-cli-service lint" + }, + "dependencies": { + "@wailsapp/runtime": "^1.1.1", + "core-js": "^3.6.5", + "vue": "^3.0.0", + "vue-router": "^4.0.0-0", + "vuex": "^4.0.0-0" + }, + "devDependencies": { + "@vue/cli-plugin-babel": "~4.5.0", + "@vue/cli-plugin-eslint": "~4.5.0", + "@vue/cli-plugin-router": "~4.5.0", + "@vue/cli-plugin-vuex": "~4.5.0", + "@vue/cli-service": "~4.5.0", + "@vue/compiler-sfc": "^3.0.0", + "babel-eslint": "^10.1.0", + "eslint": "^6.7.2", + "eslint-plugin-vue": "^7.0.0", + "stylus": "^0.54.7", + "stylus-loader": "^3.0.2" + }, + "eslintConfig": { + "root": true, + "env": { + "node": true + }, + "extends": [ + "plugin:vue/vue3-essential", + "eslint:recommended" + ], + "parserOptions": { + "parser": "babel-eslint" + }, + "rules": {} + }, + "browserslist": [ + "> 1%", + "last 2 versions", + "not dead" + ] +} diff --git a/cmd/templates/vue3-js/frontend/public/favicon.ico b/cmd/templates/vue3-js/frontend/public/favicon.ico new file mode 100644 index 000000000..df36fcfb7 Binary files /dev/null and b/cmd/templates/vue3-js/frontend/public/favicon.ico differ diff --git a/cmd/templates/vue3-js/frontend/public/index.html b/cmd/templates/vue3-js/frontend/public/index.html new file mode 100644 index 000000000..6ba8b205d --- /dev/null +++ b/cmd/templates/vue3-js/frontend/public/index.html @@ -0,0 +1,18 @@ + + + + + + + + <%= htmlWebpackPlugin.options.title %> + + + +
+ + + diff --git a/cmd/templates/vue3-js/frontend/src/App.vue b/cmd/templates/vue3-js/frontend/src/App.vue new file mode 100644 index 000000000..6d7594d66 --- /dev/null +++ b/cmd/templates/vue3-js/frontend/src/App.vue @@ -0,0 +1,30 @@ + + + diff --git a/cmd/templates/vue3-js/frontend/src/assets/appicon.png b/cmd/templates/vue3-js/frontend/src/assets/appicon.png new file mode 100644 index 000000000..9f22be34b Binary files /dev/null and b/cmd/templates/vue3-js/frontend/src/assets/appicon.png differ diff --git a/cmd/templates/vue3-js/frontend/src/assets/logo.png b/cmd/templates/vue3-js/frontend/src/assets/logo.png new file mode 100644 index 000000000..f3d2503fc Binary files /dev/null and b/cmd/templates/vue3-js/frontend/src/assets/logo.png differ diff --git a/cmd/templates/vue3-js/frontend/src/components/HelloWorld.vue b/cmd/templates/vue3-js/frontend/src/components/HelloWorld.vue new file mode 100644 index 000000000..0a5f13afe --- /dev/null +++ b/cmd/templates/vue3-js/frontend/src/components/HelloWorld.vue @@ -0,0 +1,32 @@ + + + + + + diff --git a/cmd/templates/vue3-js/frontend/src/main.js b/cmd/templates/vue3-js/frontend/src/main.js new file mode 100644 index 000000000..fb6c9ce07 --- /dev/null +++ b/cmd/templates/vue3-js/frontend/src/main.js @@ -0,0 +1,14 @@ +import {createApp} from 'vue' +import App from './App.vue' +import router from './router' +import store from './store' + +// import wails runtime +import * as Wails from '@wailsapp/runtime'; + +Wails.Init(() => { + createApp(App) + .use(store) + .use(router) + .mount('#app') +}) diff --git a/cmd/templates/vue3-js/frontend/src/router/index.js b/cmd/templates/vue3-js/frontend/src/router/index.js new file mode 100644 index 000000000..41f7ce976 --- /dev/null +++ b/cmd/templates/vue3-js/frontend/src/router/index.js @@ -0,0 +1,25 @@ +import {createMemoryHistory, createRouter} from 'vue-router' +import Home from '../views/Home.vue' +import About from '../views/About.vue' + + +const routes = [ + { + path: '/', + name: 'Home', + component: Home + }, + { + path: '/about', + name: 'About', + // You can only use pre-loading to add routes, not the on-demand loading method. + component: About + } +] + +const router = createRouter({ + history: createMemoryHistory(), + routes +}) + +export default router diff --git a/cmd/templates/vue3-js/frontend/src/store/index.js b/cmd/templates/vue3-js/frontend/src/store/index.js new file mode 100644 index 000000000..a747c1ce9 --- /dev/null +++ b/cmd/templates/vue3-js/frontend/src/store/index.js @@ -0,0 +1,8 @@ +import {createStore} from 'vuex' + +export default createStore({ + state: {}, + mutations: {}, + actions: {}, + modules: {} +}) diff --git a/cmd/templates/vue3-js/frontend/src/views/About.vue b/cmd/templates/vue3-js/frontend/src/views/About.vue new file mode 100644 index 000000000..3fa28070d --- /dev/null +++ b/cmd/templates/vue3-js/frontend/src/views/About.vue @@ -0,0 +1,5 @@ + diff --git a/cmd/templates/vue3-js/frontend/src/views/Home.vue b/cmd/templates/vue3-js/frontend/src/views/Home.vue new file mode 100644 index 000000000..ca38da0dc --- /dev/null +++ b/cmd/templates/vue3-js/frontend/src/views/Home.vue @@ -0,0 +1,42 @@ + + + diff --git a/cmd/templates/vue3-js/frontend/vue.config.js b/cmd/templates/vue3-js/frontend/vue.config.js new file mode 100644 index 000000000..72e4fd1d5 --- /dev/null +++ b/cmd/templates/vue3-js/frontend/vue.config.js @@ -0,0 +1,42 @@ +let cssConfig = {}; + +if (process.env.NODE_ENV == 'production') { + cssConfig = { + extract: { + filename: '[name].css', + chunkFilename: '[name].css' + } + }; +} + +module.exports = { + chainWebpack: config => { + let limit = 9999999999999999; + config.module + .rule('images') + .test(/\.(png|gif|jpg)(\?.*)?$/i) + .use('url-loader') + .loader('url-loader') + .tap(options => Object.assign(options, {limit: limit})); + config.module + .rule('fonts') + .test(/\.(woff2?|eot|ttf|otf|svg)(\?.*)?$/i) + .use('url-loader') + .loader('url-loader') + .options({ + limit: limit + }); + }, + css: cssConfig, + configureWebpack: { + output: { + filename: '[name].js' + }, + optimization: { + splitChunks: false + } + }, + devServer: { + disableHostCheck: true + } +}; diff --git a/cmd/templates/vue3-js/go.mod.template b/cmd/templates/vue3-js/go.mod.template new file mode 100644 index 000000000..780381065 --- /dev/null +++ b/cmd/templates/vue3-js/go.mod.template @@ -0,0 +1,5 @@ +module {{.BinaryName}} + +require ( + github.com/wailsapp/wails {{.WailsVersion}} +) \ No newline at end of file diff --git a/cmd/templates/vue3-js/main.go.template b/cmd/templates/vue3-js/main.go.template new file mode 100644 index 000000000..5c5453943 --- /dev/null +++ b/cmd/templates/vue3-js/main.go.template @@ -0,0 +1,30 @@ +package main + +import ( + _ "embed" + "github.com/wailsapp/wails" +) + +func basic() string { + return "Hello World!" +} + +//go:embed frontend/dist/app.js +var js string + +//go:embed frontend/dist/app.css +var css string + +func main() { + + app := wails.CreateApp(&wails.AppConfig{ + Width: 1024, + Height: 768, + Title: "{{.Name}}", + JS: js, + CSS: css, + Colour: "#131313", + }) + app.Bind(basic) + app.Run() +} diff --git a/cmd/templates/vue3-js/template.json b/cmd/templates/vue3-js/template.json new file mode 100644 index 000000000..8cde55215 --- /dev/null +++ b/cmd/templates/vue3-js/template.json @@ -0,0 +1,18 @@ +{ + "name": "Vue3 JS", + "version": "1.0.0", + "shortdescription": "A template based on Vue 3, Vue-router, Vuex, and Webpack5", + "description": "A template based on Vue 3, Vue-router, Vuex, and Webpack5", + "install": "npm install", + "build": "npm run build", + "author": "Misitebao ", + "created": "2021-05-02 17:25:55", + "frontenddir": "frontend", + "serve": "npm run serve", + "bridge": "src", + "wailsdir": "", + "platforms": [ + "linux", + "darwin" + ] +} diff --git a/cmd/templates/vuebasic/.jshint b/cmd/templates/vuebasic/.jshint new file mode 100644 index 000000000..0557edf11 --- /dev/null +++ b/cmd/templates/vuebasic/.jshint @@ -0,0 +1,3 @@ +{ + "esversion": 6 +} \ No newline at end of file diff --git a/cmd/templates/vuebasic/frontend/.gitignore b/cmd/templates/vuebasic/frontend/.gitignore new file mode 100644 index 000000000..185e66319 --- /dev/null +++ b/cmd/templates/vuebasic/frontend/.gitignore @@ -0,0 +1,21 @@ +.DS_Store +node_modules +/dist + +# local env files +.env.local +.env.*.local + +# Log files +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw* diff --git a/cmd/templates/vuebasic/frontend/README.md b/cmd/templates/vuebasic/frontend/README.md new file mode 100644 index 000000000..6953f66d0 --- /dev/null +++ b/cmd/templates/vuebasic/frontend/README.md @@ -0,0 +1,35 @@ +# vue basic + +## Project setup + +``` +npm install +``` + +### Compiles and hot-reloads for development + +``` +npm run serve +``` + +### Compiles and minifies for production + +``` +npm run build +``` + +### Run your tests + +``` +npm run test +``` + +### Lints and fixes files + +``` +npm run lint +``` + +### Customize configuration + +See [Configuration Reference](https://cli.vuejs.org/config/). diff --git a/cmd/templates/vuebasic/frontend/babel.config.js b/cmd/templates/vuebasic/frontend/babel.config.js new file mode 100644 index 000000000..a6106c484 --- /dev/null +++ b/cmd/templates/vuebasic/frontend/babel.config.js @@ -0,0 +1,5 @@ +module.exports = { + presets: [ + [ '@vue/app', { useBuiltIns: 'entry' } ] + ] +} diff --git a/cmd/templates/vuebasic/frontend/package.json.template b/cmd/templates/vuebasic/frontend/package.json.template new file mode 100644 index 000000000..1e51d9f38 --- /dev/null +++ b/cmd/templates/vuebasic/frontend/package.json.template @@ -0,0 +1,51 @@ +{ + "name": "{{.NPMProjectName}}", + "author": "{{.Author.Name}}<{{.Author.Email}}>", + "private": true, + "scripts": { + "serve": "vue-cli-service serve", + "build": "vue-cli-service build", + "lint": "vue-cli-service lint" + }, + "dependencies": { + "core-js": "^3.6.4", + "regenerator-runtime": "^0.13.3", + "vue": "^2.6.11", + "@wailsapp/runtime": "^1.0.10" + }, + "devDependencies": { + "@vue/cli-plugin-babel": "^4.2.3", + "@vue/cli-plugin-eslint": "^4.2.3", + "@vue/cli-service": "^4.2.3", + "babel-eslint": "^10.1.0", + "eslint": "^6.8.0", + "eslint-plugin-vue": "^6.2.1", + "eventsource-polyfill": "^0.9.6", + "vue-template-compiler": "^2.6.11", + "webpack-hot-middleware": "^2.25.0" + }, + "eslintConfig": { + "root": true, + "env": { + "node": true + }, + "extends": [ + "plugin:vue/essential", + "eslint:recommended" + ], + "rules": {}, + "parserOptions": { + "parser": "babel-eslint" + } + }, + "postcss": { + "plugins": { + "autoprefixer": {} + } + }, + "browserslist": [ + "> 1%", + "last 2 versions", + "not ie <= 8" + ] +} diff --git a/cmd/templates/vuebasic/frontend/src/App.vue b/cmd/templates/vuebasic/frontend/src/App.vue new file mode 100644 index 000000000..4700f3a71 --- /dev/null +++ b/cmd/templates/vuebasic/frontend/src/App.vue @@ -0,0 +1,18 @@ + + + diff --git a/cmd/templates/vuebasic/frontend/src/assets/css/main.css b/cmd/templates/vuebasic/frontend/src/assets/css/main.css new file mode 100644 index 000000000..ae5df813d --- /dev/null +++ b/cmd/templates/vuebasic/frontend/src/assets/css/main.css @@ -0,0 +1,38 @@ +#app { + font-family: "Roboto", Helvetica, Arial, sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + text-align: center; + color: #eee; + margin-top: 60px; +} + +html { + height: 100%; + overflow: hidden; + background-color: #131313; + background-size: 20px 20px; +} + +.logo { + width: 16em; +} + +/* roboto-regular - latin */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 400; + src: url("../fonts/roboto/roboto-v18-latin-regular.eot"); /* IE9 Compat Modes */ + src: local("Roboto"), local("Roboto-Regular"), + url("../fonts/roboto/roboto-v18-latin-regular.eot?#iefix") + format("embedded-opentype"), + /* IE6-IE8 */ url("../fonts/roboto/roboto-v18-latin-regular.woff2") + format("woff2"), + /* Super Modern Browsers */ + url("../fonts/roboto/roboto-v18-latin-regular.woff") format("woff"), + /* Modern Browsers */ url("../fonts/roboto/roboto-v18-latin-regular.ttf") + format("truetype"), + /* Safari, Android, iOS */ + url("../fonts/roboto/roboto-v18-latin-regular.svg#Roboto") format("svg"); /* Legacy iOS */ +} diff --git a/v2/internal/typescriptify/LICENSE.txt b/cmd/templates/vuebasic/frontend/src/assets/fonts/LICENSE.txt similarity index 97% rename from v2/internal/typescriptify/LICENSE.txt rename to cmd/templates/vuebasic/frontend/src/assets/fonts/LICENSE.txt index fa6e64ac4..75b52484e 100644 --- a/v2/internal/typescriptify/LICENSE.txt +++ b/cmd/templates/vuebasic/frontend/src/assets/fonts/LICENSE.txt @@ -1,202 +1,202 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [2015-] [Tomo Krajina] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/cmd/templates/vuebasic/frontend/src/assets/fonts/roboto/roboto-v18-latin-regular.eot b/cmd/templates/vuebasic/frontend/src/assets/fonts/roboto/roboto-v18-latin-regular.eot new file mode 100644 index 000000000..a0780d6e3 Binary files /dev/null and b/cmd/templates/vuebasic/frontend/src/assets/fonts/roboto/roboto-v18-latin-regular.eot differ diff --git a/cmd/templates/vuebasic/frontend/src/assets/fonts/roboto/roboto-v18-latin-regular.svg b/cmd/templates/vuebasic/frontend/src/assets/fonts/roboto/roboto-v18-latin-regular.svg new file mode 100644 index 000000000..627f5a368 --- /dev/null +++ b/cmd/templates/vuebasic/frontend/src/assets/fonts/roboto/roboto-v18-latin-regular.svg @@ -0,0 +1,308 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cmd/templates/vuebasic/frontend/src/assets/fonts/roboto/roboto-v18-latin-regular.ttf b/cmd/templates/vuebasic/frontend/src/assets/fonts/roboto/roboto-v18-latin-regular.ttf new file mode 100644 index 000000000..b91bf3f7e Binary files /dev/null and b/cmd/templates/vuebasic/frontend/src/assets/fonts/roboto/roboto-v18-latin-regular.ttf differ diff --git a/cmd/templates/vuebasic/frontend/src/assets/fonts/roboto/roboto-v18-latin-regular.woff b/cmd/templates/vuebasic/frontend/src/assets/fonts/roboto/roboto-v18-latin-regular.woff new file mode 100644 index 000000000..92dfacc61 Binary files /dev/null and b/cmd/templates/vuebasic/frontend/src/assets/fonts/roboto/roboto-v18-latin-regular.woff differ diff --git a/cmd/templates/vuebasic/frontend/src/assets/fonts/roboto/roboto-v18-latin-regular.woff2 b/cmd/templates/vuebasic/frontend/src/assets/fonts/roboto/roboto-v18-latin-regular.woff2 new file mode 100644 index 000000000..7e854e669 Binary files /dev/null and b/cmd/templates/vuebasic/frontend/src/assets/fonts/roboto/roboto-v18-latin-regular.woff2 differ diff --git a/cmd/templates/vuebasic/frontend/src/assets/images/logo.png b/cmd/templates/vuebasic/frontend/src/assets/images/logo.png new file mode 100644 index 000000000..31fc8249c Binary files /dev/null and b/cmd/templates/vuebasic/frontend/src/assets/images/logo.png differ diff --git a/cmd/templates/vuebasic/frontend/src/components/HelloWorld.vue b/cmd/templates/vuebasic/frontend/src/components/HelloWorld.vue new file mode 100644 index 000000000..722175f7b --- /dev/null +++ b/cmd/templates/vuebasic/frontend/src/components/HelloWorld.vue @@ -0,0 +1,55 @@ + + + + + + diff --git a/cmd/templates/vuebasic/frontend/src/main.js b/cmd/templates/vuebasic/frontend/src/main.js new file mode 100644 index 000000000..ce05741b7 --- /dev/null +++ b/cmd/templates/vuebasic/frontend/src/main.js @@ -0,0 +1,15 @@ +import 'core-js/stable'; +import 'regenerator-runtime/runtime'; +import Vue from 'vue'; +import App from './App.vue'; + +Vue.config.productionTip = false; +Vue.config.devtools = true; + +import * as Wails from '@wailsapp/runtime'; + +Wails.Init(() => { + new Vue({ + render: h => h(App) + }).$mount('#app'); +}); diff --git a/cmd/templates/vuebasic/frontend/vue.config.js b/cmd/templates/vuebasic/frontend/vue.config.js new file mode 100644 index 000000000..a2691b1f7 --- /dev/null +++ b/cmd/templates/vuebasic/frontend/vue.config.js @@ -0,0 +1,42 @@ +let cssConfig = {}; + +if (process.env.NODE_ENV == "production") { + cssConfig = { + extract: { + filename: "[name].css", + chunkFilename: "[name].css" + } + }; +} + +module.exports = { + chainWebpack: config => { + let limit = 9999999999999999; + config.module + .rule("images") + .test(/\.(png|gif|jpg)(\?.*)?$/i) + .use("url-loader") + .loader("url-loader") + .tap(options => Object.assign(options, { limit: limit })); + config.module + .rule("fonts") + .test(/\.(woff2?|eot|ttf|otf|svg)(\?.*)?$/i) + .use("url-loader") + .loader("url-loader") + .options({ + limit: limit + }); + }, + css: cssConfig, + configureWebpack: { + output: { + filename: "[name].js" + }, + optimization: { + splitChunks: false + } + }, + devServer: { + disableHostCheck: true + } +}; diff --git a/cmd/templates/vuebasic/go.mod.template b/cmd/templates/vuebasic/go.mod.template new file mode 100644 index 000000000..780381065 --- /dev/null +++ b/cmd/templates/vuebasic/go.mod.template @@ -0,0 +1,5 @@ +module {{.BinaryName}} + +require ( + github.com/wailsapp/wails {{.WailsVersion}} +) \ No newline at end of file diff --git a/cmd/templates/vuebasic/main.go.template b/cmd/templates/vuebasic/main.go.template new file mode 100644 index 000000000..5c5453943 --- /dev/null +++ b/cmd/templates/vuebasic/main.go.template @@ -0,0 +1,30 @@ +package main + +import ( + _ "embed" + "github.com/wailsapp/wails" +) + +func basic() string { + return "Hello World!" +} + +//go:embed frontend/dist/app.js +var js string + +//go:embed frontend/dist/app.css +var css string + +func main() { + + app := wails.CreateApp(&wails.AppConfig{ + Width: 1024, + Height: 768, + Title: "{{.Name}}", + JS: js, + CSS: css, + Colour: "#131313", + }) + app.Bind(basic) + app.Run() +} diff --git a/cmd/templates/vuebasic/template.json b/cmd/templates/vuebasic/template.json new file mode 100644 index 000000000..f2d017823 --- /dev/null +++ b/cmd/templates/vuebasic/template.json @@ -0,0 +1,12 @@ +{ + "name": "Vue2/Webpack Basic", + "shortdescription": "A basic Vue2/WebPack4 template", + "description": "A basic template using Vue 2 and bundled using Webpack 4", + "author": "Lea Anthony", + "created": "2018-12-01", + "frontenddir": "frontend", + "install": "npm install", + "build": "npm run build", + "serve": "npm run serve", + "bridge": "src" +} diff --git a/cmd/templates/vuetify-basic/.jshint b/cmd/templates/vuetify-basic/.jshint new file mode 100644 index 000000000..0557edf11 --- /dev/null +++ b/cmd/templates/vuetify-basic/.jshint @@ -0,0 +1,3 @@ +{ + "esversion": 6 +} \ No newline at end of file diff --git a/cmd/templates/vuetify-basic/frontend/.gitignore b/cmd/templates/vuetify-basic/frontend/.gitignore new file mode 100644 index 000000000..185e66319 --- /dev/null +++ b/cmd/templates/vuetify-basic/frontend/.gitignore @@ -0,0 +1,21 @@ +.DS_Store +node_modules +/dist + +# local env files +.env.local +.env.*.local + +# Log files +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw* diff --git a/cmd/templates/vuetify-basic/frontend/babel.config.js b/cmd/templates/vuetify-basic/frontend/babel.config.js new file mode 100644 index 000000000..a6106c484 --- /dev/null +++ b/cmd/templates/vuetify-basic/frontend/babel.config.js @@ -0,0 +1,5 @@ +module.exports = { + presets: [ + [ '@vue/app', { useBuiltIns: 'entry' } ] + ] +} diff --git a/cmd/templates/vuetify-basic/frontend/package.json.template b/cmd/templates/vuetify-basic/frontend/package.json.template new file mode 100644 index 000000000..430566f67 --- /dev/null +++ b/cmd/templates/vuetify-basic/frontend/package.json.template @@ -0,0 +1,53 @@ +{ + "name": "{{.NPMProjectName}}", + "author": "{{.Author.Name}}<{{.Author.Email}}>", + "private": true, + "scripts": { + "serve": "vue-cli-service serve", + "build": "vue-cli-service build", + "lint": "vue-cli-service lint" + }, +"dependencies": { + "core-js": "^3.6.4", + "regenerator-runtime": "^0.13.3", + "material-design-icons-iconfont": "^5.0.1", + "vue": "^2.5.22", + "vuetify": "^1.5.14", + "@wailsapp/runtime": "^1.0.10" + }, + "devDependencies": { + "@vue/cli-plugin-babel": "^4.2.3", + "@vue/cli-plugin-eslint": "^4.2.3", + "@vue/cli-service": "^4.2.3", + "babel-eslint": "^10.1.0", + "eslint": "^6.8.0", + "eslint-plugin-vue": "^6.2.1", + "eventsource-polyfill": "^0.9.6", + "vue-template-compiler": "^2.6.11", + "webpack-hot-middleware": "^2.25.0" + }, + "eslintConfig": { + "root": true, + "env": { + "node": true + }, + "extends": [ + "plugin:vue/essential", + "eslint:recommended" + ], + "rules": {}, + "parserOptions": { + "parser": "babel-eslint" + } + }, + "postcss": { + "plugins": { + "autoprefixer": {} + } + }, + "browserslist": [ + "> 1%", + "last 2 versions", + "not ie <= 8" + ] +} diff --git a/cmd/templates/vuetify-basic/frontend/src/App.vue b/cmd/templates/vuetify-basic/frontend/src/App.vue new file mode 100644 index 000000000..6522b31e0 --- /dev/null +++ b/cmd/templates/vuetify-basic/frontend/src/App.vue @@ -0,0 +1,60 @@ + + + + + \ No newline at end of file diff --git a/cmd/templates/vuetify-basic/frontend/src/assets/images/logo.png b/cmd/templates/vuetify-basic/frontend/src/assets/images/logo.png new file mode 100644 index 000000000..31fc8249c Binary files /dev/null and b/cmd/templates/vuetify-basic/frontend/src/assets/images/logo.png differ diff --git a/cmd/templates/vuetify-basic/frontend/src/components/HelloWorld.vue b/cmd/templates/vuetify-basic/frontend/src/components/HelloWorld.vue new file mode 100644 index 000000000..28487aa06 --- /dev/null +++ b/cmd/templates/vuetify-basic/frontend/src/components/HelloWorld.vue @@ -0,0 +1,83 @@ + + + + + + diff --git a/cmd/templates/vuetify-basic/frontend/src/main.js b/cmd/templates/vuetify-basic/frontend/src/main.js new file mode 100644 index 000000000..bbe42e116 --- /dev/null +++ b/cmd/templates/vuetify-basic/frontend/src/main.js @@ -0,0 +1,22 @@ +import 'core-js/stable'; +import 'regenerator-runtime/runtime'; +import Vue from 'vue'; + +// Setup Vuetify +import Vuetify from 'vuetify'; +Vue.use(Vuetify); +import 'vuetify/dist/vuetify.min.css'; +import 'material-design-icons-iconfont'; + +import App from './App.vue'; + +Vue.config.productionTip = false; +Vue.config.devtools = true; + +import * as Wails from '@wailsapp/runtime'; + +Wails.Init(() => { + new Vue({ + render: h => h(App) + }).$mount('#app'); +}); diff --git a/cmd/templates/vuetify-basic/frontend/vue.config.js b/cmd/templates/vuetify-basic/frontend/vue.config.js new file mode 100644 index 000000000..a2691b1f7 --- /dev/null +++ b/cmd/templates/vuetify-basic/frontend/vue.config.js @@ -0,0 +1,42 @@ +let cssConfig = {}; + +if (process.env.NODE_ENV == "production") { + cssConfig = { + extract: { + filename: "[name].css", + chunkFilename: "[name].css" + } + }; +} + +module.exports = { + chainWebpack: config => { + let limit = 9999999999999999; + config.module + .rule("images") + .test(/\.(png|gif|jpg)(\?.*)?$/i) + .use("url-loader") + .loader("url-loader") + .tap(options => Object.assign(options, { limit: limit })); + config.module + .rule("fonts") + .test(/\.(woff2?|eot|ttf|otf|svg)(\?.*)?$/i) + .use("url-loader") + .loader("url-loader") + .options({ + limit: limit + }); + }, + css: cssConfig, + configureWebpack: { + output: { + filename: "[name].js" + }, + optimization: { + splitChunks: false + } + }, + devServer: { + disableHostCheck: true + } +}; diff --git a/cmd/templates/vuetify-basic/go.mod.template b/cmd/templates/vuetify-basic/go.mod.template new file mode 100644 index 000000000..780381065 --- /dev/null +++ b/cmd/templates/vuetify-basic/go.mod.template @@ -0,0 +1,5 @@ +module {{.BinaryName}} + +require ( + github.com/wailsapp/wails {{.WailsVersion}} +) \ No newline at end of file diff --git a/cmd/templates/vuetify-basic/main.go.template b/cmd/templates/vuetify-basic/main.go.template new file mode 100644 index 000000000..5c5453943 --- /dev/null +++ b/cmd/templates/vuetify-basic/main.go.template @@ -0,0 +1,30 @@ +package main + +import ( + _ "embed" + "github.com/wailsapp/wails" +) + +func basic() string { + return "Hello World!" +} + +//go:embed frontend/dist/app.js +var js string + +//go:embed frontend/dist/app.css +var css string + +func main() { + + app := wails.CreateApp(&wails.AppConfig{ + Width: 1024, + Height: 768, + Title: "{{.Name}}", + JS: js, + CSS: css, + Colour: "#131313", + }) + app.Bind(basic) + app.Run() +} diff --git a/cmd/templates/vuetify-basic/template.json b/cmd/templates/vuetify-basic/template.json new file mode 100755 index 000000000..b58b5b041 --- /dev/null +++ b/cmd/templates/vuetify-basic/template.json @@ -0,0 +1,14 @@ +{ + "name": "Vuetify1.5/Webpack Basic", + "version": "1.0.0", + "shortdescription": "A basic Vuetify1.5/Webpack4 template", + "description": "Basic template using Vuetify v1.5 and bundled using Webpack", + "install": "npm install", + "build": "npm run build", + "author": "lea ", + "created": "2019-05-25 09:39:40.009307 +1000 AEST m=+59.539991073", + "frontenddir": "frontend", + "serve": "npm run serve", + "bridge": "src", + "wailsdir": "" +} diff --git a/cmd/templates/vuetify2-basic/.jshint b/cmd/templates/vuetify2-basic/.jshint new file mode 100644 index 000000000..0557edf11 --- /dev/null +++ b/cmd/templates/vuetify2-basic/.jshint @@ -0,0 +1,3 @@ +{ + "esversion": 6 +} \ No newline at end of file diff --git a/cmd/templates/vuetify2-basic/frontend/.gitignore b/cmd/templates/vuetify2-basic/frontend/.gitignore new file mode 100644 index 000000000..185e66319 --- /dev/null +++ b/cmd/templates/vuetify2-basic/frontend/.gitignore @@ -0,0 +1,21 @@ +.DS_Store +node_modules +/dist + +# local env files +.env.local +.env.*.local + +# Log files +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw* diff --git a/cmd/templates/vuetify2-basic/frontend/babel.config.js b/cmd/templates/vuetify2-basic/frontend/babel.config.js new file mode 100644 index 000000000..57e6d0a51 --- /dev/null +++ b/cmd/templates/vuetify2-basic/frontend/babel.config.js @@ -0,0 +1,5 @@ +module.exports = { + presets: [ + [ '@vue/app', { useBuiltIns: 'entry' } ] + ] +}; diff --git a/cmd/templates/vuetify2-basic/frontend/package.json.template b/cmd/templates/vuetify2-basic/frontend/package.json.template new file mode 100644 index 000000000..0913c632d --- /dev/null +++ b/cmd/templates/vuetify2-basic/frontend/package.json.template @@ -0,0 +1,53 @@ +{ + "name": "{{.NPMProjectName}}", + "author": "{{.Author.Name}}<{{.Author.Email}}>", + "private": true, + "scripts": { + "serve": "vue-cli-service serve", + "build": "vue-cli-service build", + "lint": "vue-cli-service lint" + }, + "dependencies": { + "core-js": "^3.6.4", + "regenerator-runtime": "^0.13.3", + "vue": "^2.6.11", + "vuetify": "^2.3.15", + "@wailsapp/runtime": "^1.0.10" + }, + "devDependencies": { + "@mdi/font": "^4.9.95", + "@vue/cli-plugin-babel": "^4.2.3", + "@vue/cli-plugin-eslint": "^4.2.3", + "@vue/cli-service": "^4.2.3", + "babel-eslint": "^10.1.0", + "eslint": "^6.8.0", + "eslint-plugin-vue": "^6.2.1", + "eventsource-polyfill": "^0.9.6", + "vue-template-compiler": "^2.6.11", + "webpack-hot-middleware": "^2.25.0" + }, + "eslintConfig": { + "root": true, + "env": { + "node": true + }, + "extends": [ + "plugin:vue/essential", + "eslint:recommended" + ], + "rules": {}, + "parserOptions": { + "parser": "babel-eslint" + } + }, + "postcss": { + "plugins": { + "autoprefixer": {} + } + }, + "browserslist": [ + "> 1%", + "last 2 versions", + "not ie <= 8" + ] +} diff --git a/cmd/templates/vuetify2-basic/frontend/src/App.vue b/cmd/templates/vuetify2-basic/frontend/src/App.vue new file mode 100644 index 000000000..759c1fba4 --- /dev/null +++ b/cmd/templates/vuetify2-basic/frontend/src/App.vue @@ -0,0 +1,60 @@ + + + + + diff --git a/cmd/templates/vuetify2-basic/frontend/src/assets/images/logo.png b/cmd/templates/vuetify2-basic/frontend/src/assets/images/logo.png new file mode 100644 index 000000000..31fc8249c Binary files /dev/null and b/cmd/templates/vuetify2-basic/frontend/src/assets/images/logo.png differ diff --git a/cmd/templates/vuetify2-basic/frontend/src/components/HelloWorld.vue b/cmd/templates/vuetify2-basic/frontend/src/components/HelloWorld.vue new file mode 100644 index 000000000..84708401c --- /dev/null +++ b/cmd/templates/vuetify2-basic/frontend/src/components/HelloWorld.vue @@ -0,0 +1,85 @@ + + + + + + diff --git a/cmd/templates/vuetify2-basic/frontend/src/main.js b/cmd/templates/vuetify2-basic/frontend/src/main.js new file mode 100644 index 000000000..245eb1e03 --- /dev/null +++ b/cmd/templates/vuetify2-basic/frontend/src/main.js @@ -0,0 +1,29 @@ +import 'core-js/stable'; +import 'regenerator-runtime/runtime'; +import '@mdi/font/css/materialdesignicons.css'; +import Vue from 'vue'; +import Vuetify from 'vuetify'; +import 'vuetify/dist/vuetify.min.css'; + +Vue.use(Vuetify); + +import App from './App.vue'; + +Vue.config.productionTip = false; +Vue.config.devtools = true; + +import Wails from '@wailsapp/runtime'; + +Wails.Init(() => { + new Vue({ + vuetify: new Vuetify({ + icons: { + iconfont: 'mdi' + }, + theme: { + dark: true + } + }), + render: h => h(App) + }).$mount('#app'); +}); diff --git a/cmd/templates/vuetify2-basic/frontend/vue.config.js b/cmd/templates/vuetify2-basic/frontend/vue.config.js new file mode 100644 index 000000000..8dcf3e339 --- /dev/null +++ b/cmd/templates/vuetify2-basic/frontend/vue.config.js @@ -0,0 +1,42 @@ +let cssConfig = {}; + +if (process.env.NODE_ENV == 'production') { + cssConfig = { + extract: { + filename: '[name].css', + chunkFilename: '[name].css' + } + }; +} + +module.exports = { + chainWebpack: config => { + let limit = 9999999999999999; + config.module + .rule('images') + .test(/\.(png|gif|jpg)(\?.*)?$/i) + .use('url-loader') + .loader('url-loader') + .tap(options => Object.assign(options, { limit: limit })); + config.module + .rule('fonts') + .test(/\.(woff2?|eot|ttf|otf|svg)(\?.*)?$/i) + .use('url-loader') + .loader('url-loader') + .options({ + limit: limit + }); + }, + css: cssConfig, + configureWebpack: { + output: { + filename: '[name].js' + }, + optimization: { + splitChunks: false + } + }, + devServer: { + disableHostCheck: true + } +}; diff --git a/cmd/templates/vuetify2-basic/go.mod.template b/cmd/templates/vuetify2-basic/go.mod.template new file mode 100644 index 000000000..780381065 --- /dev/null +++ b/cmd/templates/vuetify2-basic/go.mod.template @@ -0,0 +1,5 @@ +module {{.BinaryName}} + +require ( + github.com/wailsapp/wails {{.WailsVersion}} +) \ No newline at end of file diff --git a/cmd/templates/vuetify2-basic/main.go.template b/cmd/templates/vuetify2-basic/main.go.template new file mode 100644 index 000000000..5c5453943 --- /dev/null +++ b/cmd/templates/vuetify2-basic/main.go.template @@ -0,0 +1,30 @@ +package main + +import ( + _ "embed" + "github.com/wailsapp/wails" +) + +func basic() string { + return "Hello World!" +} + +//go:embed frontend/dist/app.js +var js string + +//go:embed frontend/dist/app.css +var css string + +func main() { + + app := wails.CreateApp(&wails.AppConfig{ + Width: 1024, + Height: 768, + Title: "{{.Name}}", + JS: js, + CSS: css, + Colour: "#131313", + }) + app.Bind(basic) + app.Run() +} diff --git a/cmd/templates/vuetify2-basic/template.json b/cmd/templates/vuetify2-basic/template.json new file mode 100755 index 000000000..a33450fe5 --- /dev/null +++ b/cmd/templates/vuetify2-basic/template.json @@ -0,0 +1,14 @@ +{ + "name": "Vuetify2/Webpack Basic", + "version": "1.0.0", + "shortdescription": "A basic Vuetify2/Webpack4 template", + "description": "Basic template using Vuetify v2 and bundled using Webpack", + "install": "npm install", + "build": "npm run build", + "author": "Michael Hipp ", + "created": "2019-09-06", + "frontenddir": "frontend", + "serve": "npm run serve", + "bridge": "src", + "wailsdir": "" +} diff --git a/cmd/version.go b/cmd/version.go new file mode 100644 index 000000000..892ffa5a0 --- /dev/null +++ b/cmd/version.go @@ -0,0 +1,4 @@ +package cmd + +// Version - Wails version +const Version = "v1.16.7" diff --git a/cmd/wails/0_setup.go b/cmd/wails/0_setup.go new file mode 100644 index 000000000..394f565a7 --- /dev/null +++ b/cmd/wails/0_setup.go @@ -0,0 +1,52 @@ +package main + +import ( + "runtime" + + "github.com/wailsapp/wails/cmd" +) + +func init() { + + commandDescription := `Sets up your local environment to develop Wails apps.` + + setupCommand := app.Command("setup", "Setup the Wails environment"). + LongDescription(commandDescription) + + app.DefaultCommand(setupCommand) + + setupCommand.Action(func() error { + + logger.PrintBanner() + + var err error + + system := cmd.NewSystemHelper() + err = system.Initialise() + if err != nil { + return err + } + + var successMessage = `Ready for take off! +Create your first project by running 'wails init'.` + if runtime.GOOS != "windows" { + successMessage = "🚀 " + successMessage + } + + // Chrck for programs and libraries dependencies + errors, err := cmd.CheckDependencies(logger) + if err != nil { + return err + } + + // Check for errors + // CheckDependencies() returns !errors + // so to get the right message in this + // check we have to do it in reversed + if errors { + logger.Yellow(successMessage) + } + + return err + }) +} diff --git a/cmd/wails/10.1_dev_newtemplate.go b/cmd/wails/10.1_dev_newtemplate.go new file mode 100644 index 000000000..17e4a4c1e --- /dev/null +++ b/cmd/wails/10.1_dev_newtemplate.go @@ -0,0 +1,122 @@ +//go:build dev +// +build dev + +package main + +import ( + "fmt" + "time" + + "github.com/wailsapp/wails/cmd" + "gopkg.in/AlecAivazis/survey.v1" +) + +var templateHelper = cmd.NewTemplateHelper() + +var qs = []*survey.Question{ + { + Name: "Name", + Prompt: &survey.Input{Message: "Please enter the name of your template (eg: React/Webpack Basic):"}, + Validate: survey.Required, + }, + { + Name: "ShortDescription", + Prompt: &survey.Input{Message: "Please enter a short description for the template (eg: React with Webpack 4):"}, + Validate: survey.Required, + }, + { + Name: "Description", + Prompt: &survey.Input{Message: "Please enter a long description:"}, + Validate: survey.Required, + }, + { + Name: "FrontendDir", + Prompt: &survey.Input{Message: "Please enter the name of the directory the frontend code resides (eg: frontend):"}, + Validate: survey.Required, + }, + { + Name: "Install", + Prompt: &survey.Input{Message: "Please enter the install command (eg: npm install):"}, + Validate: survey.Required, + }, + { + Name: "Build", + Prompt: &survey.Input{Message: "Please enter the build command (eg: npm run build):"}, + Validate: survey.Required, + }, + { + Name: "Serve", + Prompt: &survey.Input{Message: "Please enter the serve command (eg: npm run serve):"}, + Validate: survey.Required, + }, + { + Name: "Bridge", + Prompt: &survey.Input{Message: "Please enter the name of the directory to copy the wails bridge runtime (eg: src):"}, + Validate: survey.Required, + }, +} + +func newTemplate(devCommand *cmd.Command) { + + commandDescription := `This command scaffolds everything needed to develop a new template.` + newTemplate := devCommand.Command("newtemplate", "Generate a new template"). + LongDescription(commandDescription) + + newTemplate.Action(func() error { + logger.PrintSmallBanner("Generating new project template") + fmt.Println() + + var answers cmd.TemplateMetadata + + // perform the questions + err := survey.Ask(qs, &answers) + if err != nil { + fmt.Println(err.Error()) + return err + } + + dirname := templateHelper.SanitizeFilename(answers.Name) + prompt := []*survey.Question{{ + Prompt: &survey.Input{ + Message: "Please enter a directory name for the template:", + Default: dirname, + }, + Validate: func(val interface{}) error { + err := survey.Required(val) + if err != nil { + return err + } + if templateHelper.IsValidTemplate(val.(string)) { + return fmt.Errorf("template directory already exists") + } + if templateHelper.SanitizeFilename(val.(string)) != val.(string) { + return fmt.Errorf("invalid directory name '%s'", val.(string)) + } + return nil + }, + }} + err = survey.Ask(prompt, &dirname) + if err != nil { + return err + } + + answers.Version = "1.0.0" + answers.Created = time.Now().String() + + // Get Author info from system info + system := cmd.NewSystemHelper() + author, err := system.GetAuthor() + if err == nil { + answers.Author = author + } + + templateDirectory, err := templateHelper.CreateNewTemplate(dirname, &answers) + if err != nil { + return err + } + + logger.Green("Created new template '%s' in directory '%s'", answers.Name, templateDirectory) + + return nil + }) +} diff --git a/cmd/wails/10_dev.go b/cmd/wails/10_dev.go new file mode 100644 index 000000000..ea0af0976 --- /dev/null +++ b/cmd/wails/10_dev.go @@ -0,0 +1,19 @@ +//go:build dev +// +build dev + +package main + +func init() { + + commandDescription := `This command provides access to developer tooling.` + devCommand := app.Command("dev", "A selection of developer tools"). + LongDescription(commandDescription) + + // Add subcommands + newTemplate(devCommand) + + devCommand.Action(func() error { + devCommand.PrintHelp() + return nil + }) +} diff --git a/cmd/wails/15_migrate.go b/cmd/wails/15_migrate.go new file mode 100644 index 000000000..f4c935f77 --- /dev/null +++ b/cmd/wails/15_migrate.go @@ -0,0 +1,385 @@ +package main + +import ( + "bufio" + "fmt" + "io/ioutil" + "log" + "os" + "path/filepath" + "strings" + + "github.com/Masterminds/semver" + "github.com/leaanthony/spinner" + "github.com/wailsapp/wails/cmd" +) + +// Constants +var checkSpinner = spinner.NewSpinner() +var migrateProjectOptions = &cmd.ProjectOptions{} +var migrateFS = cmd.NewFSHelper() +var migrateGithub = cmd.NewGitHubHelper() +var programHelper = cmd.NewProgramHelper() +var lessThanV1 *semver.Constraints + +// The user's go.mod +var goMod string +var goModFile string + +// The user's main.js +var mainJSFile string +var mainJSContents string + +// Frontend directory +var frontEndDir string + +func init() { + + var dryrun bool + var err error + + lessThanV1, err = semver.NewConstraint("< v1.0.0") + if err != nil { + log.Fatal(err) + } + + // var forceRebuild = false + checkSpinner.SetSpinSpeed(50) + + commandDescription := `EXPERIMENTAL - This command attempts to migrate projects to the latest Wails version.` + updateCmd := app.Command("migrate", "Migrate projects to latest Wails release"). + LongDescription(commandDescription). + BoolFlag("dryrun", "Only display what would be done", &dryrun) + + updateCmd.Action(func() error { + + message := "Migrate Project" + logger.PrintSmallBanner(message) + logger.Red("WARNING: This is an experimental command. Ensure you have backups of your project!") + logger.Red("It currently only supports npm based projects.") + fmt.Println() + + // Check project directory + err := checkProjectDirectory() + if err != nil { + return err + } + + // Find Wails version from go.mod + wailsVersion, err := getWailsVersion() + if err != nil { + return err + } + + // Get latest stable version + var latestVersion *semver.Version + latestVersion, err = getLatestWailsVersion() + if err != nil { + return err + } + + var canMigrate bool + canMigrate, err = canMigrateVersion(wailsVersion, latestVersion) + if err != nil { + return err + } + + if !canMigrate { + return nil + } + + // Check for wailsbridge + wailsBridge, err := checkWailsBridge() + if err != nil { + return err + } + + // Is main.js using bridge.Init() + canUpdateMainJS, err := checkMainJS() + if err != nil { + return err + } + + // TODO: Check if we are using legacy js runtime + + // Operations + logger.Yellow("Operations to perform:") + + logger.Yellowf(" - Update to Wails v%s\n", latestVersion) + + if len(wailsBridge) > 0 { + logger.Yellow(" - Delete wailsbridge.js") + } + + if canUpdateMainJS { + logger.Yellow(" - Patch main.js") + } + + logger.Yellow(" - Ensure '@wailsapp/runtime` module is installed") + + if dryrun { + logger.White("Exiting: Dry Run") + return nil + } + + logger.Red("*WARNING* About to modify your project!") + logger.Red("Type 'YES' to continue: ") + scanner := bufio.NewScanner(os.Stdin) + scanner.Scan() + input := scanner.Text() + if input != "YES" { + logger.Red("ABORTED!") + return nil + } + + logger.Yellow("Let's do this!") + + err = updateWailsVersion(wailsVersion, latestVersion) + if err != nil { + return err + } + + if len(wailsBridge) > 0 { + err = deleteWailsBridge(wailsBridge) + if err != nil { + return err + } + } + + if canUpdateMainJS { + err = patchMainJS() + if err != nil { + return err + } + } + + // Install runtime + err = installWailsRuntime() + if err != nil { + return err + } + + fmt.Println() + logger.Yellow("Migration complete! Check project by running `wails build`.") + return nil + }) +} + +func checkProjectDirectory() error { + // Get versions + checkSpinner.Start("Check Project Directory") + + // Check we are in project directory + err := migrateProjectOptions.LoadConfig(migrateFS.Cwd()) + if err != nil { + checkSpinner.Error() + return fmt.Errorf("Unable to find 'project.json'. Please check you are in a Wails project directory") + } + + checkSpinner.Success() + return nil +} + +func getWailsVersion() (*semver.Version, error) { + checkSpinner.Start("Get Wails Version") + + result, err := cmd.GetWailsVersion() + + if err != nil { + checkSpinner.Error(err.Error()) + return nil, err + } + return result, nil + +} + +func canMigrateVersion(wailsVersion *semver.Version, latestVersion *semver.Version) (bool, error) { + checkSpinner.Start("Checking ability to Migrate") + + // Check if we are at the latest version!!!! + if wailsVersion.Equal(latestVersion) || wailsVersion.GreaterThan(latestVersion) { + checkSpinner.Errorf("Checking ability to Migrate: No! (v%s >= v%s)", wailsVersion, latestVersion) + return false, nil + } + + // Check for < v1.0.0 + if lessThanV1.Check(wailsVersion) { + checkSpinner.Successf("Checking ability to Migrate: Yes! (v%s < v1.0.0)", wailsVersion) + return true, nil + } + checkSpinner.Error("Unable to migrate") + return false, fmt.Errorf("No migration rules for version %s", wailsVersion) +} + +func checkWailsBridge() (string, error) { + checkSpinner.Start("Checking if legacy Wails Bridge present") + + // Check frontend dir is available + if migrateProjectOptions.FrontEnd == nil || + len(migrateProjectOptions.FrontEnd.Dir) == 0 || + !migrateFS.DirExists(migrateProjectOptions.FrontEnd.Dir) { + checkSpinner.Error("Unable to determine frontend directory") + return "", fmt.Errorf("Unable to determine frontend directory") + } + + frontEndDir = migrateProjectOptions.FrontEnd.Dir + + wailsBridgePath, err := filepath.Abs(filepath.Join(".", frontEndDir, "src", "wailsbridge.js")) + if err != nil { + checkSpinner.Error(err.Error()) + return "", err + } + + // If it doesn't exist, return blank string + if !migrateFS.FileExists(wailsBridgePath) { + checkSpinner.Success("Checking if legacy Wails Bridge present: No") + return "", nil + } + + checkSpinner.Success("Checking if legacy Wails Bridge present: Yes") + return wailsBridgePath, nil + +} + +// This function determines if the main.js file using wailsbridge can be auto-updated +func checkMainJS() (bool, error) { + + checkSpinner.Start("Checking if main.js can be migrated") + var err error + + // Check main.js is there + if migrateProjectOptions.FrontEnd == nil || + len(migrateProjectOptions.FrontEnd.Dir) == 0 || + !migrateFS.DirExists(migrateProjectOptions.FrontEnd.Dir) { + checkSpinner.Error("Unable to determine frontend directory") + return false, fmt.Errorf("Unable to determine frontend directory") + } + + frontEndDir = migrateProjectOptions.FrontEnd.Dir + + mainJSFile, err = filepath.Abs(filepath.Join(".", frontEndDir, "src", "main.js")) + if err != nil { + checkSpinner.Error("Unable to find main.js") + return false, err + } + + mainJSContents, err = migrateFS.LoadAsString(mainJSFile) + if err != nil { + checkSpinner.Error("Unable to load main.js") + return false, err + } + + // Check we have a line like: import Bridge from "./wailsbridge"; + if strings.Index(mainJSContents, `import Bridge from "./wailsbridge";`) == -1 { + checkSpinner.Success("Checking if main.js can be migrated: No - Cannot find `import Bridge`") + return false, nil + } + + // Check we have a line like: Bridge.Start(() => { + if strings.Index(mainJSContents, `Bridge.Start(`) == -1 { + checkSpinner.Success("Checking if main.js can be migrated: No - Cannot find `Bridge.Start`") + return false, nil + } + checkSpinner.Success("Checking if main.js can be migrated: Yes") + return true, nil +} + +func getLatestWailsVersion() (*semver.Version, error) { + checkSpinner.Start("Checking GitHub for latest Wails version") + version, err := migrateGithub.GetLatestStableRelease() + if err != nil { + checkSpinner.Error("Checking GitHub for latest Wails version: Failed") + return nil, err + } + + checkSpinner.Successf("Checking GitHub for latest Wails version: v%s", version) + return version.Version, nil +} + +func updateWailsVersion(currentVersion, latestVersion *semver.Version) error { + // Patch go.mod + checkSpinner.Start("Patching go.mod") + + wailsModule := "github.com/wailsapp/wails" + old := fmt.Sprintf("%s v%s", wailsModule, currentVersion) + new := fmt.Sprintf("%s v%s", wailsModule, latestVersion) + + goMod = strings.Replace(goMod, old, new, -1) + err := ioutil.WriteFile(goModFile, []byte(goMod), 0600) + if err != nil { + checkSpinner.Error() + return err + } + + checkSpinner.Success() + return nil +} + +func deleteWailsBridge(bridgeFilename string) error { + // Patch go.mod + checkSpinner.Start("Delete legacy wailsbridge.js") + + err := migrateFS.RemoveFile(bridgeFilename) + if err != nil { + checkSpinner.Error() + return err + } + + checkSpinner.Success() + return nil +} + +func patchMainJS() error { + // Patch main.js + checkSpinner.Start("Patching main.js") + + // Patch import line + oldImportLine := `import Bridge from "./wailsbridge";` + newImportLine := `import * as Wails from "@wailsapp/runtime";` + mainJSContents = strings.Replace(mainJSContents, oldImportLine, newImportLine, -1) + + // Patch Start line + oldStartLine := `Bridge.Start` + newStartLine := `Wails.Init` + mainJSContents = strings.Replace(mainJSContents, oldStartLine, newStartLine, -1) + + err := ioutil.WriteFile(mainJSFile, []byte(mainJSContents), 0600) + if err != nil { + checkSpinner.Error() + return err + } + + checkSpinner.Success() + return nil +} + +func installWailsRuntime() error { + + checkSpinner.Start("Installing @wailsapp/runtime module") + + // Change to the frontend directory + err := os.Chdir(frontEndDir) + if err != nil { + checkSpinner.Error() + return nil + } + + // Determine package manager + packageManager, err := migrateProjectOptions.GetNPMBinaryName() + if err != nil { + checkSpinner.Error() + return nil + } + + switch packageManager { + case cmd.NPM: + // npm install --save @wailsapp/runtime + programHelper.InstallNPMPackage("@wailsapp/runtime", true) + default: + checkSpinner.Error() + return fmt.Errorf("Unknown package manager") + } + + checkSpinner.Success() + return nil +} diff --git a/cmd/wails/2_init.go b/cmd/wails/2_init.go new file mode 100644 index 000000000..eac708fde --- /dev/null +++ b/cmd/wails/2_init.go @@ -0,0 +1,91 @@ +package main + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/leaanthony/spinner" + "github.com/wailsapp/wails/cmd" +) + +func init() { + + projectHelper := cmd.NewProjectHelper() + projectOptions := projectHelper.NewProjectOptions() + commandDescription := `Generates a new Wails project using the given flags. +Any flags that are required and not given will be prompted for.` + build := false + + initCommand := app.Command("init", "Initialises a new Wails project"). + LongDescription(commandDescription). + BoolFlag("f", "Use defaults", &projectOptions.UseDefaults). + StringFlag("dir", "Directory to create project in", &projectOptions.OutputDirectory). + StringFlag("template", "Template name", &projectOptions.Template). + StringFlag("name", "Project name", &projectOptions.Name). + StringFlag("description", "Project description", &projectOptions.Description). + StringFlag("output", "Output binary name", &projectOptions.BinaryName). + BoolFlag("build", "Build project after generating", &build) + + initCommand.Action(func() error { + + logger.PrintSmallBanner("Initialising project") + fmt.Println() + + // Check if the system is initialised + system := cmd.NewSystemHelper() + err := system.CheckInitialised() + if err != nil { + return err + } + + success, err := cmd.CheckDependenciesSilent(logger) + if !success { + return err + } + + // Do we want to just force defaults? + if projectOptions.UseDefaults { + // Use defaults + projectOptions.Defaults() + } else { + err = projectOptions.PromptForInputs() + if err != nil { + return err + } + } + + genSpinner := spinner.NewSpinner() + genSpinner.SetSpinSpeed(50) + genSpinner.Start("Generating project...") + + // Generate the project + err = projectHelper.GenerateProject(projectOptions) + if err != nil { + genSpinner.Error() + return err + } + genSpinner.Success() + if !build { + logger.Yellow("Project '%s' initialised. Run `wails build` to build it.", projectOptions.Name) + return nil + } + + // Build the project + cwd, _ := os.Getwd() + projectDir := filepath.Join(cwd, projectOptions.OutputDirectory) + program := cmd.NewProgramHelper() + buildSpinner := spinner.NewSpinner() + buildSpinner.SetSpinSpeed(50) + buildSpinner.Start("Building project (this may take a while)...") + err = program.RunCommandArray([]string{"wails", "build"}, projectDir) + if err != nil { + buildSpinner.Error(err.Error()) + return err + } + buildSpinner.Success() + logger.Yellow("Project '%s' built in directory '%s'!", projectOptions.Name, projectOptions.OutputDirectory) + + return err + }) +} diff --git a/cmd/wails/4_build.go b/cmd/wails/4_build.go new file mode 100644 index 000000000..65c8adf57 --- /dev/null +++ b/cmd/wails/4_build.go @@ -0,0 +1,210 @@ +package main + +import ( + "fmt" + "log" + "os" + "runtime" + "strings" + + "github.com/leaanthony/spinner" + "github.com/wailsapp/wails/cmd" +) + +// getSupportedPlatforms returns a slice of platform/architecture +// targets that are buildable using the cross-platform 'x' option. +func getSupportedPlatforms() []string { + return []string{ + "darwin/amd64", + "linux/amd64", + "linux/arm-7", + "windows/amd64", + } +} + +func init() { + + var packageApp = false + var forceRebuild = false + var debugMode = false + var usefirebug = false + var gopath = "" + var typescriptFilename = "" + var verbose = false + var platform = "" + var ldflags = "" + var tags = "" + + buildSpinner := spinner.NewSpinner() + buildSpinner.SetSpinSpeed(50) + + commandDescription := `This command will check to ensure all pre-requistes are installed prior to building. If not, it will attempt to install them. Building comprises of a number of steps: install frontend dependencies, build frontend, pack frontend, compile main application.` + initCmd := app.Command("build", "Builds your Wails project"). + LongDescription(commandDescription). + BoolFlag("p", "Package application on successful build", &packageApp). + BoolFlag("f", "Force rebuild of application components", &forceRebuild). + BoolFlag("d", "Build in Debug mode", &debugMode). + BoolFlag("firebug", "Enable firebug console for debug builds", &usefirebug). + BoolFlag("verbose", "Verbose output", &verbose). + StringFlag("t", "Generate Typescript definitions to given file (at runtime)", &typescriptFilename). + StringFlag("ldflags", "Extra options for -ldflags", &ldflags). + StringFlag("gopath", "Specify your GOPATH location. Mounted to /go during cross-compilation.", &gopath). + StringFlag("tags", "Build tags to pass to the go compiler (quoted and space separated)", &tags) + + var b strings.Builder + for _, plat := range getSupportedPlatforms() { + _, err := fmt.Fprintf(&b, " - %s\n", plat) + if err != nil { + log.Fatal(err) + } + } + initCmd.StringFlag("x", + fmt.Sprintf("Cross-compile application to specified platform via xgo\n%s", b.String()), + &platform) + + initCmd.Action(func() error { + + message := "Building Application" + if packageApp { + message = "Packaging Application" + } + if forceRebuild { + message += " (force rebuild)" + } + logger.PrintSmallBanner(message) + fmt.Println() + + // Project options + projectOptions := &cmd.ProjectOptions{} + projectOptions.Verbose = verbose + projectOptions.UseFirebug = usefirebug + + // Check we are in project directory + // Check project.json loads correctly + fs := cmd.NewFSHelper() + err := projectOptions.LoadConfig(fs.Cwd()) + if err != nil { + return fmt.Errorf("unable to find 'project.json'. Please check you are in a Wails project directory") + } + + // Set firebug flag + projectOptions.UseFirebug = usefirebug + + // Check that this platform is supported + if !projectOptions.PlatformSupported() { + logger.Yellow("WARNING: This project is unsupported on %s - it probably won't work!\n Valid platforms: %s\n", runtime.GOOS, strings.Join(projectOptions.Platforms, ", ")) + } + + // Set cross-compile + projectOptions.Platform = runtime.GOOS + if len(platform) > 0 { + supported := false + for _, plat := range getSupportedPlatforms() { + if plat == platform { + supported = true + } + } + if !supported { + return fmt.Errorf("unsupported platform '%s' specified.\nPlease run `wails build -h` to see the supported platform/architecture options", platform) + } + + projectOptions.CrossCompile = true + plat := strings.Split(platform, "/") + projectOptions.Platform = plat[0] + projectOptions.Architecture = plat[1] + } + + // Add ldflags + projectOptions.LdFlags = ldflags + projectOptions.GoPath = gopath + + // Add tags + projectOptions.Tags = tags + + // Validate config + // Check if we have a frontend + err = cmd.ValidateFrontendConfig(projectOptions) + if err != nil { + return err + } + + // Program checker + program := cmd.NewProgramHelper() + + if projectOptions.FrontEnd != nil { + // npm + if !program.IsInstalled("npm") { + return fmt.Errorf("it appears npm is not installed. Please install and run again") + } + } + + // Save project directory + projectDir := fs.Cwd() + + // Install deps + if projectOptions.FrontEnd != nil { + err = cmd.InstallFrontendDeps(projectDir, projectOptions, forceRebuild, "build") + if err != nil { + return err + } + } + + // Move to project directory + err = os.Chdir(projectDir) + if err != nil { + return err + } + + // Install dependencies + err = cmd.InstallGoDependencies(projectOptions.Verbose) + if err != nil { + return err + } + + // Build application + buildMode := cmd.BuildModeProd + if debugMode { + buildMode = cmd.BuildModeDebug + } + + // Save if we wish to dump typescript or not + if typescriptFilename != "" { + projectOptions.SetTypescriptDefsFilename(typescriptFilename) + } + + // Update go.mod if it is out of sync with current version + outofsync, err := cmd.GoModOutOfSync() + if err != nil { + return err + } + gomodVersion, err := cmd.GetWailsVersion() + if err != nil { + return err + } + if outofsync { + syncMessage := fmt.Sprintf("Updating go.mod (Wails version %s => %s)", gomodVersion, cmd.Version) + buildSpinner := spinner.NewSpinner(syncMessage) + buildSpinner.Start() + err := cmd.UpdateGoModVersion() + if err != nil { + buildSpinner.Error(err.Error()) + return err + } + buildSpinner.Success() + } + + err = cmd.BuildApplication(projectOptions.BinaryName, forceRebuild, buildMode, packageApp, projectOptions) + if err != nil { + return err + } + + if projectOptions.Platform == "windows" { + logger.Yellow("*** Please note: Windows builds use mshtml which is only compatible with IE11. For more information, please read https://wails.app/guides/windows/ ***") + } + + logger.Yellow("Awesome! Project '%s' built!", projectOptions.Name) + + return nil + + }) +} diff --git a/cmd/wails/6_serve.go b/cmd/wails/6_serve.go new file mode 100644 index 000000000..6e289685f --- /dev/null +++ b/cmd/wails/6_serve.go @@ -0,0 +1,70 @@ +package main + +import ( + "fmt" + "runtime" + + "github.com/leaanthony/spinner" + "github.com/wailsapp/wails/cmd" +) + +func init() { + + var forceRebuild = false + var verbose = false + buildSpinner := spinner.NewSpinner() + buildSpinner.SetSpinSpeed(50) + + commandDescription := `This command builds then serves your application in bridge mode. Useful for developing your app in a browser.` + initCmd := app.Command("serve", "Run your Wails project in bridge mode"). + LongDescription(commandDescription). + BoolFlag("verbose", "Verbose output", &verbose). + BoolFlag("f", "Force rebuild of application components", &forceRebuild) + + initCmd.Action(func() error { + + message := "Serving Application" + logger.PrintSmallBanner(message) + fmt.Println() + + // Project options + projectOptions := &cmd.ProjectOptions{} + + // Check we are in project directory + // Check project.json loads correctly + fs := cmd.NewFSHelper() + err := projectOptions.LoadConfig(fs.Cwd()) + if err != nil { + return err + } + + // Set project options + projectOptions.Verbose = verbose + projectOptions.Platform = runtime.GOOS + + // Save project directory + projectDir := fs.Cwd() + + // Install the bridge library + err = cmd.InstallBridge(projectDir, projectOptions) + if err != nil { + return err + } + + // Install dependencies + err = cmd.InstallGoDependencies(projectOptions.Verbose) + if err != nil { + return err + } + + buildMode := cmd.BuildModeBridge + err = cmd.BuildApplication(projectOptions.BinaryName, forceRebuild, buildMode, false, projectOptions) + if err != nil { + return err + } + + logger.Yellow("Awesome! Project '%s' built!", projectOptions.Name) + + return cmd.ServeProject(projectOptions, logger) + }) +} diff --git a/cmd/wails/8_update.go b/cmd/wails/8_update.go new file mode 100644 index 000000000..70224aa49 --- /dev/null +++ b/cmd/wails/8_update.go @@ -0,0 +1,164 @@ +package main + +import ( + "fmt" + "log" + "os" + + "github.com/leaanthony/spinner" + "github.com/wailsapp/wails/cmd" +) + +func init() { + + var prereleaseRequired bool + var specificVersion string + + // var forceRebuild = false + checkSpinner := spinner.NewSpinner() + checkSpinner.SetSpinSpeed(50) + + commandDescription := `This command allows you to update your version of Wails.` + updateCmd := app.Command("update", "Update to newer [pre]releases or specific versions"). + LongDescription(commandDescription). + BoolFlag("pre", "Update to latest Prerelease", &prereleaseRequired). + StringFlag("version", "Install a specific version (Overrides other flags)", &specificVersion) + + updateCmd.Action(func() error { + + message := "Checking for updates..." + logger.PrintSmallBanner(message) + fmt.Println() + + // Get versions + checkSpinner.Start(message) + + github := cmd.NewGitHubHelper() + var desiredVersion *cmd.SemanticVersion + var err error + var valid bool + + if len(specificVersion) > 0 { + // Check if this is a valid version + valid, err = github.IsValidTag(specificVersion) + if err == nil { + if !valid { + err = fmt.Errorf("version '%s' is invalid", specificVersion) + } else { + desiredVersion, err = cmd.NewSemanticVersion(specificVersion) + } + } + } else { + if prereleaseRequired { + desiredVersion, err = github.GetLatestPreRelease() + } else { + desiredVersion, err = github.GetLatestStableRelease() + } + } + if err != nil { + checkSpinner.Error(err.Error()) + return err + } + checkSpinner.Success() + fmt.Println() + + fmt.Println(" Current Version : " + cmd.Version) + + if len(specificVersion) > 0 { + fmt.Printf(" Desired Version : v%s\n", desiredVersion) + } else { + if prereleaseRequired { + fmt.Printf(" Latest Prerelease : v%s\n", desiredVersion) + } else { + fmt.Printf(" Latest Release : v%s\n", desiredVersion) + } + } + + return updateToVersion(desiredVersion, len(specificVersion) > 0) + }) +} + +func updateToVersion(targetVersion *cmd.SemanticVersion, force bool) error { + + var targetVersionString = "v" + targetVersion.String() + + // Early exit + if targetVersionString == cmd.Version { + logger.Green("Looks like you're up to date!") + return nil + } + + var desiredVersion string + + if !force { + + compareVersion := cmd.Version + + currentVersion, err := cmd.NewSemanticVersion(compareVersion) + if err != nil { + return err + } + + var success bool + + // Release -> Pre-Release = Massage current version to prerelease format + if targetVersion.IsPreRelease() && currentVersion.IsRelease() { + testVersion, err := cmd.NewSemanticVersion(compareVersion + "-0") + if err != nil { + return err + } + success, _ = targetVersion.IsGreaterThan(testVersion) + } + // Pre-Release -> Release = Massage target version to prerelease format + if targetVersion.IsRelease() && currentVersion.IsPreRelease() { + // We are ok with greater than or equal + mainversion := currentVersion.MainVersion() + targetVersion, err = cmd.NewSemanticVersion(targetVersion.String()) + if err != nil { + return err + } + success, _ = targetVersion.IsGreaterThanOrEqual(mainversion) + } + + // Release -> Release = Standard check + if (targetVersion.IsRelease() && currentVersion.IsRelease()) || + (targetVersion.IsPreRelease() && currentVersion.IsPreRelease()) { + + success, _ = targetVersion.IsGreaterThan(currentVersion) + } + + // Compare + if !success { + logger.Red("The requested version is lower than the current version.") + logger.Red("If this is what you really want to do, use `wails update -version %s`", targetVersionString) + return nil + } + + desiredVersion = "v" + targetVersion.String() + + } else { + desiredVersion = "v" + targetVersion.String() + } + + fmt.Println() + updateSpinner := spinner.NewSpinner() + updateSpinner.SetSpinSpeed(40) + updateSpinner.Start("Installing Wails " + desiredVersion) + + // Run command in non module directory + homeDir, err := os.UserHomeDir() + if err != nil { + log.Fatal("Cannot find home directory! Please file a bug report!") + } + + err = cmd.NewProgramHelper().RunCommandArray([]string{"go", "get", "github.com/wailsapp/wails/cmd/wails@" + desiredVersion}, homeDir) + if err != nil { + updateSpinner.Error(err.Error()) + return err + } + updateSpinner.Success() + fmt.Println() + logger.Green("Wails updated to " + desiredVersion) + + return nil +} diff --git a/cmd/wails/9_issue.go b/cmd/wails/9_issue.go new file mode 100644 index 000000000..a58b2938d --- /dev/null +++ b/cmd/wails/9_issue.go @@ -0,0 +1,127 @@ +package main + +import ( + "fmt" + "io/ioutil" + "net/http" + "net/url" + "os" + "runtime" + "strings" + + "github.com/pkg/browser" + + "github.com/wailsapp/wails/cmd" +) + +func init() { + + commandDescription := `Generates an issue in Github using the given title, description and system report.` + + initCommand := app.Command("issue", "Generates an issue in Github"). + LongDescription(commandDescription) + + initCommand.Action(func() error { + + logger.PrintSmallBanner("Generate Issue") + fmt.Println() + message := `Thanks for taking the time to submit an issue! + +To help you in this process, we will ask for some information, add Go/Wails details automatically, then prepare the issue for your editing and submission. +` + + logger.Yellow(message) + + title := cmd.Prompt("Issue Title") + description := cmd.Prompt("Issue Description") + + var str strings.Builder + + gomodule, exists := os.LookupEnv("GO111MODULE") + if !exists { + gomodule = "(Not Set)" + } + + // get version numbers for GCC, node & npm + program := cmd.NewProgramHelper() + // string helpers + var gccVersion, nodeVersion, npmVersion string + + // choose between OS (mac,linux,win) + switch runtime.GOOS { + case "darwin": + gcc := program.FindProgram("gcc") + if gcc != nil { + stdout, _, _, _ := gcc.Run("-dumpversion") + gccVersion = strings.TrimSpace(stdout) + } + case "linux": + // for linux we have to collect + // the distribution name + distroInfo := cmd.GetLinuxDistroInfo() + linuxDB := cmd.NewLinuxDB() + distro := linuxDB.GetDistro(distroInfo.ID) + release := distro.GetRelease(distroInfo.Release) + gccVersionCommand := release.GccVersionCommand + + gcc := program.FindProgram("gcc") + if gcc != nil { + stdout, _, _, _ := gcc.Run(gccVersionCommand) + gccVersion = strings.TrimSpace(stdout) + } + case "windows": + gcc := program.FindProgram("gcc") + if gcc != nil { + stdout, _, _, _ := gcc.Run("-dumpversion") + gccVersion = strings.TrimSpace(stdout) + } + } + + npm := program.FindProgram("npm") + if npm != nil { + stdout, _, _, _ := npm.Run("--version") + npmVersion = stdout + npmVersion = npmVersion[:len(npmVersion)-1] + npmVersion = strings.TrimSpace(npmVersion) + } + + node := program.FindProgram("node") + if node != nil { + stdout, _, _, _ := node.Run("--version") + nodeVersion = stdout + nodeVersion = nodeVersion[:len(nodeVersion)-1] + } + + str.WriteString("\n| Name | Value |\n| ----- | ----- |\n") + str.WriteString(fmt.Sprintf("| Wails Version | %s |\n", cmd.Version)) + str.WriteString(fmt.Sprintf("| Go Version | %s |\n", runtime.Version())) + str.WriteString(fmt.Sprintf("| Platform | %s |\n", runtime.GOOS)) + str.WriteString(fmt.Sprintf("| Arch | %s |\n", runtime.GOARCH)) + str.WriteString(fmt.Sprintf("| GO111MODULE | %s |\n", gomodule)) + str.WriteString(fmt.Sprintf("| GCC | %s |\n", gccVersion)) + str.WriteString(fmt.Sprintf("| Npm | %s |\n", npmVersion)) + str.WriteString(fmt.Sprintf("| Node | %s |\n", nodeVersion)) + + fmt.Println() + fmt.Println("Processing template and preparing for upload.") + + // Grab issue template + resp, err := http.Get("https://raw.githubusercontent.com/wailsapp/wails/master/.github/ISSUE_TEMPLATE/bug_report.md") + if err != nil { + logger.Red("Unable to read in issue template. Are you online?") + os.Exit(1) + } + defer resp.Body.Close() + template, _ := ioutil.ReadAll(resp.Body) + body := string(template) + body = "**Description**\n" + (strings.Split(body, "**Description**")[1]) + fullURL := "https://github.com/wailsapp/wails/issues/new?" + body = strings.Replace(body, "A clear and concise description of what the bug is.", description, -1) + body = strings.Replace(body, "Please provide your platform, GO version and variables, etc", str.String(), -1) + params := "title=" + title + "&body=" + body + + fmt.Println("Opening browser to file issue.") + browser.OpenURL(fullURL + url.PathEscape(params)) + return nil + }) +} diff --git a/cmd/wails/main.go b/cmd/wails/main.go new file mode 100644 index 000000000..bbcc94b32 --- /dev/null +++ b/cmd/wails/main.go @@ -0,0 +1,26 @@ +package main + +import ( + "os" + "os/exec" + + "github.com/wailsapp/wails/cmd" +) + +// Create Logger +var logger = cmd.NewLogger() + +// Create main app +var app = cmd.NewCli("wails", "A cli tool for building Wails applications.") + +// Main! +func main() { + err := app.Run() + if err != nil { + logger.Error(err.Error()) + if exitErr, ok := err.(*exec.ExitError); ok { + os.Exit(exitErr.ExitCode()) + } + os.Exit(1) + } +} diff --git a/cmd/windows.go b/cmd/windows.go new file mode 100644 index 000000000..1a85f13c1 --- /dev/null +++ b/cmd/windows.go @@ -0,0 +1,20 @@ +//go:build windows +// +build windows + +package cmd + +import ( + "os" + + "golang.org/x/sys/windows" +) + +// Credit: https://stackoverflow.com/a/52579002 + +func init() { + stdout := windows.Handle(os.Stdout.Fd()) + var originalMode uint32 + + _ = windows.GetConsoleMode(stdout, &originalMode) + _ = windows.SetConsoleMode(stdout, originalMode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING) +} diff --git a/cmd/windres.bat b/cmd/windres.bat new file mode 100644 index 000000000..1ce33a4a8 --- /dev/null +++ b/cmd/windres.bat @@ -0,0 +1 @@ +windres.exe -o %1 %2 \ No newline at end of file diff --git a/config.go b/config.go new file mode 100644 index 000000000..0fc80c255 --- /dev/null +++ b/config.go @@ -0,0 +1,210 @@ +package wails + +import ( + "net/url" + "strings" + + "github.com/wailsapp/wails/runtime" +) + +// AppConfig is the configuration structure used when creating a Wails App object +type AppConfig struct { + // The width and height of your application in pixels + Width, Height int + + // The title to put in the title bar + Title string + + // The HTML your app should use. If you leave it blank, a default will be used: + //
+ HTML string + + // The Javascript your app should use. Normally this should be generated by a bundler. + JS string + + // The CSS your app should use. Normally this should be generated by a bundler. + CSS string + + // The colour of your window. Can take "#fff", "rgb(255,255,255)", "rgba(255,255,255,1)" formats + Colour string + + // Indicates whether your app should be resizable + Resizable bool + + // Minimum width of a resizable window. If set, MinHeight should also be set. + MinWidth int + + // Minimum height of a resizable window. If set, MinWidth should also be set. + MinHeight int + + // Maximum width of a resizable window. If set, MaxHeight should also be set. + MaxWidth int + + // Maximum height of a resizable window. If set, MaxWidth should also be set. + MaxHeight int + + // Indicated if the devtools should be disabled + DisableInspector bool +} + +// GetWidth returns the desired width +func (a *AppConfig) GetWidth() int { + return a.Width +} + +// GetHeight returns the desired height +func (a *AppConfig) GetHeight() int { + return a.Height +} + +// GetTitle returns the desired window title +func (a *AppConfig) GetTitle() string { + return a.Title +} + +// GetHTML returns the default HTML +func (a *AppConfig) GetHTML() string { + if len(a.HTML) > 0 { + a.HTML = url.QueryEscape(a.HTML) + a.HTML = "data:text/html," + strings.ReplaceAll(a.HTML, "+", "%20") + a.HTML = strings.ReplaceAll(a.HTML, "%3D", "=") + } + return a.HTML +} + +// GetResizable returns true if the window should be resizable +func (a *AppConfig) GetResizable() bool { + return a.Resizable +} + +// GetMinWidth returns the minimum width of the window +func (a *AppConfig) GetMinWidth() int { + return a.MinWidth +} + +// GetMinHeight returns the minimum height of the window +func (a *AppConfig) GetMinHeight() int { + return a.MinHeight +} + +// GetMaxWidth returns the maximum width of the window +func (a *AppConfig) GetMaxWidth() int { + return a.MaxWidth +} + +// GetMaxHeight returns the maximum height of the window +func (a *AppConfig) GetMaxHeight() int { + return a.MaxHeight +} + +// GetDisableInspector returns true if the inspector should be disabled +func (a *AppConfig) GetDisableInspector() bool { + return a.DisableInspector +} + +// GetColour returns the colour +func (a *AppConfig) GetColour() string { + return a.Colour +} + +// GetCSS returns the user CSS +func (a *AppConfig) GetCSS() string { + return a.CSS +} + +// GetJS returns the user Javascript +func (a *AppConfig) GetJS() string { + return a.JS +} + +func (a *AppConfig) merge(in *AppConfig) error { + if in.CSS != "" { + a.CSS = in.CSS + } + if in.Title != "" { + a.Title = runtime.ProcessEncoding(in.Title) + } + + if in.Colour != "" { + a.Colour = in.Colour + } + + if in.HTML != "" { + a.HTML = in.HTML + } + + if in.JS != "" { + a.JS = in.JS + } + + if in.HTML != "" { + a.HTML = in.HTML + } + + if in.Width != 0 { + a.Width = in.Width + } + if in.Height != 0 { + a.Height = in.Height + } + + if in.MinWidth != 0 { + a.MinWidth = in.MinWidth + } + + if in.MinHeight != 0 { + a.MinHeight = in.MinHeight + } + + if in.MaxWidth != 0 { + a.MaxWidth = in.MaxWidth + } + + if in.MaxHeight != 0 { + a.MaxHeight = in.MaxHeight + } + + a.Resizable = in.Resizable + a.DisableInspector = in.DisableInspector + + return nil +} + +// Creates the default configuration +func newConfig(userConfig *AppConfig) (*AppConfig, error) { + result := &AppConfig{ + Width: 800, + Height: 600, + Resizable: true, + MinWidth: -1, + MinHeight: -1, + MaxWidth: -1, + MaxHeight: -1, + Title: "My Wails App", + Colour: "", + HTML: defaultHTML, + } + + if userConfig != nil { + err := result.merge(userConfig) + if err != nil { + return nil, err + } + } + + return result, nil +} + +var defaultHTML = ` + + + + + + + + +
+ + +` diff --git a/go.mod b/go.mod new file mode 100644 index 000000000..4d289fe39 --- /dev/null +++ b/go.mod @@ -0,0 +1,31 @@ +module github.com/wailsapp/wails + +require ( + github.com/Masterminds/semver v1.4.2 + github.com/abadojack/whatlanggo v1.0.1 + github.com/fatih/color v1.7.0 + github.com/go-playground/colors v1.2.0 + github.com/gorilla/websocket v1.4.1 + github.com/jackmordaunt/icns v1.0.0 + github.com/kennygrant/sanitize v1.2.4 + github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect + github.com/leaanthony/slicer v1.4.0 + github.com/leaanthony/spinner v0.5.3 + github.com/mattn/go-colorable v0.1.1 // indirect + github.com/mattn/go-isatty v0.0.7 // indirect + github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect + github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4 + github.com/pkg/errors v0.8.1 // indirect + github.com/sirupsen/logrus v1.8.1 + github.com/stretchr/objx v0.1.1 // indirect + github.com/stretchr/testify v1.3.0 // indirect + github.com/syossan27/tebata v0.0.0-20180602121909-b283fe4bc5ba + golang.org/x/image v0.0.0-20200430140353-33d19683fad8 + golang.org/x/net v0.0.0-20200625001655-4c5254603344 // indirect + golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 + golang.org/x/text v0.3.0 + gopkg.in/AlecAivazis/survey.v1 v1.8.4 + gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22 +) + +go 1.16 diff --git a/go.sum b/go.sum new file mode 100644 index 000000000..79a777e39 --- /dev/null +++ b/go.sum @@ -0,0 +1,94 @@ +github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc= +github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw= +github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc= +github.com/abadojack/whatlanggo v1.0.1 h1:19N6YogDnf71CTHm3Mp2qhYfkRdyvbgwWdd2EPxJRG4= +github.com/abadojack/whatlanggo v1.0.1/go.mod h1:66WiQbSbJBIlOZMsvbKe5m6pzQovxCH9B/K8tQB2uoc= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/go-playground/colors v1.2.0 h1:0EdjTXKrr2g1L/LQTYtIqabeHpZuGZz1U4osS1T8+5M= +github.com/go-playground/colors v1.2.0/go.mod h1:miw1R2JIE19cclPxsXqNdzLZsk4DP4iF+m88bRc7kfM= +github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174 h1:WlZsjVhE8Af9IcZDGgJGQpNflI3+MJSBhsgT5PCtzBQ= +github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A= +github.com/jackmordaunt/icns v1.0.0 h1:RYSxplerf/l/DUd09AHtITwckkv/mqjVv4DjYdPmAMQ= +github.com/jackmordaunt/icns v1.0.0/go.mod h1:7TTQVEuGzVVfOPPlLNHJIkzA6CoV7aH1Dv9dW351oOo= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/kennygrant/sanitize v1.2.4 h1:gN25/otpP5vAsO2djbMhF/LQX6R7+O1TB4yv8NzpJ3o= +github.com/kennygrant/sanitize v1.2.4/go.mod h1:LGsjYYtgxbetdg5owWB2mpgUL6e2nfw2eObZ0u0qvak= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/leaanthony/slicer v1.4.0 h1:Q9u4w+UBU4WHjXnEDdz+eRLMKF/rnyosRBiqULnc1J8= +github.com/leaanthony/slicer v1.4.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY= +github.com/leaanthony/spinner v0.5.3 h1:IMTvgdQCec5QA4qRy0wil4XsRP+QcG1OwLWVK/LPZ5Y= +github.com/leaanthony/spinner v0.5.3/go.mod h1:oHlrvWicr++CVV7ALWYi+qHk/XNA91D9IJ48IqmpVUo= +github.com/leaanthony/synx v0.1.0 h1:R0lmg2w6VMb8XcotOwAe5DLyzwjLrskNkwU7LLWsyL8= +github.com/leaanthony/synx v0.1.0/go.mod h1:Iz7eybeeG8bdq640iR+CwYb8p+9EOsgMWghkSRyZcqs= +github.com/leaanthony/wincursor v0.1.0 h1:Dsyp68QcF5cCs65AMBmxoYNEm0n8K7mMchG6a8fYxf8= +github.com/leaanthony/wincursor v0.1.0/go.mod h1:7TVwwrzSH/2Y9gLOGH+VhA+bZhoWXBRgbGNTMk+yimE= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc= +github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= +github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4 h1:49lOXmGaUpV9Fz3gd7TFZY106KVlPVa5jcYD1gaQf98= +github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/syossan27/tebata v0.0.0-20180602121909-b283fe4bc5ba h1:2DHfQOxcpWdGf5q5IzCUFPNvRX9Icf+09RvQK2VnJq0= +github.com/syossan27/tebata v0.0.0-20180602121909-b283fe4bc5ba/go.mod h1:iLnlXG2Pakcii2CU0cbY07DRCSvpWNa7nFxtevhOChk= +golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/image v0.0.0-20200430140353-33d19683fad8 h1:6WW6V3x1P/jokJBpRQYUJnMHRP6isStQwCozxnU7XQw= +golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/sys v0.0.0-20180606202747-9527bec2660b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c h1:UIcGWL6/wpCfyGuJnRFJRurA+yj8RrW7Q6x2YMCXt6c= +golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 h1:2B5p2L5IfGiD7+b9BOoRMC6DgObAVZV+Fsp050NqXik= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/AlecAivazis/survey.v1 v1.8.4 h1:10xXXN3wgIhPheb5NI58zFgZv32Ana7P3Tl4shW+0Qc= +gopkg.in/AlecAivazis/survey.v1 v1.8.4/go.mod h1:iBNOmqKz/NUbZx3bA+4hAGLRC7fSK7tgtVDT4tB22XA= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22 h1:0efs3hwEZhFKsCoP8l6dDB1AZWMgnEl3yWXWRZTOaEA= +gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/jetbrains-grayscale.png b/jetbrains-grayscale.png new file mode 100644 index 000000000..c5bf0ab63 Binary files /dev/null and b/jetbrains-grayscale.png differ diff --git a/lib/binding/function.go b/lib/binding/function.go new file mode 100644 index 000000000..9a41f0e79 --- /dev/null +++ b/lib/binding/function.go @@ -0,0 +1,170 @@ +package binding + +import ( + "bytes" + "encoding/json" + "fmt" + "reflect" + "runtime" + "strings" + + "github.com/wailsapp/wails/lib/logger" +) + +type boundFunction struct { + fullName string + function reflect.Value + functionType reflect.Type + inputs []reflect.Type + returnTypes []reflect.Type + log *logger.CustomLogger + hasErrorReturnType bool +} + +// Creates a new bound function based on the given method + type +func newBoundFunction(object interface{}) (*boundFunction, error) { + + objectValue := reflect.ValueOf(object) + objectType := reflect.TypeOf(object) + + name := runtime.FuncForPC(objectValue.Pointer()).Name() + if strings.Contains(name, "/") { + parts := strings.Split(name, "/") + name = parts[len(parts)-1] + } + + result := &boundFunction{ + fullName: name, + function: objectValue, + functionType: objectType, + log: logger.NewCustomLogger(name), + } + + err := result.processParameters() + + return result, err +} + +func (b *boundFunction) processParameters() error { + + // Param processing + functionType := b.functionType + + // Input parameters + inputParamCount := functionType.NumIn() + if inputParamCount > 0 { + b.inputs = make([]reflect.Type, inputParamCount) + // We start at 1 as the first param is the struct + for index := 0; index < inputParamCount; index++ { + param := functionType.In(index) + name := param.Name() + kind := param.Kind() + b.inputs[index] = param + typ := param + index := index + b.log.DebugFields("Input param", logger.Fields{ + "index": index, + "name": name, + "kind": kind, + "typ": typ, + }) + } + } + + // Process return/output declarations + returnParamsCount := functionType.NumOut() + // Guard against bad number of return types + switch returnParamsCount { + case 0: + case 1: + // Check if it's an error type + param := functionType.Out(0) + paramName := param.Name() + if paramName == "error" { + b.hasErrorReturnType = true + } + // Save return type + b.returnTypes = append(b.returnTypes, param) + case 2: + // Check the second return type is an error + secondParam := functionType.Out(1) + secondParamName := secondParam.Name() + if secondParamName != "error" { + return fmt.Errorf("last return type of method '%s' must be an error (got %s)", b.fullName, secondParamName) + } + + // Check the second return type is an error + firstParam := functionType.Out(0) + firstParamName := firstParam.Name() + if firstParamName == "error" { + return fmt.Errorf("first return type of method '%s' must not be an error", b.fullName) + } + b.hasErrorReturnType = true + + // Save return types + b.returnTypes = append(b.returnTypes, firstParam) + b.returnTypes = append(b.returnTypes, secondParam) + + default: + return fmt.Errorf("cannot register method '%s' with %d return parameters. Please use up to 2", b.fullName, returnParamsCount) + } + + return nil +} + +// call the method with the given data +func (b *boundFunction) call(data string) ([]reflect.Value, error) { + + // The data will be an array of values so we will decode the + // input data into + var jsArgs []interface{} + d := json.NewDecoder(bytes.NewBufferString(data)) + // d.UseNumber() + err := d.Decode(&jsArgs) + if err != nil { + return nil, fmt.Errorf("Invalid data passed to method call: %s", err.Error()) + } + + // Check correct number of inputs + if len(jsArgs) != len(b.inputs) { + return nil, fmt.Errorf("Invalid number of parameters given to %s. Expected %d but got %d", b.fullName, len(b.inputs), len(jsArgs)) + } + + // Set up call + args := make([]reflect.Value, len(b.inputs)) + for index := 0; index < len(b.inputs); index++ { + + // Set the input values + value, err := b.setInputValue(index, b.inputs[index], jsArgs[index]) + if err != nil { + return nil, err + } + args[index] = value + } + b.log.Debugf("Unmarshalled Args: %+v\n", jsArgs) + b.log.Debugf("Converted Args: %+v\n", args) + results := b.function.Call(args) + + b.log.Debugf("results = %+v", results) + return results, nil +} + +// Attempts to set the method input for parameter with the given value +func (b *boundFunction) setInputValue(index int, typ reflect.Type, val interface{}) (result reflect.Value, err error) { + + // Catch type conversion panics thrown by convert + defer func() { + if r := recover(); r != nil { + // Modify error + err = fmt.Errorf("%s for parameter %d of function %s", r.(string)[23:], index+1, b.fullName) + } + }() + + // Translate javascript null values + if val == nil { + result = reflect.Zero(typ) + } else { + result = reflect.ValueOf(val).Convert(typ) + } + return result, err +} diff --git a/lib/binding/internal.go b/lib/binding/internal.go new file mode 100644 index 000000000..ef6cf4341 --- /dev/null +++ b/lib/binding/internal.go @@ -0,0 +1,71 @@ +package binding + +import ( + "fmt" + "strings" + + "github.com/wailsapp/wails/lib/logger" + "github.com/wailsapp/wails/lib/messages" + "github.com/wailsapp/wails/runtime" +) + +type internalMethods struct { + log *logger.CustomLogger + browser *runtime.Browser +} + +func newInternalMethods() *internalMethods { + return &internalMethods{ + log: logger.NewCustomLogger("InternalCall"), + browser: runtime.NewBrowser(), + } +} + +func (i *internalMethods) processCall(callData *messages.CallData) (interface{}, error) { + if !strings.HasPrefix(callData.BindingName, ".wails.") { + return nil, fmt.Errorf("Invalid call signature '%s'", callData.BindingName) + } + + // Strip prefix + var splitCall = strings.Split(callData.BindingName, ".")[2:] + if len(splitCall) != 2 { + return nil, fmt.Errorf("Invalid call signature '%s'", callData.BindingName) + } + + group := splitCall[0] + switch group { + case "Browser": + return i.processBrowserCommand(splitCall[1], callData.Data) + default: + return nil, fmt.Errorf("Unknown internal command group '%s'", group) + } +} + +func (i *internalMethods) processBrowserCommand(command string, data interface{}) (interface{}, error) { + switch command { + case "OpenURL": + url := data.(string) + // Strip string quotes. Credit: https://stackoverflow.com/a/44222648 + if url[0] == '"' { + url = url[1:] + } + if i := len(url) - 1; url[i] == '"' { + url = url[:i] + } + i.log.Debugf("Calling Browser.OpenURL with '%s'", url) + return nil, i.browser.OpenURL(url) + case "OpenFile": + filename := data.(string) + // Strip string quotes. Credit: https://stackoverflow.com/a/44222648 + if filename[0] == '"' { + filename = filename[1:] + } + if i := len(filename) - 1; filename[i] == '"' { + filename = filename[:i] + } + i.log.Debugf("Calling Browser.OpenFile with '%s'", filename) + return nil, i.browser.OpenFile(filename) + default: + return nil, fmt.Errorf("Unknown Browser command '%s'", command) + } +} diff --git a/lib/binding/manager.go b/lib/binding/manager.go new file mode 100644 index 000000000..e721fc213 --- /dev/null +++ b/lib/binding/manager.go @@ -0,0 +1,372 @@ +package binding + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + "reflect" + "strings" + "unicode" + + "github.com/wailsapp/wails/lib/interfaces" + "github.com/wailsapp/wails/lib/logger" + "github.com/wailsapp/wails/lib/messages" +) + +var typescriptDefinitionFilename = "" + +// Manager handles method binding +type Manager struct { + methods map[string]*boundMethod + functions map[string]*boundFunction + internalMethods *internalMethods + initMethods []*boundMethod + shutdownMethods []*boundMethod + log *logger.CustomLogger + renderer interfaces.Renderer + runtime interfaces.Runtime // The runtime object to pass to bound structs + objectsToBind []interface{} + bindPackageNames bool // Package name should be considered when binding + structList map[string][]string // structList["mystruct"] = []string{"Method1", "Method2"} +} + +// NewManager creates a new Manager struct +func NewManager() interfaces.BindingManager { + + result := &Manager{ + methods: make(map[string]*boundMethod), + functions: make(map[string]*boundFunction), + log: logger.NewCustomLogger("Bind"), + internalMethods: newInternalMethods(), + structList: make(map[string][]string), + } + return result +} + +// BindPackageNames sets a flag to indicate package names should be considered when binding +func (b *Manager) BindPackageNames() { + b.bindPackageNames = true +} + +// Start the binding manager +func (b *Manager) Start(renderer interfaces.Renderer, runtime interfaces.Runtime) error { + b.log.Info("Starting") + b.renderer = renderer + b.runtime = runtime + err := b.initialise() + if err != nil { + b.log.Errorf("Binding error: %s", err.Error()) + return err + } + err = b.callWailsInitMethods() + return err +} + +func (b *Manager) initialise() error { + + var err error + // var binding *boundMethod + + b.log.Info("Binding Go Functions/Methods") + + // Create bindings for objects + for _, object := range b.objectsToBind { + + // Safeguard against nils + if object == nil { + return fmt.Errorf("attempted to bind nil object") + } + + // Determine kind of object + objectType := reflect.TypeOf(object) + objectKind := objectType.Kind() + + switch objectKind { + case reflect.Ptr: + err = b.bindMethod(object) + case reflect.Func: + // spew.Dump(result.objectType.String()) + err = b.bindFunction(object) + default: + err = fmt.Errorf("cannot bind object of type '%s'", objectKind.String()) + } + + // Return error if set + if err != nil { + return err + } + } + + // If we wish to generate a typescript definition file... + if typescriptDefinitionFilename != "" { + err := b.generateTypescriptDefinitions() + if err != nil { + return err + } + } + return nil +} + +// Generate typescript +func (b *Manager) generateTypescriptDefinitions() error { + + var output strings.Builder + + for structname, methodList := range b.structList { + structname = strings.SplitN(structname, ".", 2)[1] + output.WriteString(fmt.Sprintf("interface %s {\n", structname)) + for _, method := range methodList { + output.WriteString(fmt.Sprintf("\t%s(...args : any[]):Promise\n", method)) + } + output.WriteString("}\n") + } + + output.WriteString("\n") + output.WriteString("interface Backend {\n") + + for structname := range b.structList { + structname = strings.SplitN(structname, ".", 2)[1] + output.WriteString(fmt.Sprintf("\t%[1]s: %[1]s\n", structname)) + } + output.WriteString("}\n") + + globals := ` +declare global { + interface Window { + backend: Backend; + } +} +export {};` + output.WriteString(globals) + + b.log.Info("Written Typescript file: " + typescriptDefinitionFilename) + + dir := filepath.Dir(typescriptDefinitionFilename) + os.MkdirAll(dir, 0755) + return ioutil.WriteFile(typescriptDefinitionFilename, []byte(output.String()), 0755) +} + +// bind the given struct method +func (b *Manager) bindMethod(object interface{}) error { + + objectType := reflect.TypeOf(object) + baseName := objectType.String() + + // Strip pointer if there + if baseName[0] == '*' { + baseName = baseName[1:] + } + + b.log.Debugf("Processing struct: %s", baseName) + + // Calc actual name + actualName := strings.TrimPrefix(baseName, "main.") + if b.structList[actualName] == nil { + b.structList[actualName] = []string{} + } + + // Iterate over method definitions + for i := 0; i < objectType.NumMethod(); i++ { + + // Get method definition + methodDef := objectType.Method(i) + methodName := methodDef.Name + fullMethodName := baseName + "." + methodName + method := reflect.ValueOf(object).MethodByName(methodName) + + b.structList[actualName] = append(b.structList[actualName], methodName) + + // Skip unexported methods + if !unicode.IsUpper([]rune(methodName)[0]) { + continue + } + + // Create a new boundMethod + newMethod, err := newBoundMethod(methodName, fullMethodName, method, objectType) + if err != nil { + return err + } + + // Check if it's a wails init function + if newMethod.isWailsInit { + b.log.Debugf("Detected WailsInit function: %s", fullMethodName) + b.initMethods = append(b.initMethods, newMethod) + } else if newMethod.isWailsShutdown { + b.log.Debugf("Detected WailsShutdown function: %s", fullMethodName) + b.shutdownMethods = append(b.shutdownMethods, newMethod) + } else { + // Save boundMethod + b.log.Infof("Bound Method: %s()", fullMethodName) + b.methods[fullMethodName] = newMethod + + // Inform renderer of new binding + b.renderer.NewBinding(fullMethodName) + } + } + + return nil +} + +// bind the given function object +func (b *Manager) bindFunction(object interface{}) error { + + newFunction, err := newBoundFunction(object) + if err != nil { + return err + } + + // Save method + b.log.Infof("Bound Function: %s()", newFunction.fullName) + b.functions[newFunction.fullName] = newFunction + + // Register with Renderer + b.renderer.NewBinding(newFunction.fullName) + + return nil +} + +// Bind saves the given object to be bound at start time +func (b *Manager) Bind(object interface{}) { + // Store binding + b.objectsToBind = append(b.objectsToBind, object) +} + +func (b *Manager) processInternalCall(callData *messages.CallData) (interface{}, error) { + // Strip prefix + return b.internalMethods.processCall(callData) +} + +func (b *Manager) processFunctionCall(callData *messages.CallData) (interface{}, error) { + // Return values + var result []reflect.Value + var err error + + function := b.functions[callData.BindingName] + if function == nil { + return nil, fmt.Errorf("Invalid function name '%s'", callData.BindingName) + } + result, err = function.call(callData.Data) + if err != nil { + return nil, err + } + + // Do we have an error return type? + if function.hasErrorReturnType { + // We do - last result is an error type + // Check if the last result was nil + b.log.Debugf("# of return types: %d", len(function.returnTypes)) + b.log.Debugf("# of results: %d", len(result)) + errorResult := result[len(function.returnTypes)-1] + if !errorResult.IsNil() { + // It wasn't - we have an error + return nil, errorResult.Interface().(error) + } + } + // fmt.Printf("result = '%+v'\n", result) + if len(result) > 0 { + return result[0].Interface(), nil + } + return nil, nil +} + +func (b *Manager) processMethodCall(callData *messages.CallData) (interface{}, error) { + // Return values + var result []reflect.Value + var err error + + // do we have this method? + method := b.methods[callData.BindingName] + if method == nil { + return nil, fmt.Errorf("Invalid method name '%s'", callData.BindingName) + } + + result, err = method.call(callData.Data) + if err != nil { + return nil, err + } + + // Do we have an error return type? + if method.hasErrorReturnType { + // We do - last result is an error type + // Check if the last result was nil + b.log.Debugf("# of return types: %d", len(method.returnTypes)) + b.log.Debugf("# of results: %d", len(result)) + errorResult := result[len(method.returnTypes)-1] + if !errorResult.IsNil() { + // It wasn't - we have an error + return nil, errorResult.Interface().(error) + } + } + if result != nil { + return result[0].Interface(), nil + } + return nil, nil +} + +// ProcessCall processes the given call request +func (b *Manager) ProcessCall(callData *messages.CallData) (result interface{}, err error) { + b.log.Debugf("Wanting to call %s", callData.BindingName) + + // Determine if this is function call or method call by the number of + // dots in the binding name + dotCount := 0 + for _, character := range callData.BindingName { + if character == '.' { + dotCount++ + } + } + + // We need to catch reflect related panics and return + // a decent error message + // TODO: DEBUG THIS! + + defer func() { + if r := recover(); r != nil { + err = fmt.Errorf("%s", r.(string)) + } + }() + + switch dotCount { + case 1: + result, err = b.processFunctionCall(callData) + case 2: + result, err = b.processMethodCall(callData) + case 3: + result, err = b.processInternalCall(callData) + default: + result = nil + err = fmt.Errorf("Invalid binding name '%s'", callData.BindingName) + } + return +} + +// callWailsInitMethods calls all of the WailsInit methods that were +// registered with the runtime object +func (b *Manager) callWailsInitMethods() error { + // Create reflect value for runtime object + runtimeValue := reflect.ValueOf(b.runtime) + params := []reflect.Value{runtimeValue} + + // Iterate initMethods + for _, initMethod := range b.initMethods { + // Call + result := initMethod.method.Call(params) + // Check errors + err := result[0].Interface() + if err != nil { + return err.(error) + } + } + return nil +} + +// Shutdown the binding manager +func (b *Manager) Shutdown() { + b.log.Debug("Shutdown called") + for _, method := range b.shutdownMethods { + b.log.Debugf("Calling Shutdown for method: %s", method.fullName) + method.call("[]") + } + b.log.Debug("Shutdown complete") +} diff --git a/lib/binding/method.go b/lib/binding/method.go new file mode 100644 index 000000000..9a0a32603 --- /dev/null +++ b/lib/binding/method.go @@ -0,0 +1,236 @@ +package binding + +import ( + "bytes" + "encoding/json" + "fmt" + "reflect" + + "github.com/wailsapp/wails/lib/logger" +) + +type boundMethod struct { + Name string + fullName string + method reflect.Value + inputs []reflect.Type + returnTypes []reflect.Type + log *logger.CustomLogger + hasErrorReturnType bool // Indicates if there is an error return type + isWailsInit bool + isWailsShutdown bool +} + +// Creates a new bound method based on the given method + type +func newBoundMethod(name string, fullName string, method reflect.Value, objectType reflect.Type) (*boundMethod, error) { + result := &boundMethod{ + Name: name, + method: method, + fullName: fullName, + } + + // Setup logger + result.log = logger.NewCustomLogger(result.fullName) + + // Check if Parameters are valid + err := result.processParameters() + + // Are we a WailsInit method? + if result.Name == "WailsInit" { + err = result.processWailsInit() + } + + // Are we a WailsShutdown method? + if result.Name == "WailsShutdown" { + err = result.processWailsShutdown() + } + + return result, err +} + +func (b *boundMethod) processParameters() error { + + // Param processing + methodType := b.method.Type() + + // Input parameters + inputParamCount := methodType.NumIn() + if inputParamCount > 0 { + b.inputs = make([]reflect.Type, inputParamCount) + // We start at 1 as the first param is the struct + for index := 0; index < inputParamCount; index++ { + param := methodType.In(index) + name := param.Name() + kind := param.Kind() + b.inputs[index] = param + typ := param + index := index + b.log.DebugFields("Input param", logger.Fields{ + "index": index, + "name": name, + "kind": kind, + "typ": typ, + }) + } + } + + // Process return/output declarations + returnParamsCount := methodType.NumOut() + // Guard against bad number of return types + switch returnParamsCount { + case 0: + case 1: + // Check if it's an error type + param := methodType.Out(0) + paramName := param.Name() + if paramName == "error" { + b.hasErrorReturnType = true + } + // Save return type + b.returnTypes = append(b.returnTypes, param) + case 2: + // Check the second return type is an error + secondParam := methodType.Out(1) + secondParamName := secondParam.Name() + if secondParamName != "error" { + return fmt.Errorf("last return type of method '%s' must be an error (got %s)", b.Name, secondParamName) + } + + // Check the second return type is an error + firstParam := methodType.Out(0) + firstParamName := firstParam.Name() + if firstParamName == "error" { + return fmt.Errorf("first return type of method '%s' must not be an error", b.Name) + } + b.hasErrorReturnType = true + + // Save return types + b.returnTypes = append(b.returnTypes, firstParam) + b.returnTypes = append(b.returnTypes, secondParam) + + default: + return fmt.Errorf("cannot register method '%s' with %d return parameters. Please use up to 2", b.Name, returnParamsCount) + } + + return nil +} + +// call the method with the given data +func (b *boundMethod) call(data string) ([]reflect.Value, error) { + + // The data will be an array of values so we will decode the + // input data into + var jsArgs []interface{} + d := json.NewDecoder(bytes.NewBufferString(data)) + // d.UseNumber() + err := d.Decode(&jsArgs) + if err != nil { + return nil, fmt.Errorf("Invalid data passed to method call: %s", err.Error()) + } + + // Check correct number of inputs + if len(jsArgs) != len(b.inputs) { + return nil, fmt.Errorf("Invalid number of parameters given to %s. Expected %d but got %d", b.fullName, len(b.inputs), len(jsArgs)) + } + + // Set up call + args := make([]reflect.Value, len(b.inputs)) + for index := 0; index < len(b.inputs); index++ { + + // Set the input values + value, err := b.setInputValue(index, b.inputs[index], jsArgs[index]) + if err != nil { + return nil, err + } + args[index] = value + } + b.log.Debugf("Unmarshalled Args: %+v\n", jsArgs) + b.log.Debugf("Converted Args: %+v\n", args) + results := b.method.Call(args) + + b.log.Debugf("results = %+v", results) + return results, nil +} + +// Attempts to set the method input for parameter with the given value +func (b *boundMethod) setInputValue(index int, typ reflect.Type, val interface{}) (result reflect.Value, err error) { + + // Catch type conversion panics thrown by convert + defer func() { + if r := recover(); r != nil { + // Modify error + fmt.Printf("Recovery message: %+v\n", r) + err = fmt.Errorf("%s for parameter %d of method %s", r.(string)[23:], index+1, b.fullName) + } + }() + + // Do the conversion + // Handle nil values + if val == nil { + switch typ.Kind() { + case reflect.Chan, + reflect.Func, + reflect.Interface, + reflect.Map, + reflect.Ptr, + reflect.Slice: + b.log.Debug("Converting nil to type") + result = reflect.ValueOf(val).Convert(typ) + default: + b.log.Debug("Cannot convert nil to type, returning error") + return reflect.Zero(typ), fmt.Errorf("Unable to use null value for parameter %d of method %s", index+1, b.fullName) + } + } else { + result = reflect.ValueOf(val).Convert(typ) + } + + return result, err +} + +func (b *boundMethod) processWailsInit() error { + // We must have only 1 input, it must be *wails.Runtime + if len(b.inputs) != 1 { + return fmt.Errorf("Invalid WailsInit() definition. Expected 1 input, but got %d", len(b.inputs)) + } + + // It must be *wails.Runtime + inputName := b.inputs[0].String() + b.log.Debugf("WailsInit input type: %s", inputName) + if inputName != "*runtime.Runtime" { + return fmt.Errorf("Invalid WailsInit() definition. Expected input to be wails.Runtime, but got %s", inputName) + } + + // We must have only 1 output, it must be error + if len(b.returnTypes) != 1 { + return fmt.Errorf("Invalid WailsInit() definition. Expected 1 return type, but got %d", len(b.returnTypes)) + } + + // It must be *wails.Runtime + outputName := b.returnTypes[0].String() + b.log.Debugf("WailsInit output type: %s", outputName) + if outputName != "error" { + return fmt.Errorf("Invalid WailsInit() definition. Expected input to be error, but got %s", outputName) + } + + // We are indeed a wails Init method + b.isWailsInit = true + + return nil +} + +func (b *boundMethod) processWailsShutdown() error { + // We must not have any inputs + if len(b.inputs) != 0 { + return fmt.Errorf("Invalid WailsShutdown() definition. Expected 0 inputs, but got %d", len(b.inputs)) + } + + // We must have only 1 output, it must be error + if len(b.returnTypes) != 0 { + return fmt.Errorf("Invalid WailsShutdown() definition. Expected 0 return types, but got %d", len(b.returnTypes)) + } + + // We are indeed a wails Shutdown method + b.isWailsShutdown = true + + return nil +} diff --git a/lib/event/manager.go b/lib/event/manager.go new file mode 100644 index 000000000..23e4f31c8 --- /dev/null +++ b/lib/event/manager.go @@ -0,0 +1,180 @@ +package event + +import ( + "fmt" + "sync" + + "github.com/wailsapp/wails/lib/interfaces" + "github.com/wailsapp/wails/lib/logger" + "github.com/wailsapp/wails/lib/messages" +) + +// Manager handles and processes events +type Manager struct { + incomingEvents chan *messages.EventData + quitChannel chan struct{} + listeners map[string][]*eventListener + running bool + log *logger.CustomLogger + renderer interfaces.Renderer // Messages will be dispatched to the frontend + wg sync.WaitGroup + mu sync.Mutex +} + +// NewManager creates a new event manager with a 100 event buffer +func NewManager() interfaces.EventManager { + return &Manager{ + incomingEvents: make(chan *messages.EventData, 100), + quitChannel: make(chan struct{}, 1), + listeners: make(map[string][]*eventListener), + running: false, + log: logger.NewCustomLogger("Events"), + } +} + +// PushEvent places the given event on to the event queue +func (e *Manager) PushEvent(eventData *messages.EventData) { + e.incomingEvents <- eventData +} + +// eventListener holds a callback function which is invoked when +// the event listened for is emitted. It has a counter which indicates +// how the total number of events it is interested in. A value of zero +// means it does not expire (default). +type eventListener struct { + callback func(...interface{}) // Function to call with emitted event data + counter uint // Expire after counter callbacks. 0 = infinite + expired bool // Indicates if the listener has expired +} + +// Creates a new event listener from the given callback function +func (e *Manager) addEventListener(eventName string, callback func(...interface{}), counter uint) error { + + // Sanity check inputs + if callback == nil { + return fmt.Errorf("nil callback bassed to addEventListener") + } + + // Check event has been registered before + if e.listeners[eventName] == nil { + e.listeners[eventName] = []*eventListener{} + } + + // Create the callback + listener := &eventListener{ + callback: callback, + counter: counter, + } + + // Register listener + e.listeners[eventName] = append(e.listeners[eventName], listener) + + // All good mate + return nil +} + +// On adds a listener for the given event +func (e *Manager) On(eventName string, callback func(...interface{})) { + // Add a persistent eventListener (counter = 0) + err := e.addEventListener(eventName, callback, 0) + if err != nil { + e.log.Error(err.Error()) + } +} + +// Once adds a listener for the given event that will auto remove +// after one callback +func (e *Manager) Once(eventName string, callback func(...interface{})) { + // Add a persistent eventListener (counter = 0) + err := e.addEventListener(eventName, callback, 1) + if err != nil { + e.log.Error(err.Error()) + } +} + +// OnMultiple adds a listener for the given event that will trigger +// at most times. +func (e *Manager) OnMultiple(eventName string, callback func(...interface{}), counter uint) { + // Add a persistent eventListener (counter = 0) + err := e.addEventListener(eventName, callback, counter) + if err != nil { + e.log.Error(err.Error()) + } +} + +// Emit broadcasts the given event to the subscribed listeners +func (e *Manager) Emit(eventName string, optionalData ...interface{}) { + e.incomingEvents <- &messages.EventData{Name: eventName, Data: optionalData} +} + +// Start the event manager's queue processing +func (e *Manager) Start(renderer interfaces.Renderer) { + + e.log.Info("Starting") + + // Store renderer + e.renderer = renderer + + // Set up waitgroup so we can wait for goroutine to quit + e.running = true + e.wg.Add(1) + + // Run main loop in separate goroutine + go func() { + e.log.Info("Listening") + for e.running { + // TODO: Listen for application exit + select { + case event := <-e.incomingEvents: + e.log.DebugFields("Got Event", logger.Fields{ + "data": event.Data, + "name": event.Name, + }) + + // Notify renderer + err := e.renderer.NotifyEvent(event) + if err != nil { + e.log.Error(err.Error()) + } + + e.mu.Lock() + + // Iterate listeners + for _, listener := range e.listeners[event.Name] { + + if !listener.expired { + // Call listener, perhaps with data + if event.Data == nil { + go listener.callback() + } else { + unpacked := event.Data.([]interface{}) + go listener.callback(unpacked...) + } + } + + // Update listen counter + if listener.counter > 0 { + listener.counter = listener.counter - 1 + if listener.counter == 0 { + listener.expired = true + } + } + } + + e.mu.Unlock() + + case <-e.quitChannel: + e.running = false + } + } + e.wg.Done() + }() +} + +// Shutdown is called when exiting the Application +func (e *Manager) Shutdown() { + e.log.Debug("Shutting Down") + e.quitChannel <- struct{}{} + e.log.Debug("Waiting for main loop to exit") + e.wg.Wait() +} diff --git a/lib/interfaces/appconfig.go b/lib/interfaces/appconfig.go new file mode 100644 index 000000000..2feb157a8 --- /dev/null +++ b/lib/interfaces/appconfig.go @@ -0,0 +1,18 @@ +package interfaces + +// AppConfig is the application config interface +type AppConfig interface { + GetWidth() int + GetHeight() int + GetTitle() string + GetMinWidth() int + GetMinHeight() int + GetMaxWidth() int + GetMaxHeight() int + GetResizable() bool + GetHTML() string + GetDisableInspector() bool + GetColour() string + GetCSS() string + GetJS() string +} diff --git a/lib/interfaces/bindingmanager.go b/lib/interfaces/bindingmanager.go new file mode 100644 index 000000000..e145d3b95 --- /dev/null +++ b/lib/interfaces/bindingmanager.go @@ -0,0 +1,11 @@ +package interfaces + +import "github.com/wailsapp/wails/lib/messages" + +// BindingManager is the binding manager interface +type BindingManager interface { + Bind(object interface{}) + Start(renderer Renderer, runtime Runtime) error + ProcessCall(callData *messages.CallData) (result interface{}, err error) + Shutdown() +} diff --git a/lib/interfaces/eventmanager.go b/lib/interfaces/eventmanager.go new file mode 100644 index 000000000..4805ee2b2 --- /dev/null +++ b/lib/interfaces/eventmanager.go @@ -0,0 +1,14 @@ +package interfaces + +import "github.com/wailsapp/wails/lib/messages" + +// EventManager is the event manager interface +type EventManager interface { + PushEvent(*messages.EventData) + Emit(eventName string, optionalData ...interface{}) + OnMultiple(eventName string, callback func(...interface{}), counter uint) + Once(eventName string, callback func(...interface{})) + On(eventName string, callback func(...interface{})) + Start(Renderer) + Shutdown() +} diff --git a/lib/interfaces/ipcmanager.go b/lib/interfaces/ipcmanager.go new file mode 100644 index 000000000..bc6a3cc00 --- /dev/null +++ b/lib/interfaces/ipcmanager.go @@ -0,0 +1,13 @@ +package interfaces + +// CallbackFunc defines the signature of a function required to be provided to the +// Dispatch function so that the response may be returned +type CallbackFunc func(string) error + +// IPCManager is the event manager interface +type IPCManager interface { + BindRenderer(Renderer) + Dispatch(message string, f CallbackFunc) + Start(eventManager EventManager, bindingManager BindingManager) + Shutdown() +} diff --git a/lib/interfaces/renderer.go b/lib/interfaces/renderer.go new file mode 100644 index 000000000..8f5dbfb36 --- /dev/null +++ b/lib/interfaces/renderer.go @@ -0,0 +1,33 @@ +package interfaces + +import ( + "github.com/wailsapp/wails/lib/messages" +) + +// Renderer is an interface describing a Wails target to render the app to +type Renderer interface { + Initialise(AppConfig, IPCManager, EventManager) error + Run() error + + // Binding + NewBinding(bindingName string) error + + // Events + NotifyEvent(eventData *messages.EventData) error + + // Dialog Runtime + SelectFile(title string, filter string) string + SelectDirectory() string + SelectSaveFile(title string, filter string) string + + // Window Runtime + SetColour(string) error + + SetMinSize(width, height int) + SetMaxSize(width, height int) + + Fullscreen() + UnFullscreen() + SetTitle(title string) + Close() +} diff --git a/lib/interfaces/runtime.go b/lib/interfaces/runtime.go new file mode 100644 index 000000000..dfc0e6bc0 --- /dev/null +++ b/lib/interfaces/runtime.go @@ -0,0 +1,4 @@ +package interfaces + +// Runtime interface +type Runtime interface{} diff --git a/lib/ipc/call.go b/lib/ipc/call.go new file mode 100644 index 000000000..f332e7407 --- /dev/null +++ b/lib/ipc/call.go @@ -0,0 +1,35 @@ +package ipc + +import ( + "fmt" + + "github.com/wailsapp/wails/lib/messages" +) + +func init() { + messageProcessors["call"] = processCallData +} + +func processCallData(message *ipcMessage) (*ipcMessage, error) { + + var payload messages.CallData + + // Decode binding call data + payloadMap := message.Payload.(map[string]interface{}) + + // Check for binding name + if payloadMap["bindingName"] == nil { + return nil, fmt.Errorf("bindingName not given in call") + } + payload.BindingName = payloadMap["bindingName"].(string) + + // Check for data + if payloadMap["data"] != nil { + payload.Data = payloadMap["data"].(string) + } + + // Reassign payload to decoded data + message.Payload = &payload + + return message, nil +} diff --git a/lib/ipc/event.go b/lib/ipc/event.go new file mode 100644 index 000000000..9dc9b1afc --- /dev/null +++ b/lib/ipc/event.go @@ -0,0 +1,37 @@ +package ipc + +import ( + "encoding/json" + + "github.com/wailsapp/wails/lib/messages" +) + +// Register the message handler +func init() { + messageProcessors["event"] = processEventData +} + +// This processes the given event message +func processEventData(message *ipcMessage) (*ipcMessage, error) { + + // TODO: Is it worth double checking this is actually an event message, + // even though that's done by the caller? + var payload messages.EventData + + // Decode event data + payloadMap := message.Payload.(map[string]interface{}) + payload.Name = payloadMap["name"].(string) + + // decode the payload data + var data []interface{} + err := json.Unmarshal([]byte(payloadMap["data"].(string)), &data) + if err != nil { + return nil, err + } + payload.Data = data + + // Reassign payload to decoded data + message.Payload = &payload + + return message, nil +} diff --git a/lib/ipc/log.go b/lib/ipc/log.go new file mode 100644 index 000000000..4bf75a9a9 --- /dev/null +++ b/lib/ipc/log.go @@ -0,0 +1,24 @@ +package ipc + +import "github.com/wailsapp/wails/lib/messages" + +// Register the message handler +func init() { + messageProcessors["log"] = processLogData +} + +// This processes the given log message +func processLogData(message *ipcMessage) (*ipcMessage, error) { + + var payload messages.LogData + + // Decode event data + payloadMap := message.Payload.(map[string]interface{}) + payload.Level = payloadMap["level"].(string) + payload.Message = payloadMap["message"].(string) + + // Reassign payload to decoded data + message.Payload = &payload + + return message, nil +} diff --git a/lib/ipc/manager.go b/lib/ipc/manager.go new file mode 100644 index 000000000..8cff6e3db --- /dev/null +++ b/lib/ipc/manager.go @@ -0,0 +1,182 @@ +package ipc + +import ( + "fmt" + "sync" + + "github.com/wailsapp/wails/lib/interfaces" + "github.com/wailsapp/wails/lib/logger" + "github.com/wailsapp/wails/lib/messages" +) + +// Manager manages the IPC subsystem +type Manager struct { + renderer interfaces.Renderer // The renderer + messageQueue chan *ipcMessage + quitChannel chan struct{} + // signals chan os.Signal + log *logger.CustomLogger + eventManager interfaces.EventManager + bindingManager interfaces.BindingManager + running bool + wg sync.WaitGroup +} + +// NewManager creates a new IPC Manager +func NewManager() interfaces.IPCManager { + result := &Manager{ + messageQueue: make(chan *ipcMessage, 100), + quitChannel: make(chan struct{}), + // signals: make(chan os.Signal, 1), + log: logger.NewCustomLogger("IPC"), + } + return result +} + +// BindRenderer sets the renderer, returns the dispatch function +func (i *Manager) BindRenderer(renderer interfaces.Renderer) { + i.renderer = renderer +} + +// Start the IPC Manager +func (i *Manager) Start(eventManager interfaces.EventManager, bindingManager interfaces.BindingManager) { + + // Store manager references + i.eventManager = eventManager + i.bindingManager = bindingManager + + i.log.Info("Starting") + // signal.Notify(manager.signals, os.Interrupt) + i.running = true + + // Keep track of this goroutine + i.wg.Add(1) + go func() { + for i.running { + select { + case incomingMessage := <-i.messageQueue: + i.log.DebugFields("Processing message", logger.Fields{ + "1D": &incomingMessage, + }) + switch incomingMessage.Type { + case "call": + callData := incomingMessage.Payload.(*messages.CallData) + i.log.DebugFields("Processing call", logger.Fields{ + "1D": &incomingMessage, + "bindingName": callData.BindingName, + "data": callData.Data, + }) + go func() { + result, err := bindingManager.ProcessCall(callData) + i.log.DebugFields("processed call", logger.Fields{"result": result, "err": err}) + if err != nil { + incomingMessage.ReturnError(err.Error()) + } else { + incomingMessage.ReturnSuccess(result) + } + i.log.DebugFields("Finished processing call", logger.Fields{ + "1D": &incomingMessage, + }) + }() + case "event": + + // Extract event data + eventData := incomingMessage.Payload.(*messages.EventData) + + // Log + i.log.DebugFields("Processing event", logger.Fields{ + "name": eventData.Name, + "data": eventData.Data, + }) + + // Push the event to the event manager + i.eventManager.PushEvent(eventData) + + // Log + i.log.DebugFields("Finished processing event", logger.Fields{ + "name": eventData.Name, + }) + case "log": + logdata := incomingMessage.Payload.(*messages.LogData) + switch logdata.Level { + case "info": + logger.GlobalLogger.Info(logdata.Message) + case "debug": + logger.GlobalLogger.Debug(logdata.Message) + case "warning": + logger.GlobalLogger.Warn(logdata.Message) + case "error": + logger.GlobalLogger.Error(logdata.Message) + case "fatal": + logger.GlobalLogger.Fatal(logdata.Message) + default: + logger.ErrorFields("Invalid log level sent", logger.Fields{ + "level": logdata.Level, + "message": logdata.Message, + }) + } + default: + i.log.Debugf("bad message sent to MessageQueue! Unknown type: %s", incomingMessage.Type) + } + + // Log + i.log.DebugFields("Finished processing message", logger.Fields{ + "1D": &incomingMessage, + }) + case <-i.quitChannel: + i.running = false + } + } + i.log.Debug("Stopping") + i.wg.Done() + }() +} + +// Dispatch receives JSON encoded messages from the renderer. +// It processes the message to ensure that it is valid and places +// the processed message on the message queue +func (i *Manager) Dispatch(message string, cb interfaces.CallbackFunc) { + + // Create a new IPC Message + incomingMessage, err := newIPCMessage(message, i.SendResponse(cb)) + if err != nil { + i.log.ErrorFields("Could not understand incoming message! ", map[string]interface{}{ + "message": message, + "error": err, + }) + return + } + + // Put message on queue + i.log.DebugFields("Message received", map[string]interface{}{ + "type": incomingMessage.Type, + "payload": incomingMessage.Payload, + }) + + // Put incoming message on the message queue + i.messageQueue <- incomingMessage +} + +// SendResponse sends the given response back to the frontend +// It sends the data back to the correct renderer by way of the provided callback function +func (i *Manager) SendResponse(cb interfaces.CallbackFunc) func(i *ipcResponse) error { + + return func(response *ipcResponse) error { + // Serialise the Message + data, err := response.Serialise() + if err != nil { + fmt.Printf(err.Error()) + return err + } + return cb(data) + } + +} + +// Shutdown is called when exiting the Application +func (i *Manager) Shutdown() { + i.log.Debug("Shutdown called") + i.quitChannel <- struct{}{} + i.log.Debug("Waiting of main loop shutdown") + i.wg.Wait() +} diff --git a/lib/ipc/message.go b/lib/ipc/message.go new file mode 100644 index 000000000..8c09ab988 --- /dev/null +++ b/lib/ipc/message.go @@ -0,0 +1,93 @@ +package ipc + +import ( + "encoding/json" + "fmt" +) + +// Message handler +type messageProcessorFunc func(*ipcMessage) (*ipcMessage, error) + +var messageProcessors = make(map[string]messageProcessorFunc) + +// ipcMessage is the struct version of the Message sent from the frontend. +// The payload has the specialised message data +type ipcMessage struct { + Type string `json:"type"` + Payload interface{} `json:"payload"` + CallbackID string `json:"callbackid,omitempty"` + sendResponse func(*ipcResponse) error +} + +func parseMessage(incomingMessage string) (*ipcMessage, error) { + // Parse message + var message ipcMessage + err := json.Unmarshal([]byte(incomingMessage), &message) + return &message, err +} + +func newIPCMessage(incomingMessage string, responseFunction func(*ipcResponse) error) (*ipcMessage, error) { + + // Parse the Message + message, err := parseMessage(incomingMessage) + if err != nil { + return nil, err + } + + // Check message type is valid + messageProcessor := messageProcessors[message.Type] + if messageProcessor == nil { + return nil, fmt.Errorf("unknown message type: %s", message.Type) + } + + // Process message payload + message, err = messageProcessor(message) + if err != nil { + return nil, err + } + + // Set the response function + message.sendResponse = responseFunction + + return message, nil +} + +// hasCallbackID checks if the message can send an error back to the frontend +func (m *ipcMessage) hasCallbackID() error { + if m.CallbackID == "" { + return fmt.Errorf("attempted to return error to message with no Callback ID") + } + return nil +} + +// ReturnError returns an error back to the frontend +func (m *ipcMessage) ReturnError(format string, args ...interface{}) error { + + // Ignore ReturnError if no callback ID given + err := m.hasCallbackID() + if err != nil { + return err + } + + // Create response + response := newErrorResponse(m.CallbackID, fmt.Sprintf(format, args...)) + + // Send response + return m.sendResponse(response) +} + +// ReturnSuccess returns a success message back with the given data +func (m *ipcMessage) ReturnSuccess(data interface{}) error { + + // Ignore ReturnSuccess if no callback ID given + err := m.hasCallbackID() + if err != nil { + return err + } + + // Create the response + response := newSuccessResponse(m.CallbackID, data) + + // Send response + return m.sendResponse(response) +} diff --git a/lib/ipc/response.go b/lib/ipc/response.go new file mode 100644 index 000000000..3006b3bbb --- /dev/null +++ b/lib/ipc/response.go @@ -0,0 +1,45 @@ +package ipc + +import ( + "encoding/hex" + "encoding/json" +) + +// ipcResponse contains the response data from an RPC call +type ipcResponse struct { + CallbackID string `json:"callbackid"` + ErrorMessage string `json:"error,omitempty"` + Data interface{} `json:"data,omitempty"` +} + +// newErrorResponse returns the given error message to the frontend with the callbackid +func newErrorResponse(callbackID string, errorMessage string) *ipcResponse { + // Create response object + result := &ipcResponse{ + CallbackID: callbackID, + ErrorMessage: errorMessage, + } + return result +} + +// newSuccessResponse returns the given data to the frontend with the callbackid +func newSuccessResponse(callbackID string, data interface{}) *ipcResponse { + + // Create response object + result := &ipcResponse{ + CallbackID: callbackID, + Data: data, + } + + return result +} + +// Serialise formats the response to a string +func (i *ipcResponse) Serialise() (string, error) { + b, err := json.Marshal(i) + if err != nil { + return "", err + } + result := hex.EncodeToString(b) + return result, err +} diff --git a/lib/logger/custom.go b/lib/logger/custom.go new file mode 100644 index 000000000..fd055d0e8 --- /dev/null +++ b/lib/logger/custom.go @@ -0,0 +1,104 @@ +package logger + +// CustomLogger is a wrapper object to logrus +type CustomLogger struct { + prefix string + errorOnly bool +} + +// NewCustomLogger creates a new custom logger with the given prefix +func NewCustomLogger(prefix string) *CustomLogger { + return &CustomLogger{ + prefix: "[" + prefix + "] ", + } +} + +// Info level message +func (c *CustomLogger) Info(message string) { + GlobalLogger.Info(c.prefix + message) +} + +// Infof - formatted message +func (c *CustomLogger) Infof(message string, args ...interface{}) { + GlobalLogger.Infof(c.prefix+message, args...) +} + +// InfoFields - message with fields +func (c *CustomLogger) InfoFields(message string, fields Fields) { + GlobalLogger.WithFields(map[string]interface{}(fields)).Info(c.prefix + message) +} + +// Debug level message +func (c *CustomLogger) Debug(message string) { + GlobalLogger.Debug(c.prefix + message) +} + +// Debugf - formatted message +func (c *CustomLogger) Debugf(message string, args ...interface{}) { + GlobalLogger.Debugf(c.prefix+message, args...) +} + +// DebugFields - message with fields +func (c *CustomLogger) DebugFields(message string, fields Fields) { + GlobalLogger.WithFields(map[string]interface{}(fields)).Debug(c.prefix + message) +} + +// Warn level message +func (c *CustomLogger) Warn(message string) { + GlobalLogger.Warn(c.prefix + message) +} + +// Warnf - formatted message +func (c *CustomLogger) Warnf(message string, args ...interface{}) { + GlobalLogger.Warnf(c.prefix+message, args...) +} + +// WarnFields - message with fields +func (c *CustomLogger) WarnFields(message string, fields Fields) { + GlobalLogger.WithFields(map[string]interface{}(fields)).Warn(c.prefix + message) +} + +// Error level message +func (c *CustomLogger) Error(message string) { + GlobalLogger.Error(c.prefix + message) +} + +// Errorf - formatted message +func (c *CustomLogger) Errorf(message string, args ...interface{}) { + GlobalLogger.Errorf(c.prefix+message, args...) +} + +// ErrorFields - message with fields +func (c *CustomLogger) ErrorFields(message string, fields Fields) { + GlobalLogger.WithFields(map[string]interface{}(fields)).Error(c.prefix + message) +} + +// Fatal level message +func (c *CustomLogger) Fatal(message string) { + GlobalLogger.Fatal(c.prefix + message) +} + +// Fatalf - formatted message +func (c *CustomLogger) Fatalf(message string, args ...interface{}) { + GlobalLogger.Fatalf(c.prefix+message, args...) +} + +// FatalFields - message with fields +func (c *CustomLogger) FatalFields(message string, fields Fields) { + GlobalLogger.WithFields(map[string]interface{}(fields)).Fatal(c.prefix + message) +} + +// Panic level message +func (c *CustomLogger) Panic(message string) { + GlobalLogger.Panic(c.prefix + message) +} + +// Panicf - formatted message +func (c *CustomLogger) Panicf(message string, args ...interface{}) { + GlobalLogger.Panicf(c.prefix+message, args...) +} + +// PanicFields - message with fields +func (c *CustomLogger) PanicFields(message string, fields Fields) { + GlobalLogger.WithFields(map[string]interface{}(fields)).Panic(c.prefix + message) +} diff --git a/lib/logger/log.go b/lib/logger/log.go new file mode 100644 index 000000000..791328645 --- /dev/null +++ b/lib/logger/log.go @@ -0,0 +1,47 @@ +package logger + +import ( + "os" + "strings" + + "github.com/sirupsen/logrus" +) + +// GlobalLogger is the global logger +var GlobalLogger = logrus.New() + +// Fields is used by the customLogger object to output +// fields along with a message +type Fields map[string]interface{} + +// Default options for the global logger +func init() { + GlobalLogger.SetOutput(os.Stdout) + GlobalLogger.SetLevel(logrus.DebugLevel) +} + +// ErrorFields is a helper for logging fields to the global logger +func ErrorFields(message string, fields Fields) { + GlobalLogger.WithFields(map[string]interface{}(fields)).Error(message) +} + +// SetLogLevel sets the log level to the given level +func SetLogLevel(level string) { + switch strings.ToLower(level) { + case "info": + GlobalLogger.SetLevel(logrus.InfoLevel) + case "debug": + GlobalLogger.SetLevel(logrus.DebugLevel) + case "warn": + GlobalLogger.SetLevel(logrus.WarnLevel) + case "error": + GlobalLogger.SetLevel(logrus.ErrorLevel) + case "fatal": + GlobalLogger.SetLevel(logrus.FatalLevel) + case "panic": + GlobalLogger.SetLevel(logrus.PanicLevel) + default: + GlobalLogger.SetLevel(logrus.DebugLevel) + GlobalLogger.Warnf("Log level '%s' not recognised. Setting to Debug.", level) + } +} diff --git a/lib/messages/calldata.go b/lib/messages/calldata.go new file mode 100644 index 000000000..d3da1d414 --- /dev/null +++ b/lib/messages/calldata.go @@ -0,0 +1,7 @@ +package messages + +// CallData represents a call to a Go function/method +type CallData struct { + BindingName string `json:"bindingName"` + Data string `json:"data,omitempty"` +} diff --git a/lib/messages/eventdata.go b/lib/messages/eventdata.go new file mode 100644 index 000000000..c15ba08c1 --- /dev/null +++ b/lib/messages/eventdata.go @@ -0,0 +1,7 @@ +package messages + +// EventData represents an event sent from the frontend +type EventData struct { + Name string `json:"name"` + Data interface{} `json:"data"` +} diff --git a/lib/messages/logdata.go b/lib/messages/logdata.go new file mode 100644 index 000000000..068b6a709 --- /dev/null +++ b/lib/messages/logdata.go @@ -0,0 +1,7 @@ +package messages + +// LogData represents a call to log from the frontend +type LogData struct { + Level string `json:"level"` + Message string `json:"string"` +} diff --git a/lib/renderer/bridge.go b/lib/renderer/bridge.go new file mode 100644 index 000000000..44da78495 --- /dev/null +++ b/lib/renderer/bridge.go @@ -0,0 +1,10 @@ +package renderer + +import ( + bridge "github.com/wailsapp/wails/lib/renderer/bridge" +) + +// NewBridge returns a new Bridge struct +func NewBridge() *bridge.Bridge { + return &bridge.Bridge{} +} diff --git a/lib/renderer/bridge/bridge.go b/lib/renderer/bridge/bridge.go new file mode 100644 index 000000000..3fd3646cb --- /dev/null +++ b/lib/renderer/bridge/bridge.go @@ -0,0 +1,230 @@ +package renderer + +import ( + "encoding/json" + "fmt" + "net/http" + "sync" + + "github.com/gorilla/websocket" + "github.com/wailsapp/wails/lib/interfaces" + "github.com/wailsapp/wails/lib/logger" + "github.com/wailsapp/wails/lib/messages" +) + +type messageType int + +const ( + jsMessage messageType = iota + cssMessage + htmlMessage + notifyMessage + bindingMessage + callbackMessage + wailsRuntimeMessage +) + +func (m messageType) toString() string { + return [...]string{"j", "s", "h", "n", "b", "c", "w"}[m] +} + +// Bridge is a backend that opens a local web server +// and renders the files over a websocket +type Bridge struct { + // Common + log *logger.CustomLogger + ipcManager interfaces.IPCManager + appConfig interfaces.AppConfig + eventManager interfaces.EventManager + bindingCache []string + + // Bridge specific + server *http.Server + + lock sync.Mutex + sessions map[string]*session +} + +// Initialise the Bridge Renderer +func (h *Bridge) Initialise(appConfig interfaces.AppConfig, ipcManager interfaces.IPCManager, eventManager interfaces.EventManager) error { + h.sessions = map[string]*session{} + h.ipcManager = ipcManager + h.appConfig = appConfig + h.eventManager = eventManager + ipcManager.BindRenderer(h) + h.log = logger.NewCustomLogger("Bridge") + return nil +} + +func (h *Bridge) wsBridgeHandler(w http.ResponseWriter, r *http.Request) { + conn, err := websocket.Upgrade(w, r, w.Header(), 1024, 1024) + if err != nil { + http.Error(w, "Could not open websocket connection", http.StatusBadRequest) + } + h.log.Infof("Connection from frontend accepted [%s].", conn.RemoteAddr().String()) + h.startSession(conn) +} + +func (h *Bridge) startSession(conn *websocket.Conn) { + s := newSession(conn, + h.bindingCache, + h.ipcManager, + logger.NewCustomLogger("BridgeSession"), + h.eventManager) + + conn.SetCloseHandler(func(int, string) error { + h.log.Infof("Connection dropped [%s].", s.Identifier()) + h.eventManager.Emit("wails:bridge:session:closed", s.Identifier()) + h.lock.Lock() + defer h.lock.Unlock() + delete(h.sessions, s.Identifier()) + return nil + }) + + h.lock.Lock() + defer h.lock.Unlock() + go s.start(len(h.sessions) == 0) + h.sessions[s.Identifier()] = s +} + +// Run the app in Bridge mode! +func (h *Bridge) Run() error { + h.server = &http.Server{Addr: ":34115"} + http.HandleFunc("/bridge", h.wsBridgeHandler) + + h.log.Info("Bridge mode started.") + h.log.Info("The frontend will connect automatically.") + + err := h.server.ListenAndServe() + if err != nil && err != http.ErrServerClosed { + h.log.Fatal(err.Error()) + } + return err +} + +// NewBinding creates a new binding with the frontend +func (h *Bridge) NewBinding(methodName string) error { + h.bindingCache = append(h.bindingCache, methodName) + return nil +} + +// SelectFile is unsupported for Bridge but required +// for the Renderer interface +func (h *Bridge) SelectFile(title string, filter string) string { + h.log.Warn("SelectFile() unsupported in bridge mode") + return "" +} + +// SelectDirectory is unsupported for Bridge but required +// for the Renderer interface +func (h *Bridge) SelectDirectory() string { + h.log.Warn("SelectDirectory() unsupported in bridge mode") + return "" +} + +// SelectSaveFile is unsupported for Bridge but required +// for the Renderer interface +func (h *Bridge) SelectSaveFile(title string, filter string) string { + h.log.Warn("SelectSaveFile() unsupported in bridge mode") + return "" +} + +// NotifyEvent notifies the frontend of an event +func (h *Bridge) NotifyEvent(event *messages.EventData) error { + + // Look out! Nils about! + var err error + if event == nil { + err = fmt.Errorf("Sent nil event to renderer.webViewRenderer") + h.log.Error(err.Error()) + return err + } + + // Default data is a blank array + data := []byte("[]") + + // Process event data + if event.Data != nil { + // Marshall the data + data, err = json.Marshal(event.Data) + if err != nil { + h.log.Errorf("Cannot marshal JSON data in event: %s ", err.Error()) + return err + } + } + + // Double encode data to ensure everything is escaped correctly. + data, err = json.Marshal(string(data)) + if err != nil { + h.log.Errorf("Cannot marshal JSON data in event: %s ", err.Error()) + return err + } + + message := "window.wails._.Notify('" + event.Name + "'," + string(data) + ")" + dead := []*session{} + for _, session := range h.sessions { + err := session.evalJS(message, notifyMessage) + if err != nil { + h.log.Debugf("Failed to send message to %s - Removing listener : %v", session.Identifier(), err) + h.log.Infof("Connection from [%v] unresponsive - dropping", session.Identifier()) + dead = append(dead, session) + } + } + h.lock.Lock() + defer h.lock.Unlock() + for _, session := range dead { + delete(h.sessions, session.Identifier()) + } + + return nil +} + +// SetColour is unsupported for Bridge but required +// for the Renderer interface +func (h *Bridge) SetColour(colour string) error { + h.log.WarnFields("SetColour ignored for Bridge more", logger.Fields{"col": colour}) + return nil +} + +// SetMinSize is unsupported for Bridge but required +// for the Renderer interface +func (h *Bridge) SetMinSize(width, height int) { + h.log.Warn("SetMinSize() unsupported in bridge mode") +} + +// SetMaxSize is unsupported for Bridge but required +// for the Renderer interface +func (h *Bridge) SetMaxSize(width, height int) { + h.log.Warn("SetMaxSize() unsupported in bridge mode") +} + +// Fullscreen is unsupported for Bridge but required +// for the Renderer interface +func (h *Bridge) Fullscreen() { + h.log.Warn("Fullscreen() unsupported in bridge mode") +} + +// UnFullscreen is unsupported for Bridge but required +// for the Renderer interface +func (h *Bridge) UnFullscreen() { + h.log.Warn("UnFullscreen() unsupported in bridge mode") +} + +// SetTitle is currently unsupported for Bridge but required +// for the Renderer interface +func (h *Bridge) SetTitle(title string) { + h.log.WarnFields("SetTitle() unsupported in bridge mode", logger.Fields{"title": title}) +} + +// Close is unsupported for Bridge but required +// for the Renderer interface +func (h *Bridge) Close() { + h.log.Debug("Shutting down") + for _, session := range h.sessions { + session.Shutdown() + } + err := h.server.Close() + if err != nil { + h.log.Errorf(err.Error()) + } +} diff --git a/lib/renderer/bridge/session.go b/lib/renderer/bridge/session.go new file mode 100644 index 000000000..c85839342 --- /dev/null +++ b/lib/renderer/bridge/session.go @@ -0,0 +1,135 @@ +package renderer + +import ( + "time" + + "github.com/wailsapp/wails/runtime" + + "github.com/gorilla/websocket" + "github.com/wailsapp/wails/lib/interfaces" + "github.com/wailsapp/wails/lib/logger" +) + +// TODO Move this back into bridge.go + +// session represents a single websocket session +type session struct { + bindingCache []string + conn *websocket.Conn + eventManager interfaces.EventManager + log *logger.CustomLogger + ipc interfaces.IPCManager + + // Mutex for writing to the socket + shutdown chan bool + writeChan chan []byte + + done bool +} + +func newSession(conn *websocket.Conn, bindingCache []string, ipc interfaces.IPCManager, logger *logger.CustomLogger, eventMgr interfaces.EventManager) *session { + return &session{ + conn: conn, + bindingCache: bindingCache, + ipc: ipc, + log: logger, + eventManager: eventMgr, + shutdown: make(chan bool), + writeChan: make(chan []byte, 100), + } +} + +// Identifier returns a string identifier for the remote connection. +// Taking the form of the client's :. +func (s *session) Identifier() string { + if s.conn != nil { + return s.conn.RemoteAddr().String() + } + return "" +} + +func (s *session) sendMessage(msg string) error { + if !s.done { + s.writeChan <- []byte(msg) + } + return nil +} + +func (s *session) start(firstSession bool) { + s.log.Infof("Connected to frontend.") + go s.writePump() + + s.evalJS(runtime.WailsJS, wailsRuntimeMessage) + + // Inject bindings + for _, binding := range s.bindingCache { + s.evalJS(binding, bindingMessage) + } + s.eventManager.Emit("wails:bridge:session:started", s.Identifier()) + + // Emit that everything is loaded and ready + if firstSession { + s.eventManager.Emit("wails:ready") + } + + for { + messageType, buffer, err := s.conn.ReadMessage() + if messageType == -1 { + return + } + if err != nil { + s.log.Errorf("Error reading message: %v", err) + continue + } + + s.log.Debugf("Got message: %#v\n", string(buffer)) + + s.ipc.Dispatch(string(buffer), s.Callback) + + if s.done { + break + } + } +} + +// Callback sends a callback to the frontend +func (s *session) Callback(data string) error { + return s.evalJS(data, callbackMessage) +} + +func (s *session) evalJS(js string, mtype messageType) error { + // Prepend message type to message + return s.sendMessage(mtype.toString() + js) +} + +// Shutdown +func (s *session) Shutdown() { + s.done = true + s.shutdown <- true + s.log.Debugf("session %v exit", s.Identifier()) +} + +// writePump pulls messages from the writeChan and sends them to the client +// since it uses a channel to read the messages the socket is protected without locks +func (s *session) writePump() { + s.log.Debugf("Session %v - writePump start", s.Identifier()) + for { + select { + case msg, ok := <-s.writeChan: + s.conn.SetWriteDeadline(time.Now().Add(1 * time.Second)) + if !ok { + s.log.Debug("writeChan was closed!") + s.conn.WriteMessage(websocket.CloseMessage, []byte{}) + return + } + + if err := s.conn.WriteMessage(websocket.TextMessage, msg); err != nil { + s.log.Debug(err.Error()) + return + } + case <-s.shutdown: + break + } + } + s.log.Debug("writePump exiting...") +} diff --git a/lib/renderer/webview.go b/lib/renderer/webview.go new file mode 100644 index 000000000..777a8560c --- /dev/null +++ b/lib/renderer/webview.go @@ -0,0 +1,463 @@ +package renderer + +import ( + "encoding/json" + "fmt" + "math/rand" + "strings" + "sync" + "time" + + "github.com/wailsapp/wails/runtime" + + "github.com/go-playground/colors" + "github.com/wailsapp/wails/lib/interfaces" + "github.com/wailsapp/wails/lib/logger" + "github.com/wailsapp/wails/lib/messages" + wv "github.com/wailsapp/wails/lib/renderer/webview" +) + +// WebView defines the main webview application window +// Default values in [] + +// UseFirebug indicates whether to inject the firebug console +var UseFirebug = "" + +type WebView struct { + window wv.WebView // The webview object + ipc interfaces.IPCManager + log *logger.CustomLogger + config interfaces.AppConfig + eventManager interfaces.EventManager + bindingCache []string + maximumSizeSet bool +} + +// NewWebView returns a new WebView struct +func NewWebView() *WebView { + return &WebView{} +} + +// Initialise sets up the WebView +func (w *WebView) Initialise(config interfaces.AppConfig, ipc interfaces.IPCManager, eventManager interfaces.EventManager) error { + + // Store reference to eventManager + w.eventManager = eventManager + + // Set up logger + w.log = logger.NewCustomLogger("WebView") + + // Set up the dispatcher function + w.ipc = ipc + ipc.BindRenderer(w) + + // Save the config + w.config = config + + width := config.GetWidth() + height := config.GetHeight() + + // Clamp width and height + minWidth, minHeight := config.GetMinWidth(), config.GetMinHeight() + maxWidth, maxHeight := config.GetMaxWidth(), config.GetMaxHeight() + setMinSize := minWidth != -1 && minHeight != -1 + setMaxSize := maxWidth != -1 && maxHeight != -1 + + if setMinSize { + if width < minWidth { + width = minWidth + } + if height < minHeight { + height = minHeight + } + } + + if setMaxSize { + if width > maxWidth { + width = maxWidth + } + if height > maxHeight { + height = maxHeight + } + } + + // Create the WebView instance + w.window = wv.NewWebview(wv.Settings{ + Width: width, + Height: height, + Title: config.GetTitle(), + Resizable: config.GetResizable(), + URL: config.GetHTML(), + Debug: !config.GetDisableInspector(), + ExternalInvokeCallback: func(_ wv.WebView, message string) { + w.ipc.Dispatch(message, w.callback) + }, + }) + + // Set minimum and maximum sizes + if setMinSize { + w.SetMinSize(minWidth, minHeight) + } + if setMaxSize { + w.SetMaxSize(maxWidth, maxHeight) + } + + // Set minimum and maximum sizes + if setMinSize { + w.SetMinSize(minWidth, minHeight) + } + if setMaxSize { + w.SetMaxSize(maxWidth, maxHeight) + } + + // SignalManager.OnExit(w.Exit) + + // Set colour + color := config.GetColour() + if color != "" { + err := w.SetColour(color) + if err != nil { + return err + } + } + + w.log.Info("Initialised") + return nil +} + +// SetColour sets the window colour +func (w *WebView) SetColour(colour string) error { + color, err := colors.Parse(colour) + if err != nil { + return err + } + rgba := color.ToRGBA() + alpha := uint8(255 * rgba.A) + w.window.Dispatch(func() { + w.window.SetColor(rgba.R, rgba.G, rgba.B, alpha) + }) + + return nil +} + +// evalJS evaluates the given js in the WebView +// I should rename this to evilJS lol +func (w *WebView) evalJS(js string) error { + outputJS := fmt.Sprintf("%.45s", js) + if len(js) > 45 { + outputJS += "..." + } + w.log.DebugFields("Eval", logger.Fields{"js": outputJS}) + // + w.window.Dispatch(func() { + w.window.Eval(js) + }) + return nil +} + +// Escape the Javascripts! +func escapeJS(js string) (string, error) { + result := strings.Replace(js, "\\", "\\\\", -1) + result = strings.Replace(result, "'", "\\'", -1) + result = strings.Replace(result, "\n", "\\n", -1) + return result, nil +} + +// evalJSSync evaluates the given js in the WebView synchronously +// Do not call this from the main thread or you'll nuke your app because +// you won't get the callback. +func (w *WebView) evalJSSync(js string) error { + + minified, err := escapeJS(js) + + if err != nil { + return err + } + + outputJS := fmt.Sprintf("%.45s", js) + if len(js) > 45 { + outputJS += "..." + } + w.log.DebugFields("EvalSync", logger.Fields{"js": outputJS}) + + ID := fmt.Sprintf("syncjs:%d:%d", time.Now().Unix(), rand.Intn(9999)) + var wg sync.WaitGroup + wg.Add(1) + + go func() { + exit := false + // We are done when we receive the Callback ID + w.log.Debug("SyncJS: sending with ID = " + ID) + w.eventManager.On(ID, func(...interface{}) { + w.log.Debug("SyncJS: Got callback ID = " + ID) + wg.Done() + exit = true + }) + command := fmt.Sprintf("wails._.AddScript('%s', '%s')", minified, ID) + w.window.Dispatch(func() { + w.window.Eval(command) + }) + for exit == false { + time.Sleep(time.Millisecond * 1) + } + }() + + wg.Wait() + + return nil +} + +// injectCSS adds the given CSS to the WebView +func (w *WebView) injectCSS(css string) { + w.window.Dispatch(func() { + w.window.InjectCSS(css) + }) +} + +// Exit closes the window +func (w *WebView) Exit() { + w.window.Exit() +} + +// Run the window main loop +func (w *WebView) Run() error { + + w.log.Info("Running...") + + // Inject firebug in debug mode on Windows + if UseFirebug != "" { + w.log.Debug("Injecting Firebug") + w.evalJS(`window.usefirebug=true;`) + } + + // Runtime assets + w.log.DebugFields("Injecting wails JS runtime", logger.Fields{"js": runtime.WailsJS}) + w.evalJS(runtime.WailsJS) + + // Ping the wait channel when the wails runtime is loaded + w.eventManager.On("wails:loaded", func(...interface{}) { + + // Run this in a different go routine to free up the main process + go func() { + + // Inject Bindings + for _, binding := range w.bindingCache { + w.evalJSSync(binding) + } + + // Inject user CSS + if w.config.GetCSS() != "" { + outputCSS := fmt.Sprintf("%.45s", w.config.GetCSS()) + if len(outputCSS) > 45 { + outputCSS += "..." + } + w.log.DebugFields("Inject User CSS", logger.Fields{"css": outputCSS}) + w.injectCSS(w.config.GetCSS()) + } else { + // Use default wails css + + w.log.Debug("Injecting Default Wails CSS: " + runtime.WailsCSS) + w.injectCSS(runtime.WailsCSS) + } + + // Inject user JS + if w.config.GetJS() != "" { + outputJS := fmt.Sprintf("%.45s", w.config.GetJS()) + if len(outputJS) > 45 { + outputJS += "..." + } + w.log.DebugFields("Inject User JS", logger.Fields{"js": outputJS}) + w.evalJSSync(w.config.GetJS()) + } + + // Emit that everything is loaded and ready + w.eventManager.Emit("wails:ready") + }() + }) + + // Kick off main window loop + w.window.Run() + + return nil +} + +// NewBinding registers a new binding with the frontend +func (w *WebView) NewBinding(methodName string) error { + objectCode := fmt.Sprintf("window.wails._.NewBinding('%s');", methodName) + w.bindingCache = append(w.bindingCache, objectCode) + return nil +} + +// SelectFile opens a dialog that allows the user to select a file +func (w *WebView) SelectFile(title string, filter string) string { + var result string + + // We need to run this on the main thread, however Dispatch is + // non-blocking so we launch this in a goroutine and wait for + // dispatch to finish before returning the result + var wg sync.WaitGroup + wg.Add(1) + go func() { + w.window.Dispatch(func() { + result = w.window.Dialog(wv.DialogTypeOpen, 0, title, "", filter) + wg.Done() + }) + }() + + defer w.focus() // Ensure the main window is put back into focus afterwards + + wg.Wait() + return result +} + +// SelectDirectory opens a dialog that allows the user to select a directory +func (w *WebView) SelectDirectory() string { + var result string + // We need to run this on the main thread, however Dispatch is + // non-blocking so we launch this in a goroutine and wait for + // dispatch to finish before returning the result + var wg sync.WaitGroup + wg.Add(1) + go func() { + w.window.Dispatch(func() { + result = w.window.Dialog(wv.DialogTypeOpen, wv.DialogFlagDirectory, "Select Directory", "", "") + wg.Done() + }) + }() + + defer w.focus() // Ensure the main window is put back into focus afterwards + + wg.Wait() + return result +} + +// SelectSaveFile opens a dialog that allows the user to select a file to save +func (w *WebView) SelectSaveFile(title string, filter string) string { + var result string + // We need to run this on the main thread, however Dispatch is + // non-blocking so we launch this in a goroutine and wait for + // dispatch to finish before returning the result + var wg sync.WaitGroup + wg.Add(1) + go func() { + w.window.Dispatch(func() { + result = w.window.Dialog(wv.DialogTypeSave, 0, title, "", filter) + wg.Done() + }) + }() + + defer w.focus() // Ensure the main window is put back into focus afterwards + + wg.Wait() + return result +} + +// focus puts the main window into focus +func (w *WebView) focus() { + w.window.Dispatch(func() { + w.window.Focus() + }) +} + +// callback sends a callback to the frontend +func (w *WebView) callback(data string) error { + callbackCMD := fmt.Sprintf("window.wails._.Callback('%s');", data) + return w.evalJS(callbackCMD) +} + +// NotifyEvent notifies the frontend about a backend runtime event +func (w *WebView) NotifyEvent(event *messages.EventData) error { + + // Look out! Nils about! + var err error + if event == nil { + err = fmt.Errorf("Sent nil event to renderer.WebView") + w.log.Error(err.Error()) + return err + } + + // Default data is a blank array + data := []byte("[]") + + // Process event data + if event.Data != nil { + // Marshall the data + data, err = json.Marshal(event.Data) + if err != nil { + w.log.Errorf("Cannot unmarshall JSON data in event: %s ", err.Error()) + return err + } + } + + // Double encode data to ensure everything is escaped correctly. + data, err = json.Marshal(string(data)) + if err != nil { + w.log.Errorf("Cannot marshal JSON data in event: %s ", err.Error()) + return err + } + + message := "window.wails._.Notify('" + event.Name + "'," + string(data) + ")" + return w.evalJS(message) +} + +// SetMinSize sets the minimum size of a resizable window +func (w *WebView) SetMinSize(width, height int) { + if w.config.GetResizable() == false { + w.log.Warn("Cannot call SetMinSize() - App.Resizable = false") + return + } + w.window.Dispatch(func() { + w.window.SetMinSize(width, height) + }) +} + +// SetMaxSize sets the maximum size of a resizable window +func (w *WebView) SetMaxSize(width, height int) { + if w.config.GetResizable() == false { + w.log.Warn("Cannot call SetMaxSize() - App.Resizable = false") + return + } + w.maximumSizeSet = true + w.window.Dispatch(func() { + w.window.SetMaxSize(width, height) + }) +} + +// Fullscreen makes the main window go fullscreen +func (w *WebView) Fullscreen() { + if w.config.GetResizable() == false { + w.log.Warn("Cannot call Fullscreen() - App.Resizable = false") + return + } else if w.maximumSizeSet { + w.log.Warn("Cannot call Fullscreen() - Maximum size of window set") + return + } + w.window.Dispatch(func() { + w.window.SetFullscreen(true) + }) +} + +// UnFullscreen returns the window to the position prior to a fullscreen call +func (w *WebView) UnFullscreen() { + if w.config.GetResizable() == false { + w.log.Warn("Cannot call UnFullscreen() - App.Resizable = false") + return + } + w.window.Dispatch(func() { + w.window.SetFullscreen(false) + }) +} + +// SetTitle sets the window title +func (w *WebView) SetTitle(title string) { + w.window.Dispatch(func() { + w.window.SetTitle(title) + }) +} + +// Close closes the window +func (w *WebView) Close() { + w.window.Dispatch(func() { + w.window.Terminate() + }) +} diff --git a/lib/renderer/webview/LICENSE b/lib/renderer/webview/LICENSE new file mode 100644 index 000000000..b18604bf4 --- /dev/null +++ b/lib/renderer/webview/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Serge Zaitsev + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/lib/renderer/webview/webview.go b/lib/renderer/webview/webview.go new file mode 100755 index 000000000..60ce89e26 --- /dev/null +++ b/lib/renderer/webview/webview.go @@ -0,0 +1,411 @@ +// Package webview implements Go bindings to https://github.com/zserge/webview C library. +// It is a modified version of webview.go from that repository +// Bindings closely repeat the C APIs and include both, a simplified +// single-function API to just open a full-screen webview window, and a more +// advanced and featureful set of APIs, including Go-to-JavaScript bindings. +// +// The library uses gtk-webkit, Cocoa/Webkit and MSHTML (IE8..11) as a browser +// engine and supports Linux, MacOS and Windows 7..10 respectively. +// +package webview + +/* +#cgo linux openbsd freebsd CFLAGS: -DWEBVIEW_GTK=1 -Wno-deprecated-declarations +#cgo linux openbsd freebsd pkg-config: gtk+-3.0 webkit2gtk-4.0 + +#cgo windows CFLAGS: -DWEBVIEW_WINAPI=1 -std=c99 +#cgo windows LDFLAGS: -lole32 -lcomctl32 -loleaut32 -luuid -lgdi32 + +#cgo darwin CFLAGS: -DWEBVIEW_COCOA=1 -x objective-c +#cgo darwin LDFLAGS: -framework Cocoa -framework WebKit + +#include +#include +#define WEBVIEW_STATIC +#define WEBVIEW_IMPLEMENTATION +#include "webview.h" + +extern void _webviewExternalInvokeCallback(void *, void *); + +static inline void CgoWebViewFree(void *w) { + free((void *)((struct webview *)w)->title); + free((void *)((struct webview *)w)->url); + free(w); +} + +static inline void *CgoWebViewCreate(int width, int height, char *title, char *url, int resizable, int debug) { + struct webview *w = (struct webview *) calloc(1, sizeof(*w)); + w->width = width; + w->height = height; + w->title = title; + w->url = url; + w->resizable = resizable; + w->debug = debug; + w->external_invoke_cb = (webview_external_invoke_cb_t) _webviewExternalInvokeCallback; + if (webview_init(w) != 0) { + CgoWebViewFree(w); + return NULL; + } + return (void *)w; +} + +static inline int CgoWebViewLoop(void *w, int blocking) { + return webview_loop((struct webview *)w, blocking); +} + +static inline void CgoWebViewTerminate(void *w) { + webview_terminate((struct webview *)w); +} + +static inline void CgoWebViewExit(void *w) { + webview_exit((struct webview *)w); +} + +static inline void CgoWebViewSetTitle(void *w, char *title) { + webview_set_title((struct webview *)w, title); +} + +static inline void CgoWebViewFocus(void *w) { + webview_focus((struct webview *)w); +} + +static inline void CgoWebViewMinSize(void *w, int width, int height) { + webview_minsize((struct webview *)w, width, height); +} + +static inline void CgoWebViewMaxSize(void *w, int width, int height) { + webview_maxsize((struct webview *)w, width, height); +} + +static inline void CgoWebViewSetFullscreen(void *w, int fullscreen) { + webview_set_fullscreen((struct webview *)w, fullscreen); +} + +static inline void CgoWebViewSetColor(void *w, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { + webview_set_color((struct webview *)w, r, g, b, a); +} + +static inline void CgoDialog(void *w, int dlgtype, int flags, +char *title, char *arg, char *res, size_t ressz, char *filter) { + webview_dialog(w, dlgtype, flags, + (const char*)title, (const char*) arg, res, ressz, filter); +} + +static inline int CgoWebViewEval(void *w, char *js) { + return webview_eval((struct webview *)w, js); +} + +static inline void CgoWebViewInjectCSS(void *w, char *css) { + webview_inject_css((struct webview *)w, css); +} + +extern void _webviewDispatchGoCallback(void *); +static inline void _webview_dispatch_cb(struct webview *w, void *arg) { + _webviewDispatchGoCallback(arg); +} +static inline void CgoWebViewDispatch(void *w, uintptr_t arg) { + webview_dispatch((struct webview *)w, _webview_dispatch_cb, (void *)arg); +} +*/ +import "C" +import ( + "errors" + "runtime" + "sync" + "unsafe" +) + +func init() { + // Ensure that main.main is called from the main thread + runtime.LockOSThread() +} + +// Open is a simplified API to open a single native window with a full-size webview in +// it. It can be helpful if you want to communicate with the core app using XHR +// or WebSockets (as opposed to using JavaScript bindings). +// +// Window appearance can be customized using title, width, height and resizable parameters. +// URL must be provided and can user either a http or https protocol, or be a +// local file:// URL. On some platforms "data:" URLs are also supported +// (Linux/MacOS). +func Open(title, url string, w, h int, resizable bool) error { + titleStr := C.CString(title) + defer C.free(unsafe.Pointer(titleStr)) + urlStr := C.CString(url) + defer C.free(unsafe.Pointer(urlStr)) + resize := C.int(0) + if resizable { + resize = C.int(1) + } + + r := C.webview(titleStr, urlStr, C.int(w), C.int(h), resize) + if r != 0 { + return errors.New("failed to create webview") + } + return nil +} + +// ExternalInvokeCallbackFunc is a function type that is called every time +// "window.external.invoke()" is called from JavaScript. Data is the only +// obligatory string parameter passed into the "invoke(data)" function from +// JavaScript. To pass more complex data serialized JSON or base64 encoded +// string can be used. +type ExternalInvokeCallbackFunc func(w WebView, data string) + +// Settings is a set of parameters to customize the initial WebView appearance +// and behavior. It is passed into the webview.New() constructor. +type Settings struct { + // WebView main window title + Title string + // URL to open in a webview + URL string + // Window width in pixels + Width int + // Window height in pixels + Height int + // Allows/disallows window resizing + Resizable bool + // Enable debugging tools (Linux/BSD/MacOS, on Windows use Firebug) + Debug bool + // A callback that is executed when JavaScript calls "window.external.invoke()" + ExternalInvokeCallback ExternalInvokeCallbackFunc +} + +// WebView is an interface that wraps the basic methods for controlling the UI +// loop, handling multithreading and providing JavaScript bindings. +type WebView interface { + // Run() starts the main UI loop until the user closes the webview window or + // Terminate() is called. + Run() + // Loop() runs a single iteration of the main UI. + Loop(blocking bool) bool + // SetTitle() changes window title. This method must be called from the main + // thread only. See Dispatch() for more details. + SetTitle(title string) + + // Focus() puts the main window into focus + Focus() + + // SetMinSize() sets the minimum size of the window + SetMinSize(width, height int) + + // SetMaxSize() sets the maximum size of the window + SetMaxSize(width, height int) + + // SetFullscreen() controls window full-screen mode. This method must be + // called from the main thread only. See Dispatch() for more details. + SetFullscreen(fullscreen bool) + // SetColor() changes window background color. This method must be called from + // the main thread only. See Dispatch() for more details. + SetColor(r, g, b, a uint8) + // Eval() evaluates an arbitrary JS code inside the webview. This method must + // be called from the main thread only. See Dispatch() for more details. + Eval(js string) error + // InjectJS() injects an arbitrary block of CSS code using the JS API. This + // method must be called from the main thread only. See Dispatch() for more + // details. + InjectCSS(css string) + // Dialog() opens a system dialog of the given type and title. String + // argument can be provided for certain dialogs, such as alert boxes. For + // alert boxes argument is a message inside the dialog box. + Dialog(dlgType DialogType, flags int, title string, arg string, filter string) string + // Terminate() breaks the main UI loop. This method must be called from the main thread + // only. See Dispatch() for more details. + Terminate() + // Dispatch() schedules some arbitrary function to be executed on the main UI + // thread. This may be helpful if you want to run some JavaScript from + // background threads/goroutines, or to terminate the app. + Dispatch(func()) + // Exit() closes the window and cleans up the resources. Use Terminate() to + // forcefully break out of the main UI loop. + Exit() +} + +// DialogType is an enumeration of all supported system dialog types +type DialogType int + +const ( + // DialogTypeOpen is a system file open dialog + DialogTypeOpen DialogType = iota + // DialogTypeSave is a system file save dialog + DialogTypeSave + // DialogTypeAlert is a system alert dialog (message box) + DialogTypeAlert +) + +const ( + // DialogFlagFile is a normal file picker dialog + DialogFlagFile = C.WEBVIEW_DIALOG_FLAG_FILE + // DialogFlagDirectory is an open directory dialog + DialogFlagDirectory = C.WEBVIEW_DIALOG_FLAG_DIRECTORY + // DialogFlagInfo is an info alert dialog + DialogFlagInfo = C.WEBVIEW_DIALOG_FLAG_INFO + // DialogFlagWarning is a warning alert dialog + DialogFlagWarning = C.WEBVIEW_DIALOG_FLAG_WARNING + // DialogFlagError is an error dialog + DialogFlagError = C.WEBVIEW_DIALOG_FLAG_ERROR +) + +var ( + m sync.Mutex + index uintptr + fns = map[uintptr]func(){} + cbs = map[WebView]ExternalInvokeCallbackFunc{} +) + +type webview struct { + w unsafe.Pointer +} + +var _ WebView = &webview{} + +func boolToInt(b bool) int { + if b { + return 1 + } + return 0 +} + +// NewWebview creates and opens a new webview window using the given settings. The +// returned object implements the WebView interface. This function returns nil +// if a window can not be created. +func NewWebview(settings Settings) WebView { + if settings.Width == 0 { + settings.Width = 640 + } + if settings.Height == 0 { + settings.Height = 480 + } + if settings.Title == "" { + settings.Title = "WebView" + } + w := &webview{} + w.w = C.CgoWebViewCreate(C.int(settings.Width), C.int(settings.Height), + C.CString(settings.Title), C.CString(settings.URL), + C.int(boolToInt(settings.Resizable)), C.int(boolToInt(settings.Debug))) + m.Lock() + if settings.ExternalInvokeCallback != nil { + cbs[w] = settings.ExternalInvokeCallback + } else { + cbs[w] = func(w WebView, data string) {} + } + m.Unlock() + return w +} + +func (w *webview) Loop(blocking bool) bool { + block := C.int(0) + if blocking { + block = 1 + } + return C.CgoWebViewLoop(w.w, block) == 0 +} + +func (w *webview) Run() { + for w.Loop(true) { + } +} + +func (w *webview) Exit() { + C.CgoWebViewExit(w.w) +} + +func (w *webview) Dispatch(f func()) { + m.Lock() + for ; fns[index] != nil; index++ { + } + fns[index] = f + m.Unlock() + C.CgoWebViewDispatch(w.w, C.uintptr_t(index)) +} + +func (w *webview) SetTitle(title string) { + p := C.CString(title) + defer C.free(unsafe.Pointer(p)) + C.CgoWebViewSetTitle(w.w, p) +} + +func (w *webview) SetColor(r, g, b, a uint8) { + C.CgoWebViewSetColor(w.w, C.uint8_t(r), C.uint8_t(g), C.uint8_t(b), C.uint8_t(a)) +} + +func (w *webview) Focus() { + C.CgoWebViewFocus(w.w) +} + +func (w *webview) SetMinSize(width, height int) { + C.CgoWebViewMinSize(w.w, C.int(width), C.int(height)) +} + +func (w *webview) SetMaxSize(width, height int) { + C.CgoWebViewMaxSize(w.w, C.int(width), C.int(height)) +} + +func (w *webview) SetFullscreen(fullscreen bool) { + C.CgoWebViewSetFullscreen(w.w, C.int(boolToInt(fullscreen))) +} + +func (w *webview) Dialog(dlgType DialogType, flags int, title string, arg string, filter string) string { + const maxPath = 4096 + titlePtr := C.CString(title) + defer C.free(unsafe.Pointer(titlePtr)) + argPtr := C.CString(arg) + defer C.free(unsafe.Pointer(argPtr)) + resultPtr := (*C.char)(C.calloc((C.size_t)(unsafe.Sizeof((*C.char)(nil))), (C.size_t)(maxPath))) + defer C.free(unsafe.Pointer(resultPtr)) + filterPtr := C.CString(filter) + defer C.free(unsafe.Pointer(filterPtr)) + C.CgoDialog(w.w, C.int(dlgType), C.int(flags), titlePtr, + argPtr, resultPtr, C.size_t(maxPath), filterPtr) + return C.GoString(resultPtr) +} + +func (w *webview) Eval(js string) error { + p := C.CString(js) + defer C.free(unsafe.Pointer(p)) + switch C.CgoWebViewEval(w.w, p) { + case -1: + return errors.New("evaluation failed") + } + return nil +} + +func (w *webview) InjectCSS(css string) { + p := C.CString(css) + defer C.free(unsafe.Pointer(p)) + C.CgoWebViewInjectCSS(w.w, p) +} + +func (w *webview) Terminate() { + C.CgoWebViewTerminate(w.w) +} + +//export _webviewDispatchGoCallback +func _webviewDispatchGoCallback(index unsafe.Pointer) { + var f func() + m.Lock() + f = fns[uintptr(index)] + delete(fns, uintptr(index)) + m.Unlock() + if f != nil { + f() + } +} + +//export _webviewExternalInvokeCallback +func _webviewExternalInvokeCallback(w unsafe.Pointer, data unsafe.Pointer) { + m.Lock() + var ( + cb ExternalInvokeCallbackFunc + wv WebView + ) + for wv, cb = range cbs { + if wv.(*webview).w == w { + break + } + } + m.Unlock() + if cb != nil { + cb(wv, C.GoString((*C.char)(data))) + } +} diff --git a/lib/renderer/webview/webview.h b/lib/renderer/webview/webview.h new file mode 100644 index 000000000..2fb3b62d3 --- /dev/null +++ b/lib/renderer/webview/webview.h @@ -0,0 +1,2505 @@ +/* + * MIT License + * + * Copyright (c) 2017 Serge Zaitsev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef WEBVIEW_H +#define WEBVIEW_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifdef WEBVIEW_STATIC +#define WEBVIEW_API static +#else +#define WEBVIEW_API extern +#endif + +#include +#include +#include + +#if defined(WEBVIEW_GTK) +#include +#include +#include + + struct webview_priv + { + GtkWidget *window; + GtkWidget *scroller; + GtkWidget *webview; + GtkWidget *inspector_window; + GAsyncQueue *queue; + int ready; + int js_busy; + int should_exit; + + int min_width; + int min_height; + int max_width; + int max_height; + }; +#elif defined(WEBVIEW_WINAPI) +#define CINTERFACE +#include + +#include +#include +#include +#include +#include + +#include + +struct webview_priv +{ + HWND hwnd; + IOleObject **browser; + BOOL is_fullscreen; + DWORD saved_style; + DWORD saved_ex_style; + RECT saved_rect; + + int min_width; + int min_height; + int max_width; + int max_height; +}; +#elif defined(WEBVIEW_COCOA) +#import +#import +#import + +struct webview_priv +{ + NSAutoreleasePool *pool; + NSWindow *window; + WebView *webview; + id delegate; + int should_exit; +}; +#else +#error "Define one of: WEBVIEW_GTK, WEBVIEW_COCOA or WEBVIEW_WINAPI" +#endif + + struct webview; + + typedef void (*webview_external_invoke_cb_t)(struct webview *w, + const char *arg); + + struct webview + { + const char *url; + const char *title; + int width; + int height; + int resizable; + int transparentTitlebar; + int debug; + webview_external_invoke_cb_t external_invoke_cb; + struct webview_priv priv; + void *userdata; + }; + + enum webview_dialog_type + { + WEBVIEW_DIALOG_TYPE_OPEN = 0, + WEBVIEW_DIALOG_TYPE_SAVE = 1, + WEBVIEW_DIALOG_TYPE_ALERT = 2 + }; + +#define WEBVIEW_DIALOG_FLAG_FILE (0 << 0) +#define WEBVIEW_DIALOG_FLAG_DIRECTORY (1 << 0) + +#define WEBVIEW_DIALOG_FLAG_INFO (1 << 1) +#define WEBVIEW_DIALOG_FLAG_WARNING (2 << 1) +#define WEBVIEW_DIALOG_FLAG_ERROR (3 << 1) +#define WEBVIEW_DIALOG_FLAG_ALERT_MASK (3 << 1) + + typedef void (*webview_dispatch_fn)(struct webview *w, void *arg); + + struct webview_dispatch_arg + { + webview_dispatch_fn fn; + struct webview *w; + void *arg; + }; + +#define DEFAULT_URL \ + "data:text/" \ + "html,%3C%21DOCTYPE%20html%3E%0A%3Chtml%20lang=%22en%22%3E%0A%3Chead%3E%" \ + "3Cmeta%20charset=%22utf-8%22%3E%3Cmeta%20http-equiv=%22IE=edge%22%" \ + "20content=%22IE=edge%22%3E%3C%2Fhead%3E%0A%3Cbody%3E%3Cdiv%20id=%22app%22%" \ + "3E%3C%2Fdiv%3E%3Cscript%20type=%22text%2Fjavascript%22%3E%3C%2Fscript%3E%" \ + "3C%2Fbody%3E%0A%3C%2Fhtml%3E" + +#define CSS_INJECT_FUNCTION \ + "(function(e){var " \ + "t=document.createElement('style'),d=document.head||document." \ + "getElementsByTagName('head')[0];t.setAttribute('type','text/" \ + "css'),t.styleSheet?t.styleSheet.cssText=e:t.appendChild(document." \ + "createTextNode(e)),d.appendChild(t)})" + + static const char *webview_check_url(const char *url) + { + if (url == NULL || strlen(url) == 0) + { + return DEFAULT_URL; + } + return url; + } + + WEBVIEW_API int webview(const char *title, const char *url, int width, + int height, int resizable); + + WEBVIEW_API int webview_init(struct webview *w); + WEBVIEW_API int webview_loop(struct webview *w, int blocking); + WEBVIEW_API int webview_eval(struct webview *w, const char *js); + WEBVIEW_API int webview_inject_css(struct webview *w, const char *css); + WEBVIEW_API void webview_set_title(struct webview *w, const char *title); + WEBVIEW_API void webview_focus(struct webview *w); + WEBVIEW_API void webview_minsize(struct webview *w, int width, int height); + WEBVIEW_API void webview_maxsize(struct webview *w, int width, int height); + WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen); + WEBVIEW_API void webview_set_color(struct webview *w, uint8_t r, uint8_t g, + uint8_t b, uint8_t a); + WEBVIEW_API void webview_dialog(struct webview *w, + enum webview_dialog_type dlgtype, int flags, + const char *title, const char *arg, + char *result, size_t resultsz, char *filter); + WEBVIEW_API void webview_dispatch(struct webview *w, webview_dispatch_fn fn, + void *arg); + WEBVIEW_API void webview_terminate(struct webview *w); + WEBVIEW_API void webview_exit(struct webview *w); + WEBVIEW_API void webview_debug(const char *format, ...); + WEBVIEW_API void webview_print_log(const char *s); + +#ifdef WEBVIEW_IMPLEMENTATION +#undef WEBVIEW_IMPLEMENTATION + + WEBVIEW_API int webview(const char *title, const char *url, int width, + int height, int resizable) + { + struct webview webview; + memset(&webview, 0, sizeof(webview)); + webview.title = title; + webview.url = url; + webview.width = width; + webview.height = height; + webview.resizable = resizable; + int r = webview_init(&webview); + if (r != 0) + { + return r; + } + while (webview_loop(&webview, 1) == 0) + { + } + webview_exit(&webview); + return 0; + } + + WEBVIEW_API void webview_debug(const char *format, ...) + { + char buf[4096]; + va_list ap; + va_start(ap, format); + vsnprintf(buf, sizeof(buf), format, ap); + webview_print_log(buf); + va_end(ap); + } + + static int webview_js_encode(const char *s, char *esc, size_t n) + { + int r = 1; /* At least one byte for trailing zero */ + for (; *s; s++) + { + const unsigned char c = *s; + if (c >= 0x20 && c < 0x80 && strchr("<>\\'\"", c) == NULL) + { + if (n > 0) + { + *esc++ = c; + n--; + } + r++; + } + else + { + if (n > 0) + { + snprintf(esc, n, "\\x%02x", (int)c); + esc += 4; + n -= 4; + } + r += 4; + } + } + return r; + } + + WEBVIEW_API int webview_inject_css(struct webview *w, const char *css) + { + int n = webview_js_encode(css, NULL, 0); + char *esc = (char *)calloc(1, sizeof(CSS_INJECT_FUNCTION) + n + 4); + if (esc == NULL) + { + return -1; + } + char *js = (char *)calloc(1, n); + webview_js_encode(css, js, n); + snprintf(esc, sizeof(CSS_INJECT_FUNCTION) + n + 4, "%s(\"%s\")", + CSS_INJECT_FUNCTION, js); + int r = webview_eval(w, esc); + free(js); + free(esc); + return r; + } + +#if defined(WEBVIEW_GTK) + static void external_message_received_cb(WebKitUserContentManager *m, + WebKitJavascriptResult *r, + gpointer arg) + { + (void)m; + struct webview *w = (struct webview *)arg; + if (w->external_invoke_cb == NULL) + { + return; + } + JSGlobalContextRef context = webkit_javascript_result_get_global_context(r); + JSValueRef value = webkit_javascript_result_get_value(r); + JSStringRef js = JSValueToStringCopy(context, value, NULL); + size_t n = JSStringGetMaximumUTF8CStringSize(js); + char *s = g_new(char, n); + JSStringGetUTF8CString(js, s, n); + w->external_invoke_cb(w, s); + JSStringRelease(js); + g_free(s); + } + + static void webview_load_changed_cb(WebKitWebView *webview, + WebKitLoadEvent event, gpointer arg) + { + (void)webview; + struct webview *w = (struct webview *)arg; + if (event == WEBKIT_LOAD_FINISHED) + { + w->priv.ready = 1; + } + } + + static void webview_destroy_cb(GtkWidget *widget, gpointer arg) + { + (void)widget; + struct webview *w = (struct webview *)arg; + webview_terminate(w); + } + + static gboolean webview_context_menu_cb(WebKitWebView *webview, + GtkWidget *default_menu, + WebKitHitTestResult *hit_test_result, + gboolean triggered_with_keyboard, + gpointer userdata) + { + (void)webview; + (void)default_menu; + (void)hit_test_result; + (void)triggered_with_keyboard; + (void)userdata; + return TRUE; + } + + WEBVIEW_API int webview_init(struct webview *w) + { + if (gtk_init_check(0, NULL) == FALSE) + { + return -1; + } + + w->priv.ready = 0; + w->priv.should_exit = 0; + w->priv.queue = g_async_queue_new(); + w->priv.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + + w->priv.min_width = -1; + w->priv.min_height = -1; + w->priv.max_width = -1; + w->priv.max_height = -1; + + gtk_window_set_title(GTK_WINDOW(w->priv.window), w->title); + + if (w->resizable) + { + gtk_window_set_default_size(GTK_WINDOW(w->priv.window), w->width, + w->height); + } + else + { + gtk_widget_set_size_request(w->priv.window, w->width, w->height); + } + gtk_window_set_resizable(GTK_WINDOW(w->priv.window), !!w->resizable); + gtk_window_set_position(GTK_WINDOW(w->priv.window), GTK_WIN_POS_CENTER); + + w->priv.scroller = gtk_scrolled_window_new(NULL, NULL); + gtk_container_add(GTK_CONTAINER(w->priv.window), w->priv.scroller); + + WebKitUserContentManager *m = webkit_user_content_manager_new(); + webkit_user_content_manager_register_script_message_handler(m, "external"); + g_signal_connect(m, "script-message-received::external", + G_CALLBACK(external_message_received_cb), w); + + w->priv.webview = webkit_web_view_new_with_user_content_manager(m); + webkit_web_view_load_uri(WEBKIT_WEB_VIEW(w->priv.webview), + webview_check_url(w->url)); + g_signal_connect(G_OBJECT(w->priv.webview), "load-changed", + G_CALLBACK(webview_load_changed_cb), w); + gtk_container_add(GTK_CONTAINER(w->priv.scroller), w->priv.webview); + + if (w->debug) + { + WebKitSettings *settings = + webkit_web_view_get_settings(WEBKIT_WEB_VIEW(w->priv.webview)); + webkit_settings_set_enable_write_console_messages_to_stdout(settings, true); + webkit_settings_set_enable_developer_extras(settings, true); + webkit_settings_set_hardware_acceleration_policy(settings, WEBKIT_HARDWARE_ACCELERATION_POLICY_ALWAYS); + } + else + { + g_signal_connect(G_OBJECT(w->priv.webview), "context-menu", + G_CALLBACK(webview_context_menu_cb), w); + } + + gtk_widget_show_all(w->priv.window); + + webkit_web_view_run_javascript( + WEBKIT_WEB_VIEW(w->priv.webview), + "window.external={invoke:function(x){" + "window.webkit.messageHandlers.external.postMessage(x);}}", + NULL, NULL, NULL); + + g_signal_connect(G_OBJECT(w->priv.window), "destroy", + G_CALLBACK(webview_destroy_cb), w); + return 0; + } + + WEBVIEW_API int webview_loop(struct webview *w, int blocking) + { + gtk_main_iteration_do(blocking); + return w->priv.should_exit; + } + + WEBVIEW_API void webview_set_title(struct webview *w, const char *title) + { + gtk_window_set_title(GTK_WINDOW(w->priv.window), title); + } + + WEBVIEW_API void webview_focus(struct webview *w) + { + gtk_window_present(GTK_WINDOW(w->priv.window)); + } + + WEBVIEW_API void webview_minsize(struct webview *w, int width, int height) { + + w->priv.min_width = width; + w->priv.min_height = height; + + GdkGeometry hints; + GdkWindowHints usedHints = (GdkWindowHints) GDK_HINT_MIN_SIZE; + + hints.min_width = w->priv.min_width; + hints.min_height = w->priv.min_height; + if (w->priv.max_width != -1) { + hints.max_width = w->priv.max_width; + hints.max_height = w->priv.max_height; + usedHints = (GdkWindowHints)(GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE); + } + + gtk_window_set_geometry_hints(GTK_WINDOW(w->priv.window), w->priv.window, &hints, usedHints); + } + + WEBVIEW_API void webview_maxsize(struct webview *w, int width, int height) { + + w->priv.max_width = width; + w->priv.max_height = height; + + GdkGeometry hints; + GdkWindowHints usedHints = (GdkWindowHints) GDK_HINT_MAX_SIZE; + + if (w->priv.min_width != -1) { + hints.min_width = w->priv.min_width; + hints.min_height = w->priv.min_height; + usedHints = (GdkWindowHints)(GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE); + } + hints.max_width = w->priv.max_width; + hints.max_height = w->priv.max_height; + + gtk_window_set_geometry_hints(GTK_WINDOW(w->priv.window), w->priv.window, &hints, usedHints); + } + + WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen) + { + if (fullscreen) + { + gtk_window_fullscreen(GTK_WINDOW(w->priv.window)); + } + else + { + gtk_window_unfullscreen(GTK_WINDOW(w->priv.window)); + } + } + + WEBVIEW_API void webview_set_color(struct webview *w, uint8_t r, uint8_t g, + uint8_t b, uint8_t a) + { + GdkRGBA color = {r / 255.0, g / 255.0, b / 255.0, a / 255.0}; + webkit_web_view_set_background_color(WEBKIT_WEB_VIEW(w->priv.webview), + &color); + } + + WEBVIEW_API void webview_dialog(struct webview *w, + enum webview_dialog_type dlgtype, int flags, + const char *title, const char *arg, + char *result, size_t resultsz, char *filter) + { + GtkWidget *dlg; + if (result != NULL) + { + result[0] = '\0'; + } + if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN || + dlgtype == WEBVIEW_DIALOG_TYPE_SAVE) + { + dlg = gtk_file_chooser_dialog_new( + title, GTK_WINDOW(w->priv.window), + (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN + ? (flags & WEBVIEW_DIALOG_FLAG_DIRECTORY + ? GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER + : GTK_FILE_CHOOSER_ACTION_OPEN) + : GTK_FILE_CHOOSER_ACTION_SAVE), + "_Cancel", GTK_RESPONSE_CANCEL, + (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN ? "_Open" : "_Save"), + GTK_RESPONSE_ACCEPT, NULL); + if (filter[0] != '\0') { + GtkFileFilter *file_filter = gtk_file_filter_new(); + gchar **filters = g_strsplit(filter, ",", -1); + gint i; + for(i = 0; filters && filters[i]; i++) { + gtk_file_filter_add_pattern(file_filter, filters[i]); + } + gtk_file_filter_set_name(file_filter, filter); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dlg), file_filter); + g_strfreev(filters); + } + gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(dlg), FALSE); + gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dlg), FALSE); + gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dlg), TRUE); + gtk_file_chooser_set_create_folders(GTK_FILE_CHOOSER(dlg), TRUE); + gint response = gtk_dialog_run(GTK_DIALOG(dlg)); + if (response == GTK_RESPONSE_ACCEPT) + { + gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dlg)); + g_strlcpy(result, filename, resultsz); + g_free(filename); + } + gtk_widget_destroy(dlg); + } + else if (dlgtype == WEBVIEW_DIALOG_TYPE_ALERT) + { + GtkMessageType type = GTK_MESSAGE_OTHER; + switch (flags & WEBVIEW_DIALOG_FLAG_ALERT_MASK) + { + case WEBVIEW_DIALOG_FLAG_INFO: + type = GTK_MESSAGE_INFO; + break; + case WEBVIEW_DIALOG_FLAG_WARNING: + type = GTK_MESSAGE_WARNING; + break; + case WEBVIEW_DIALOG_FLAG_ERROR: + type = GTK_MESSAGE_ERROR; + break; + } + dlg = gtk_message_dialog_new(GTK_WINDOW(w->priv.window), GTK_DIALOG_MODAL, + type, GTK_BUTTONS_OK, "%s", title); + gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dlg), "%s", + arg); + gtk_dialog_run(GTK_DIALOG(dlg)); + gtk_widget_destroy(dlg); + } + } + + static void webview_eval_finished(GObject *object, GAsyncResult *result, + gpointer userdata) + { + (void)object; + (void)result; + struct webview *w = (struct webview *)userdata; + w->priv.js_busy = 0; + } + + WEBVIEW_API int webview_eval(struct webview *w, const char *js) + { + while (w->priv.ready == 0) + { + g_main_context_iteration(NULL, TRUE); + } + w->priv.js_busy = 1; + webkit_web_view_run_javascript(WEBKIT_WEB_VIEW(w->priv.webview), js, NULL, + webview_eval_finished, w); + while (w->priv.js_busy) + { + g_main_context_iteration(NULL, TRUE); + } + return 0; + } + + static gboolean webview_dispatch_wrapper(gpointer userdata) + { + struct webview *w = (struct webview *)userdata; + for (;;) + { + struct webview_dispatch_arg *arg = + (struct webview_dispatch_arg *)g_async_queue_try_pop(w->priv.queue); + if (arg == NULL) + { + break; + } + (arg->fn)(w, arg->arg); + g_free(arg); + } + return FALSE; + } + + WEBVIEW_API void webview_dispatch(struct webview *w, webview_dispatch_fn fn, + void *arg) + { + struct webview_dispatch_arg *context = + (struct webview_dispatch_arg *)g_new(struct webview_dispatch_arg *, 1); + context->w = w; + context->arg = arg; + context->fn = fn; + g_async_queue_lock(w->priv.queue); + g_async_queue_push_unlocked(w->priv.queue, context); + if (g_async_queue_length_unlocked(w->priv.queue) == 1) + { + gdk_threads_add_idle(webview_dispatch_wrapper, w); + } + g_async_queue_unlock(w->priv.queue); + } + + WEBVIEW_API void webview_terminate(struct webview *w) + { + w->priv.should_exit = 1; + } + + WEBVIEW_API void webview_exit(struct webview *w) { (void)w; } + WEBVIEW_API void webview_print_log(const char *s) + { + fprintf(stderr, "%s\n", s); + } + +#endif /* WEBVIEW_GTK */ + +#if defined(WEBVIEW_WINAPI) + +#pragma comment(lib, "user32.lib") +#pragma comment(lib, "ole32.lib") +#pragma comment(lib, "oleaut32.lib") + +#define WM_WEBVIEW_DISPATCH (WM_APP + 1) + + typedef struct + { + IOleInPlaceFrame frame; + HWND window; + } _IOleInPlaceFrameEx; + + typedef struct + { + IOleInPlaceSite inplace; + _IOleInPlaceFrameEx frame; + } _IOleInPlaceSiteEx; + + typedef struct + { + IDocHostUIHandler ui; + } _IDocHostUIHandlerEx; + + typedef struct + { + IOleClientSite client; + _IOleInPlaceSiteEx inplace; + _IDocHostUIHandlerEx ui; + IDispatch external; + } _IOleClientSiteEx; + +#ifdef __cplusplus +#define iid_ref(x) &(x) +#define iid_unref(x) *(x) +#else +#define iid_ref(x) (x) +#define iid_unref(x) (x) +#endif + + static inline WCHAR *webview_to_utf16(const char *s) + { + DWORD size = MultiByteToWideChar(CP_UTF8, 0, s, -1, 0, 0); + WCHAR *ws = (WCHAR *)GlobalAlloc(GMEM_FIXED, sizeof(WCHAR) * size); + if (ws == NULL) + { + return NULL; + } + MultiByteToWideChar(CP_UTF8, 0, s, -1, ws, size); + return ws; + } + + static inline char *webview_from_utf16(WCHAR *ws) + { + int n = WideCharToMultiByte(CP_UTF8, 0, ws, -1, NULL, 0, NULL, NULL); + char *s = (char *)GlobalAlloc(GMEM_FIXED, n); + if (s == NULL) + { + return NULL; + } + WideCharToMultiByte(CP_UTF8, 0, ws, -1, s, n, NULL, NULL); + return s; + } + + static int iid_eq(REFIID a, const IID *b) + { + return memcmp((const void *)iid_ref(a), (const void *)b, sizeof(GUID)) == 0; + } + + static HRESULT STDMETHODCALLTYPE JS_QueryInterface(IDispatch FAR *This, + REFIID riid, + LPVOID FAR *ppvObj) + { + if (iid_eq(riid, &IID_IDispatch)) + { + *ppvObj = This; + return S_OK; + } + *ppvObj = 0; + return E_NOINTERFACE; + } + static ULONG STDMETHODCALLTYPE JS_AddRef(IDispatch FAR *This) { return 1; } + static ULONG STDMETHODCALLTYPE JS_Release(IDispatch FAR *This) { return 1; } + static HRESULT STDMETHODCALLTYPE JS_GetTypeInfoCount(IDispatch FAR *This, + UINT *pctinfo) + { + return S_OK; + } + static HRESULT STDMETHODCALLTYPE JS_GetTypeInfo(IDispatch FAR *This, + UINT iTInfo, LCID lcid, + ITypeInfo **ppTInfo) + { + return S_OK; + } +#define WEBVIEW_JS_INVOKE_ID 0x1000 + static HRESULT STDMETHODCALLTYPE JS_GetIDsOfNames(IDispatch FAR *This, + REFIID riid, + LPOLESTR *rgszNames, + UINT cNames, LCID lcid, + DISPID *rgDispId) + { + if (cNames != 1) + { + return S_FALSE; + } + if (wcscmp(rgszNames[0], L"invoke") == 0) + { + rgDispId[0] = WEBVIEW_JS_INVOKE_ID; + return S_OK; + } + return S_FALSE; + } + + static HRESULT STDMETHODCALLTYPE + JS_Invoke(IDispatch FAR *This, DISPID dispIdMember, REFIID riid, LCID lcid, + WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, UINT *puArgErr) + { + size_t offset = (size_t) & ((_IOleClientSiteEx *)NULL)->external; + _IOleClientSiteEx *ex = (_IOleClientSiteEx *)((char *)(This)-offset); + struct webview *w = (struct webview *)GetWindowLongPtr( + ex->inplace.frame.window, GWLP_USERDATA); + if (pDispParams->cArgs == 1 && pDispParams->rgvarg[0].vt == VT_BSTR) + { + BSTR bstr = pDispParams->rgvarg[0].bstrVal; + char *s = webview_from_utf16(bstr); + if (s != NULL) + { + if (dispIdMember == WEBVIEW_JS_INVOKE_ID) + { + if (w->external_invoke_cb != NULL) + { + w->external_invoke_cb(w, s); + } + } + else + { + return S_FALSE; + } + GlobalFree(s); + } + } + return S_OK; + } + + static IDispatchVtbl ExternalDispatchTable = { + JS_QueryInterface, JS_AddRef, JS_Release, JS_GetTypeInfoCount, + JS_GetTypeInfo, JS_GetIDsOfNames, JS_Invoke}; + + static ULONG STDMETHODCALLTYPE Site_AddRef(IOleClientSite FAR *This) + { + return 1; + } + static ULONG STDMETHODCALLTYPE Site_Release(IOleClientSite FAR *This) + { + return 1; + } + static HRESULT STDMETHODCALLTYPE Site_SaveObject(IOleClientSite FAR *This) + { + return E_NOTIMPL; + } + static HRESULT STDMETHODCALLTYPE Site_GetMoniker(IOleClientSite FAR *This, + DWORD dwAssign, + DWORD dwWhichMoniker, + IMoniker **ppmk) + { + return E_NOTIMPL; + } + static HRESULT STDMETHODCALLTYPE + Site_GetContainer(IOleClientSite FAR *This, LPOLECONTAINER FAR *ppContainer) + { + *ppContainer = 0; + return E_NOINTERFACE; + } + static HRESULT STDMETHODCALLTYPE Site_ShowObject(IOleClientSite FAR *This) + { + return NOERROR; + } + static HRESULT STDMETHODCALLTYPE Site_OnShowWindow(IOleClientSite FAR *This, + BOOL fShow) + { + return E_NOTIMPL; + } + static HRESULT STDMETHODCALLTYPE + Site_RequestNewObjectLayout(IOleClientSite FAR *This) + { + return E_NOTIMPL; + } + static HRESULT STDMETHODCALLTYPE Site_QueryInterface(IOleClientSite FAR *This, + REFIID riid, + void **ppvObject) + { + if (iid_eq(riid, &IID_IUnknown) || iid_eq(riid, &IID_IOleClientSite)) + { + *ppvObject = &((_IOleClientSiteEx *)This)->client; + } + else if (iid_eq(riid, &IID_IOleInPlaceSite)) + { + *ppvObject = &((_IOleClientSiteEx *)This)->inplace; + } + else if (iid_eq(riid, &IID_IDocHostUIHandler)) + { + *ppvObject = &((_IOleClientSiteEx *)This)->ui; + } + else + { + *ppvObject = 0; + return (E_NOINTERFACE); + } + return S_OK; + } + static HRESULT STDMETHODCALLTYPE InPlace_QueryInterface( + IOleInPlaceSite FAR *This, REFIID riid, LPVOID FAR *ppvObj) + { + return (Site_QueryInterface( + (IOleClientSite *)((char *)This - sizeof(IOleClientSite)), riid, ppvObj)); + } + static ULONG STDMETHODCALLTYPE InPlace_AddRef(IOleInPlaceSite FAR *This) + { + return 1; + } + static ULONG STDMETHODCALLTYPE InPlace_Release(IOleInPlaceSite FAR *This) + { + return 1; + } + static HRESULT STDMETHODCALLTYPE InPlace_GetWindow(IOleInPlaceSite FAR *This, + HWND FAR *lphwnd) + { + *lphwnd = ((_IOleInPlaceSiteEx FAR *)This)->frame.window; + return S_OK; + } + static HRESULT STDMETHODCALLTYPE + InPlace_ContextSensitiveHelp(IOleInPlaceSite FAR *This, BOOL fEnterMode) + { + return E_NOTIMPL; + } + static HRESULT STDMETHODCALLTYPE + InPlace_CanInPlaceActivate(IOleInPlaceSite FAR *This) + { + return S_OK; + } + static HRESULT STDMETHODCALLTYPE + InPlace_OnInPlaceActivate(IOleInPlaceSite FAR *This) + { + return S_OK; + } + static HRESULT STDMETHODCALLTYPE + InPlace_OnUIActivate(IOleInPlaceSite FAR *This) + { + return S_OK; + } + static HRESULT STDMETHODCALLTYPE InPlace_GetWindowContext( + IOleInPlaceSite FAR *This, LPOLEINPLACEFRAME FAR *lplpFrame, + LPOLEINPLACEUIWINDOW FAR *lplpDoc, LPRECT lprcPosRect, LPRECT lprcClipRect, + LPOLEINPLACEFRAMEINFO lpFrameInfo) + { + *lplpFrame = (LPOLEINPLACEFRAME) & ((_IOleInPlaceSiteEx *)This)->frame; + *lplpDoc = 0; + lpFrameInfo->fMDIApp = FALSE; + lpFrameInfo->hwndFrame = ((_IOleInPlaceFrameEx *)*lplpFrame)->window; + lpFrameInfo->haccel = 0; + lpFrameInfo->cAccelEntries = 0; + return S_OK; + } + static HRESULT STDMETHODCALLTYPE InPlace_Scroll(IOleInPlaceSite FAR *This, + SIZE scrollExtent) + { + return E_NOTIMPL; + } + static HRESULT STDMETHODCALLTYPE + InPlace_OnUIDeactivate(IOleInPlaceSite FAR *This, BOOL fUndoable) + { + return S_OK; + } + static HRESULT STDMETHODCALLTYPE + InPlace_OnInPlaceDeactivate(IOleInPlaceSite FAR *This) + { + return S_OK; + } + static HRESULT STDMETHODCALLTYPE + InPlace_DiscardUndoState(IOleInPlaceSite FAR *This) + { + return E_NOTIMPL; + } + static HRESULT STDMETHODCALLTYPE + InPlace_DeactivateAndUndo(IOleInPlaceSite FAR *This) + { + return E_NOTIMPL; + } + static HRESULT STDMETHODCALLTYPE + InPlace_OnPosRectChange(IOleInPlaceSite FAR *This, LPCRECT lprcPosRect) + { + IOleObject *browserObject; + IOleInPlaceObject *inplace; + browserObject = *((IOleObject **)((char *)This - sizeof(IOleObject *) - + sizeof(IOleClientSite))); + if (!browserObject->lpVtbl->QueryInterface(browserObject, + iid_unref(&IID_IOleInPlaceObject), + (void **)&inplace)) + { + inplace->lpVtbl->SetObjectRects(inplace, lprcPosRect, lprcPosRect); + inplace->lpVtbl->Release(inplace); + } + return S_OK; + } + static HRESULT STDMETHODCALLTYPE Frame_QueryInterface( + IOleInPlaceFrame FAR *This, REFIID riid, LPVOID FAR *ppvObj) + { + return E_NOTIMPL; + } + static ULONG STDMETHODCALLTYPE Frame_AddRef(IOleInPlaceFrame FAR *This) + { + return 1; + } + static ULONG STDMETHODCALLTYPE Frame_Release(IOleInPlaceFrame FAR *This) + { + return 1; + } + static HRESULT STDMETHODCALLTYPE Frame_GetWindow(IOleInPlaceFrame FAR *This, + HWND FAR *lphwnd) + { + *lphwnd = ((_IOleInPlaceFrameEx *)This)->window; + return S_OK; + } + static HRESULT STDMETHODCALLTYPE + Frame_ContextSensitiveHelp(IOleInPlaceFrame FAR *This, BOOL fEnterMode) + { + return E_NOTIMPL; + } + static HRESULT STDMETHODCALLTYPE Frame_GetBorder(IOleInPlaceFrame FAR *This, + LPRECT lprectBorder) + { + return E_NOTIMPL; + } + static HRESULT STDMETHODCALLTYPE Frame_RequestBorderSpace( + IOleInPlaceFrame FAR *This, LPCBORDERWIDTHS pborderwidths) + { + return E_NOTIMPL; + } + static HRESULT STDMETHODCALLTYPE Frame_SetBorderSpace( + IOleInPlaceFrame FAR *This, LPCBORDERWIDTHS pborderwidths) + { + return E_NOTIMPL; + } + static HRESULT STDMETHODCALLTYPE Frame_SetActiveObject( + IOleInPlaceFrame FAR *This, IOleInPlaceActiveObject *pActiveObject, + LPCOLESTR pszObjName) + { + return S_OK; + } + static HRESULT STDMETHODCALLTYPE + Frame_InsertMenus(IOleInPlaceFrame FAR *This, HMENU hmenuShared, + LPOLEMENUGROUPWIDTHS lpMenuWidths) + { + return E_NOTIMPL; + } + static HRESULT STDMETHODCALLTYPE Frame_SetMenu(IOleInPlaceFrame FAR *This, + HMENU hmenuShared, + HOLEMENU holemenu, + HWND hwndActiveObject) + { + return S_OK; + } + static HRESULT STDMETHODCALLTYPE Frame_RemoveMenus(IOleInPlaceFrame FAR *This, + HMENU hmenuShared) + { + return E_NOTIMPL; + } + static HRESULT STDMETHODCALLTYPE Frame_SetStatusText(IOleInPlaceFrame FAR *This, + LPCOLESTR pszStatusText) + { + return S_OK; + } + static HRESULT STDMETHODCALLTYPE + Frame_EnableModeless(IOleInPlaceFrame FAR *This, BOOL fEnable) + { + return S_OK; + } + static HRESULT STDMETHODCALLTYPE + Frame_TranslateAccelerator(IOleInPlaceFrame FAR *This, LPMSG lpmsg, WORD wID) + { + return E_NOTIMPL; + } + static HRESULT STDMETHODCALLTYPE UI_QueryInterface(IDocHostUIHandler FAR *This, + REFIID riid, + LPVOID FAR *ppvObj) + { + return (Site_QueryInterface((IOleClientSite *)((char *)This - + sizeof(IOleClientSite) - + sizeof(_IOleInPlaceSiteEx)), + riid, ppvObj)); + } + static ULONG STDMETHODCALLTYPE UI_AddRef(IDocHostUIHandler FAR *This) + { + return 1; + } + static ULONG STDMETHODCALLTYPE UI_Release(IDocHostUIHandler FAR *This) + { + return 1; + } + static HRESULT STDMETHODCALLTYPE UI_ShowContextMenu( + IDocHostUIHandler FAR *This, DWORD dwID, POINT __RPC_FAR *ppt, + IUnknown __RPC_FAR *pcmdtReserved, IDispatch __RPC_FAR *pdispReserved) + { + return S_OK; + } + static HRESULT STDMETHODCALLTYPE + UI_GetHostInfo(IDocHostUIHandler FAR *This, DOCHOSTUIINFO __RPC_FAR *pInfo) + { + pInfo->cbSize = sizeof(DOCHOSTUIINFO); + pInfo->dwFlags = DOCHOSTUIFLAG_NO3DBORDER; + pInfo->dwDoubleClick = DOCHOSTUIDBLCLK_DEFAULT; + return S_OK; + } + static HRESULT STDMETHODCALLTYPE UI_ShowUI( + IDocHostUIHandler FAR *This, DWORD dwID, + IOleInPlaceActiveObject __RPC_FAR *pActiveObject, + IOleCommandTarget __RPC_FAR *pCommandTarget, + IOleInPlaceFrame __RPC_FAR *pFrame, IOleInPlaceUIWindow __RPC_FAR *pDoc) + { + return S_OK; + } + static HRESULT STDMETHODCALLTYPE UI_HideUI(IDocHostUIHandler FAR *This) + { + return S_OK; + } + static HRESULT STDMETHODCALLTYPE UI_UpdateUI(IDocHostUIHandler FAR *This) + { + return S_OK; + } + static HRESULT STDMETHODCALLTYPE UI_EnableModeless(IDocHostUIHandler FAR *This, + BOOL fEnable) + { + return S_OK; + } + static HRESULT STDMETHODCALLTYPE + UI_OnDocWindowActivate(IDocHostUIHandler FAR *This, BOOL fActivate) + { + return S_OK; + } + static HRESULT STDMETHODCALLTYPE + UI_OnFrameWindowActivate(IDocHostUIHandler FAR *This, BOOL fActivate) + { + return S_OK; + } + static HRESULT STDMETHODCALLTYPE + UI_ResizeBorder(IDocHostUIHandler FAR *This, LPCRECT prcBorder, + IOleInPlaceUIWindow __RPC_FAR *pUIWindow, BOOL fRameWindow) + { + return S_OK; + } + static HRESULT STDMETHODCALLTYPE + UI_TranslateAccelerator(IDocHostUIHandler FAR *This, LPMSG lpMsg, + const GUID __RPC_FAR *pguidCmdGroup, DWORD nCmdID) + { + return S_FALSE; + } + static HRESULT STDMETHODCALLTYPE UI_GetOptionKeyPath( + IDocHostUIHandler FAR *This, LPOLESTR __RPC_FAR *pchKey, DWORD dw) + { + return S_FALSE; + } + static HRESULT STDMETHODCALLTYPE UI_GetDropTarget( + IDocHostUIHandler FAR *This, IDropTarget __RPC_FAR *pDropTarget, + IDropTarget __RPC_FAR *__RPC_FAR *ppDropTarget) + { + return S_FALSE; + } + static HRESULT STDMETHODCALLTYPE UI_GetExternal( + IDocHostUIHandler FAR *This, IDispatch __RPC_FAR *__RPC_FAR *ppDispatch) + { + *ppDispatch = (IDispatch *)(This + 1); + return S_OK; + } + static HRESULT STDMETHODCALLTYPE UI_TranslateUrl( + IDocHostUIHandler FAR *This, DWORD dwTranslate, OLECHAR __RPC_FAR *pchURLIn, + OLECHAR __RPC_FAR *__RPC_FAR *ppchURLOut) + { + *ppchURLOut = 0; + return S_FALSE; + } + static HRESULT STDMETHODCALLTYPE + UI_FilterDataObject(IDocHostUIHandler FAR *This, IDataObject __RPC_FAR *pDO, + IDataObject __RPC_FAR *__RPC_FAR *ppDORet) + { + *ppDORet = 0; + return S_FALSE; + } + + static const TCHAR *classname = TEXT("WebView"); + static const SAFEARRAYBOUND ArrayBound = {1, 0}; + + static IOleClientSiteVtbl MyIOleClientSiteTable = { + Site_QueryInterface, Site_AddRef, Site_Release, + Site_SaveObject, Site_GetMoniker, Site_GetContainer, + Site_ShowObject, Site_OnShowWindow, Site_RequestNewObjectLayout}; + static IOleInPlaceSiteVtbl MyIOleInPlaceSiteTable = { + InPlace_QueryInterface, + InPlace_AddRef, + InPlace_Release, + InPlace_GetWindow, + InPlace_ContextSensitiveHelp, + InPlace_CanInPlaceActivate, + InPlace_OnInPlaceActivate, + InPlace_OnUIActivate, + InPlace_GetWindowContext, + InPlace_Scroll, + InPlace_OnUIDeactivate, + InPlace_OnInPlaceDeactivate, + InPlace_DiscardUndoState, + InPlace_DeactivateAndUndo, + InPlace_OnPosRectChange}; + + static IOleInPlaceFrameVtbl MyIOleInPlaceFrameTable = { + Frame_QueryInterface, + Frame_AddRef, + Frame_Release, + Frame_GetWindow, + Frame_ContextSensitiveHelp, + Frame_GetBorder, + Frame_RequestBorderSpace, + Frame_SetBorderSpace, + Frame_SetActiveObject, + Frame_InsertMenus, + Frame_SetMenu, + Frame_RemoveMenus, + Frame_SetStatusText, + Frame_EnableModeless, + Frame_TranslateAccelerator}; + + static IDocHostUIHandlerVtbl MyIDocHostUIHandlerTable = { + UI_QueryInterface, + UI_AddRef, + UI_Release, + UI_ShowContextMenu, + UI_GetHostInfo, + UI_ShowUI, + UI_HideUI, + UI_UpdateUI, + UI_EnableModeless, + UI_OnDocWindowActivate, + UI_OnFrameWindowActivate, + UI_ResizeBorder, + UI_TranslateAccelerator, + UI_GetOptionKeyPath, + UI_GetDropTarget, + UI_GetExternal, + UI_TranslateUrl, + UI_FilterDataObject}; + + static void UnEmbedBrowserObject(struct webview *w) + { + if (w->priv.browser != NULL) + { + (*w->priv.browser)->lpVtbl->Close(*w->priv.browser, OLECLOSE_NOSAVE); + (*w->priv.browser)->lpVtbl->Release(*w->priv.browser); + GlobalFree(w->priv.browser); + w->priv.browser = NULL; + } + } + + static int EmbedBrowserObject(struct webview *w) + { + RECT rect; + IWebBrowser2 *webBrowser2 = NULL; + LPCLASSFACTORY pClassFactory = NULL; + _IOleClientSiteEx *_iOleClientSiteEx = NULL; + IOleObject **browser = (IOleObject **)GlobalAlloc( + GMEM_FIXED, sizeof(IOleObject *) + sizeof(_IOleClientSiteEx)); + if (browser == NULL) + { + goto error; + } + w->priv.browser = browser; + + _iOleClientSiteEx = (_IOleClientSiteEx *)(browser + 1); + _iOleClientSiteEx->client.lpVtbl = &MyIOleClientSiteTable; + _iOleClientSiteEx->inplace.inplace.lpVtbl = &MyIOleInPlaceSiteTable; + _iOleClientSiteEx->inplace.frame.frame.lpVtbl = &MyIOleInPlaceFrameTable; + _iOleClientSiteEx->inplace.frame.window = w->priv.hwnd; + _iOleClientSiteEx->ui.ui.lpVtbl = &MyIDocHostUIHandlerTable; + _iOleClientSiteEx->external.lpVtbl = &ExternalDispatchTable; + + if (CoGetClassObject(iid_unref(&CLSID_WebBrowser), + CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, NULL, + iid_unref(&IID_IClassFactory), + (void **)&pClassFactory) != S_OK) + { + goto error; + } + + if (pClassFactory == NULL) + { + goto error; + } + + if (pClassFactory->lpVtbl->CreateInstance(pClassFactory, 0, + iid_unref(&IID_IOleObject), + (void **)browser) != S_OK) + { + goto error; + } + pClassFactory->lpVtbl->Release(pClassFactory); + if ((*browser)->lpVtbl->SetClientSite( + *browser, (IOleClientSite *)_iOleClientSiteEx) != S_OK) + { + goto error; + } + (*browser)->lpVtbl->SetHostNames(*browser, L"My Host Name", 0); + + if (OleSetContainedObject((struct IUnknown *)(*browser), TRUE) != S_OK) + { + goto error; + } + GetClientRect(w->priv.hwnd, &rect); + if ((*browser)->lpVtbl->DoVerb((*browser), OLEIVERB_SHOW, NULL, + (IOleClientSite *)_iOleClientSiteEx, -1, + w->priv.hwnd, &rect) != S_OK) + { + goto error; + } + if ((*browser)->lpVtbl->QueryInterface((*browser), + iid_unref(&IID_IWebBrowser2), + (void **)&webBrowser2) != S_OK) + { + goto error; + } + + webBrowser2->lpVtbl->put_Left(webBrowser2, 0); + webBrowser2->lpVtbl->put_Top(webBrowser2, 0); + webBrowser2->lpVtbl->put_Width(webBrowser2, rect.right); + webBrowser2->lpVtbl->put_Height(webBrowser2, rect.bottom); + webBrowser2->lpVtbl->Release(webBrowser2); + + return 0; + error: + UnEmbedBrowserObject(w); + if (pClassFactory != NULL) + { + pClassFactory->lpVtbl->Release(pClassFactory); + } + if (browser != NULL) + { + GlobalFree(browser); + } + return -1; + } + +#define WEBVIEW_DATA_URL_PREFIX "data:text/html," + static int DisplayHTMLPage(struct webview *w) + { + IWebBrowser2 *webBrowser2; + VARIANT myURL; + LPDISPATCH lpDispatch; + IHTMLDocument2 *htmlDoc2; + BSTR bstr; + IOleObject *browserObject; + SAFEARRAY *sfArray; + VARIANT *pVar; + browserObject = *w->priv.browser; + int isDataURL = 0; + const char *webview_url = webview_check_url(w->url); + if (!browserObject->lpVtbl->QueryInterface( + browserObject, iid_unref(&IID_IWebBrowser2), (void **)&webBrowser2)) + { + LPCSTR webPageName; + isDataURL = (strncmp(webview_url, WEBVIEW_DATA_URL_PREFIX, + strlen(WEBVIEW_DATA_URL_PREFIX)) == 0); + if (isDataURL) + { + webPageName = "about:blank"; + } + else + { + webPageName = (LPCSTR)webview_url; + } + VariantInit(&myURL); + myURL.vt = VT_BSTR; + // #ifndef UNICODE + { + wchar_t *buffer = webview_to_utf16(webPageName); + if (buffer == NULL) + { + goto badalloc; + } + myURL.bstrVal = SysAllocString(buffer); + GlobalFree(buffer); + } + // #else + // myURL.bstrVal = SysAllocString(webPageName); + // #endif + if (!myURL.bstrVal) + { + badalloc: + webBrowser2->lpVtbl->Release(webBrowser2); + return (-6); + } + webBrowser2->lpVtbl->Navigate2(webBrowser2, &myURL, 0, 0, 0, 0); + VariantClear(&myURL); + if (!isDataURL) + { + return 0; + } + + char *url = (char *)calloc(1, strlen(webview_url) + 1); + char *q = url; + for (const char *p = webview_url + strlen(WEBVIEW_DATA_URL_PREFIX); *q = *p; + p++, q++) + { + if (*q == '%' && *(p + 1) && *(p + 2)) + { + sscanf(p + 1, "%02x", q); + p = p + 2; + } + } + + if (webBrowser2->lpVtbl->get_Document(webBrowser2, &lpDispatch) == S_OK) + { + if (lpDispatch->lpVtbl->QueryInterface(lpDispatch, + iid_unref(&IID_IHTMLDocument2), + (void **)&htmlDoc2) == S_OK) + { + if ((sfArray = SafeArrayCreate(VT_VARIANT, 1, + (SAFEARRAYBOUND *)&ArrayBound))) + { + if (!SafeArrayAccessData(sfArray, (void **)&pVar)) + { + pVar->vt = VT_BSTR; + // #ifndef UNICODE + { + wchar_t *buffer = webview_to_utf16(url); + if (buffer == NULL) + { + goto release; + } + bstr = SysAllocString(buffer); + GlobalFree(buffer); + } + // #else + // bstr = SysAllocString(url); + // #endif + if ((pVar->bstrVal = bstr)) + { + htmlDoc2->lpVtbl->write(htmlDoc2, sfArray); + htmlDoc2->lpVtbl->close(htmlDoc2); + } + } + SafeArrayDestroy(sfArray); + } + release: + free(url); + htmlDoc2->lpVtbl->Release(htmlDoc2); + } + lpDispatch->lpVtbl->Release(lpDispatch); + } + webBrowser2->lpVtbl->Release(webBrowser2); + return (0); + } + return (-5); + } + + static LRESULT CALLBACK wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, + LPARAM lParam) + { + struct webview *w = (struct webview *)GetWindowLongPtr(hwnd, GWLP_USERDATA); + switch (uMsg) + { + case WM_CREATE: + w = (struct webview *)((CREATESTRUCT *)lParam)->lpCreateParams; + w->priv.hwnd = hwnd; + + return EmbedBrowserObject(w); + case WM_GETMINMAXINFO: + { + if (w != NULL) { + // get pixel density + HDC hDC = GetDC(NULL); + double DPIScaleX = GetDeviceCaps(hDC, 88)/96.0; + double DPIScaleY = GetDeviceCaps(hDC, 90)/96.0; + ReleaseDC(NULL, hDC); + + RECT rcClient, rcWind; + POINT ptDiff; + GetClientRect(hwnd, &rcClient); + GetWindowRect(hwnd, &rcWind); + + int widthExtra = (rcWind.right - rcWind.left) - rcClient.right; + int heightExtra = (rcWind.bottom - rcWind.top) - rcClient.bottom; + + LPMINMAXINFO lpMMI = (LPMINMAXINFO)lParam; + + if (w->priv.min_width != -1) { + lpMMI->ptMinTrackSize.x = w->priv.min_width * DPIScaleX + widthExtra; + lpMMI->ptMinTrackSize.y = w->priv.min_height * DPIScaleY + heightExtra; + } + if (w->priv.max_width != -1) { + lpMMI->ptMaxTrackSize.x = w->priv.max_width * DPIScaleX + widthExtra; + lpMMI->ptMaxTrackSize.y = w->priv.max_height * DPIScaleY + heightExtra; + } + } + + return 0; + } + case WM_DESTROY: + UnEmbedBrowserObject(w); + PostQuitMessage(0); + return TRUE; + case WM_SIZE: + { + IWebBrowser2 *webBrowser2; + IOleObject *browser = *w->priv.browser; + if (browser->lpVtbl->QueryInterface(browser, iid_unref(&IID_IWebBrowser2), + (void **)&webBrowser2) == S_OK) + { + RECT rect; + GetClientRect(hwnd, &rect); + webBrowser2->lpVtbl->put_Width(webBrowser2, rect.right); + webBrowser2->lpVtbl->put_Height(webBrowser2, rect.bottom); + } + return TRUE; + } + case WM_WEBVIEW_DISPATCH: + { + webview_dispatch_fn f = (webview_dispatch_fn)wParam; + void *arg = (void *)lParam; + (*f)(w, arg); + return TRUE; + } + } + return DefWindowProc(hwnd, uMsg, wParam, lParam); + } + +#define WEBVIEW_KEY_FEATURE_BROWSER_EMULATION \ + "Software\\Microsoft\\Internet " \ + "Explorer\\Main\\FeatureControl\\FEATURE_BROWSER_EMULATION" + + static int webview_fix_ie_compat_mode() + { + HKEY hKey; + DWORD ie_version = 11000; + TCHAR appname[MAX_PATH + 1]; + TCHAR *p; + if (GetModuleFileName(NULL, appname, MAX_PATH + 1) == 0) + { + return -1; + } + for (p = &appname[strlen(appname) - 1]; p != appname && *p != '\\'; p--) + { + } + p++; + if (RegCreateKey(HKEY_CURRENT_USER, WEBVIEW_KEY_FEATURE_BROWSER_EMULATION, + &hKey) != ERROR_SUCCESS) + { + return -1; + } + if (RegSetValueEx(hKey, p, 0, REG_DWORD, (BYTE *)&ie_version, + sizeof(ie_version)) != ERROR_SUCCESS) + { + RegCloseKey(hKey); + return -1; + } + RegCloseKey(hKey); + return 0; + } + + WEBVIEW_API int webview_init(struct webview *w) + { + w->priv.min_width = -1; + w->priv.max_width = -1; + + WNDCLASSEX wc; + HINSTANCE hInstance; + DWORD style; + RECT clientRect; + RECT rect; + + if (webview_fix_ie_compat_mode() < 0) + { + return -1; + } + + hInstance = GetModuleHandle(NULL); + if (hInstance == NULL) + { + return -1; + } + if (OleInitialize(NULL) != S_OK) + { + return -1; + } + + ZeroMemory(&wc, sizeof(WNDCLASSEX)); + wc.cbSize = sizeof(WNDCLASSEX); + wc.hInstance = hInstance; + wc.lpfnWndProc = wndproc; + wc.lpszClassName = classname; + wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(100)); + wc.hIconSm = LoadIcon(hInstance, MAKEINTRESOURCE(100)); + RegisterClassEx(&wc); + + style = WS_OVERLAPPEDWINDOW; + if (!w->resizable) + { + style = WS_OVERLAPPED | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU; + } + + // Scale + // Credit: https://github.com/webview/webview/issues/54#issuecomment-379528243 + HDC hDC = GetDC(NULL); + w->width = GetDeviceCaps(hDC, 88)*w->width/96.0; + w->height = GetDeviceCaps(hDC, 90)*w->height/96.0; + ReleaseDC(NULL, hDC); + + rect.left = 0; + rect.top = 0; + rect.right = w->width; + rect.bottom = w->height; + AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, 0); + + GetClientRect(GetDesktopWindow(), &clientRect); + int left = (clientRect.right / 2) - ((rect.right - rect.left) / 2); + int top = (clientRect.bottom / 2) - ((rect.bottom - rect.top) / 2); + rect.right = rect.right - rect.left + left; + rect.left = left; + rect.bottom = rect.bottom - rect.top + top; + rect.top = top; + +#ifdef UNICODE + wchar_t *u16title = webview_to_utf16(w->title); + if (u16title == NULL) + { + return -1; + } + + w->priv.hwnd = + CreateWindowEx(0, classname, u16title, style, rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + HWND_DESKTOP, NULL, hInstance, (void *)w); +#else + w->priv.hwnd = + CreateWindowEx(0, classname, w->title, style, rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + HWND_DESKTOP, NULL, hInstance, (void *)w); +#endif + + if (w->priv.hwnd == 0) + { + OleUninitialize(); + return -1; + } + + SetWindowLongPtr(w->priv.hwnd, GWLP_USERDATA, (LONG_PTR)w); + + DisplayHTMLPage(w); + +#ifdef UNICODE + SetWindowText(w->priv.hwnd, u16title); + GlobalFree(u16title); +#else + SetWindowText(w->priv.hwnd, w->title); +#endif + + ShowWindow(w->priv.hwnd, SW_SHOWDEFAULT); + UpdateWindow(w->priv.hwnd); + SetFocus(w->priv.hwnd); + + return 0; + } + + WEBVIEW_API int webview_loop(struct webview *w, int blocking) + { + MSG msg; + if (blocking) + { + GetMessage(&msg, 0, 0, 0); + } + else + { + PeekMessage(&msg, 0, 0, 0, PM_REMOVE); + } + switch (msg.message) + { + case WM_QUIT: + return -1; + case WM_COMMAND: + case WM_KEYDOWN: + case WM_KEYUP: + { + // Disable refresh when pressing F5 on windows + if (msg.wParam == VK_F5) + { + break; + } + HRESULT r = S_OK; + IWebBrowser2 *webBrowser2; + IOleObject *browser = *w->priv.browser; + if (browser->lpVtbl->QueryInterface(browser, iid_unref(&IID_IWebBrowser2), + (void **)&webBrowser2) == S_OK) + { + IOleInPlaceActiveObject *pIOIPAO; + if (browser->lpVtbl->QueryInterface( + browser, iid_unref(&IID_IOleInPlaceActiveObject), + (void **)&pIOIPAO) == S_OK) + { + r = pIOIPAO->lpVtbl->TranslateAccelerator(pIOIPAO, &msg); + pIOIPAO->lpVtbl->Release(pIOIPAO); + } + webBrowser2->lpVtbl->Release(webBrowser2); + } + if (r != S_FALSE) + { + break; + } + } + default: + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return 0; + } + + WEBVIEW_API int webview_eval(struct webview *w, const char *js) + { + IWebBrowser2 *webBrowser2; + IHTMLDocument2 *htmlDoc2; + IDispatch *docDispatch; + IDispatch *scriptDispatch; + if ((*w->priv.browser) + ->lpVtbl->QueryInterface((*w->priv.browser), + iid_unref(&IID_IWebBrowser2), + (void **)&webBrowser2) != S_OK) + { + return -1; + } + + if (webBrowser2->lpVtbl->get_Document(webBrowser2, &docDispatch) != S_OK) + { + return -1; + } + if (docDispatch->lpVtbl->QueryInterface(docDispatch, + iid_unref(&IID_IHTMLDocument2), + (void **)&htmlDoc2) != S_OK) + { + return -1; + } + if (htmlDoc2->lpVtbl->get_Script(htmlDoc2, &scriptDispatch) != S_OK) + { + return -1; + } + DISPID dispid; + BSTR evalStr = SysAllocString(L"eval"); + if (scriptDispatch->lpVtbl->GetIDsOfNames( + scriptDispatch, iid_unref(&IID_NULL), &evalStr, 1, + LOCALE_SYSTEM_DEFAULT, &dispid) != S_OK) + { + SysFreeString(evalStr); + return -1; + } + SysFreeString(evalStr); + + DISPPARAMS params; + VARIANT arg; + VARIANT result; + EXCEPINFO excepInfo; + UINT nArgErr = (UINT)-1; + params.cArgs = 1; + params.cNamedArgs = 0; + params.rgvarg = &arg; + arg.vt = VT_BSTR; + static const char *prologue = "(function(){"; + static const char *epilogue = ";})();"; + int n = strlen(prologue) + strlen(epilogue) + strlen(js) + 1; + char *eval = (char *)malloc(n); + snprintf(eval, n, "%s%s%s", prologue, js, epilogue); + wchar_t *buf = webview_to_utf16(eval); + if (buf == NULL) + { + return -1; + } + arg.bstrVal = SysAllocString(buf); + if (scriptDispatch->lpVtbl->Invoke( + scriptDispatch, dispid, iid_unref(&IID_NULL), 0, DISPATCH_METHOD, + ¶ms, &result, &excepInfo, &nArgErr) != S_OK) + { + return -1; + } + SysFreeString(arg.bstrVal); + free(eval); + scriptDispatch->lpVtbl->Release(scriptDispatch); + htmlDoc2->lpVtbl->Release(htmlDoc2); + docDispatch->lpVtbl->Release(docDispatch); + return 0; + } + + WEBVIEW_API void webview_dispatch(struct webview *w, webview_dispatch_fn fn, + void *arg) + { + PostMessageW(w->priv.hwnd, WM_WEBVIEW_DISPATCH, (WPARAM)fn, (LPARAM)arg); + } + + WEBVIEW_API void webview_set_title(struct webview *w, const char *title) + { +#ifdef UNICODE + wchar_t *u16title = webview_to_utf16(title); + if (u16title == NULL) + { + return; + } + SetWindowText(w->priv.hwnd, u16title); + GlobalFree(u16title); +#else + SetWindowText(w->priv.hwnd, title); +#endif + } + + WEBVIEW_API void webview_focus(struct webview *w) + { + SetFocus(w->priv.hwnd); + } + + WEBVIEW_API void webview_minsize(struct webview *w, int width, int height) { + w->priv.min_width = width; + w->priv.min_height = height; + } + + WEBVIEW_API void webview_maxsize(struct webview *w, int width, int height) { + w->priv.max_width = width; + w->priv.max_height = height; + } + + WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen) + { + if (w->priv.is_fullscreen == !!fullscreen) + { + return; + } + if (w->priv.is_fullscreen == 0) + { + w->priv.saved_style = GetWindowLong(w->priv.hwnd, GWL_STYLE); + w->priv.saved_ex_style = GetWindowLong(w->priv.hwnd, GWL_EXSTYLE); + GetWindowRect(w->priv.hwnd, &w->priv.saved_rect); + } + w->priv.is_fullscreen = !!fullscreen; + if (fullscreen) + { + MONITORINFO monitor_info; + SetWindowLong(w->priv.hwnd, GWL_STYLE, + w->priv.saved_style & ~(WS_CAPTION | WS_THICKFRAME)); + SetWindowLong(w->priv.hwnd, GWL_EXSTYLE, + w->priv.saved_ex_style & + ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE | + WS_EX_CLIENTEDGE | WS_EX_STATICEDGE)); + monitor_info.cbSize = sizeof(monitor_info); + GetMonitorInfo(MonitorFromWindow(w->priv.hwnd, MONITOR_DEFAULTTONEAREST), + &monitor_info); + RECT r; + r.left = monitor_info.rcMonitor.left; + r.top = monitor_info.rcMonitor.top; + r.right = monitor_info.rcMonitor.right; + r.bottom = monitor_info.rcMonitor.bottom; + SetWindowPos(w->priv.hwnd, NULL, r.left, r.top, r.right - r.left, + r.bottom - r.top, + SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED); + } + else + { + SetWindowLong(w->priv.hwnd, GWL_STYLE, w->priv.saved_style); + SetWindowLong(w->priv.hwnd, GWL_EXSTYLE, w->priv.saved_ex_style); + SetWindowPos(w->priv.hwnd, NULL, w->priv.saved_rect.left, + w->priv.saved_rect.top, + w->priv.saved_rect.right - w->priv.saved_rect.left, + w->priv.saved_rect.bottom - w->priv.saved_rect.top, + SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED); + } + } + + WEBVIEW_API void webview_set_color(struct webview *w, uint8_t r, uint8_t g, + uint8_t b, uint8_t a) + { + HBRUSH brush = CreateSolidBrush(RGB(r, g, b)); + SetClassLongPtr(w->priv.hwnd, GCLP_HBRBACKGROUND, (LONG_PTR)brush); + } + +/* These are missing parts from MinGW */ +#ifndef __IFileDialog_INTERFACE_DEFINED__ +#define __IFileDialog_INTERFACE_DEFINED__ + enum _FILEOPENDIALOGOPTIONS + { + FOS_OVERWRITEPROMPT = 0x2, + FOS_STRICTFILETYPES = 0x4, + FOS_NOCHANGEDIR = 0x8, + FOS_PICKFOLDERS = 0x20, + FOS_FORCEFILESYSTEM = 0x40, + FOS_ALLNONSTORAGEITEMS = 0x80, + FOS_NOVALIDATE = 0x100, + FOS_ALLOWMULTISELECT = 0x200, + FOS_PATHMUSTEXIST = 0x800, + FOS_FILEMUSTEXIST = 0x1000, + FOS_CREATEPROMPT = 0x2000, + FOS_SHAREAWARE = 0x4000, + FOS_NOREADONLYRETURN = 0x8000, + FOS_NOTESTFILECREATE = 0x10000, + FOS_HIDEMRUPLACES = 0x20000, + FOS_HIDEPINNEDPLACES = 0x40000, + FOS_NODEREFERENCELINKS = 0x100000, + FOS_DONTADDTORECENT = 0x2000000, + FOS_FORCESHOWHIDDEN = 0x10000000, + FOS_DEFAULTNOMINIMODE = 0x20000000, + FOS_FORCEPREVIEWPANEON = 0x40000000 + }; + typedef DWORD FILEOPENDIALOGOPTIONS; + typedef enum FDAP + { + FDAP_BOTTOM = 0, + FDAP_TOP = 1 + } FDAP; + DEFINE_GUID(IID_IFileDialog, 0x42f85136, 0xdb7e, 0x439c, 0x85, 0xf1, 0xe4, 0x07, + 0x5d, 0x13, 0x5f, 0xc8); + typedef struct IFileDialogVtbl + { + BEGIN_INTERFACE + HRESULT(STDMETHODCALLTYPE *QueryInterface) + (IFileDialog *This, REFIID riid, void **ppvObject); + ULONG(STDMETHODCALLTYPE *AddRef) + (IFileDialog *This); + ULONG(STDMETHODCALLTYPE *Release) + (IFileDialog *This); + HRESULT(STDMETHODCALLTYPE *Show) + (IFileDialog *This, HWND hwndOwner); + HRESULT(STDMETHODCALLTYPE *SetFileTypes) + (IFileDialog *This, UINT cFileTypes, const COMDLG_FILTERSPEC *rgFilterSpec); + HRESULT(STDMETHODCALLTYPE *SetFileTypeIndex) + (IFileDialog *This, UINT iFileType); + HRESULT(STDMETHODCALLTYPE *GetFileTypeIndex) + (IFileDialog *This, UINT *piFileType); + HRESULT(STDMETHODCALLTYPE *Advise) + (IFileDialog *This, IFileDialogEvents *pfde, DWORD *pdwCookie); + HRESULT(STDMETHODCALLTYPE *Unadvise) + (IFileDialog *This, DWORD dwCookie); + HRESULT(STDMETHODCALLTYPE *SetOptions) + (IFileDialog *This, FILEOPENDIALOGOPTIONS fos); + HRESULT(STDMETHODCALLTYPE *GetOptions) + (IFileDialog *This, FILEOPENDIALOGOPTIONS *pfos); + HRESULT(STDMETHODCALLTYPE *SetDefaultFolder) + (IFileDialog *This, IShellItem *psi); + HRESULT(STDMETHODCALLTYPE *SetFolder) + (IFileDialog *This, IShellItem *psi); + HRESULT(STDMETHODCALLTYPE *GetFolder) + (IFileDialog *This, IShellItem **ppsi); + HRESULT(STDMETHODCALLTYPE *GetCurrentSelection) + (IFileDialog *This, IShellItem **ppsi); + HRESULT(STDMETHODCALLTYPE *SetFileName) + (IFileDialog *This, LPCWSTR pszName); + HRESULT(STDMETHODCALLTYPE *GetFileName) + (IFileDialog *This, LPWSTR *pszName); + HRESULT(STDMETHODCALLTYPE *SetTitle) + (IFileDialog *This, LPCWSTR pszTitle); + HRESULT(STDMETHODCALLTYPE *SetOkButtonLabel) + (IFileDialog *This, LPCWSTR pszText); + HRESULT(STDMETHODCALLTYPE *SetFileNameLabel) + (IFileDialog *This, LPCWSTR pszLabel); + HRESULT(STDMETHODCALLTYPE *GetResult) + (IFileDialog *This, IShellItem **ppsi); + HRESULT(STDMETHODCALLTYPE *AddPlace) + (IFileDialog *This, IShellItem *psi, FDAP fdap); + HRESULT(STDMETHODCALLTYPE *SetDefaultExtension) + (IFileDialog *This, LPCWSTR pszDefaultExtension); + HRESULT(STDMETHODCALLTYPE *Close) + (IFileDialog *This, HRESULT hr); + HRESULT(STDMETHODCALLTYPE *SetClientGuid) + (IFileDialog *This, REFGUID guid); + HRESULT(STDMETHODCALLTYPE *ClearClientData) + (IFileDialog *This); + HRESULT(STDMETHODCALLTYPE *SetFilter) + (IFileDialog *This, IShellItemFilter *pFilter); + END_INTERFACE + } IFileDialogVtbl; + interface IFileDialog + { + CONST_VTBL IFileDialogVtbl *lpVtbl; + }; + DEFINE_GUID(IID_IFileOpenDialog, 0xd57c7288, 0xd4ad, 0x4768, 0xbe, 0x02, 0x9d, + 0x96, 0x95, 0x32, 0xd9, 0x60); + DEFINE_GUID(IID_IFileSaveDialog, 0x84bccd23, 0x5fde, 0x4cdb, 0xae, 0xa4, 0xaf, + 0x64, 0xb8, 0x3d, 0x78, 0xab); +#endif + + WEBVIEW_API void webview_dialog(struct webview *w, + enum webview_dialog_type dlgtype, int flags, + const char *title, const char *arg, + char *result, size_t resultsz, char *filter) + { + if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN || + dlgtype == WEBVIEW_DIALOG_TYPE_SAVE) + { + IFileDialog *dlg = NULL; + IShellItem *res = NULL; + WCHAR *ws = NULL; + char *s = NULL; + FILEOPENDIALOGOPTIONS opts, add_opts; + if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN) + { + if (CoCreateInstance( + iid_unref(&CLSID_FileOpenDialog), NULL, CLSCTX_INPROC_SERVER, + iid_unref(&IID_IFileOpenDialog), (void **)&dlg) != S_OK) + { + goto error_dlg; + } + if (flags & WEBVIEW_DIALOG_FLAG_DIRECTORY) + { + add_opts |= FOS_PICKFOLDERS; + } + add_opts |= FOS_NOCHANGEDIR | FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE | + FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_SHAREAWARE | + FOS_NOTESTFILECREATE | FOS_NODEREFERENCELINKS | + FOS_FORCESHOWHIDDEN | FOS_DEFAULTNOMINIMODE; + } + else + { + if (CoCreateInstance( + iid_unref(&CLSID_FileSaveDialog), NULL, CLSCTX_INPROC_SERVER, + iid_unref(&IID_IFileSaveDialog), (void **)&dlg) != S_OK) + { + goto error_dlg; + } + add_opts |= FOS_OVERWRITEPROMPT | FOS_NOCHANGEDIR | + FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE | FOS_SHAREAWARE | + FOS_NOTESTFILECREATE | FOS_NODEREFERENCELINKS | + FOS_FORCESHOWHIDDEN | FOS_DEFAULTNOMINIMODE; + } + if (filter[0] != '\0') + { + int count; + int i=0; + char* token; + char* filter_dup = strdup(filter); + for (count=1; filter[count]; filter[count]==',' ? count++ : *filter++); + COMDLG_FILTERSPEC rgSpec[count]; + char* filters[count]; + token = strtok(filter_dup, ","); + while(token != NULL) + { + filters[i] = token; + token = strtok(NULL, ","); + i++; + } + for (int i=0; i < count; i++) { + wchar_t *wFilter = (wchar_t *)malloc(4096); + MultiByteToWideChar(CP_ACP, 0, filters[i], -1, wFilter, 4096); + rgSpec[i].pszName = wFilter; + rgSpec[i].pszSpec = wFilter; + } + if (dlg->lpVtbl->SetFileTypes(dlg, count, rgSpec) != S_OK) { + goto error_dlg; + } + } + if (dlg->lpVtbl->GetOptions(dlg, &opts) != S_OK) + { + goto error_dlg; + } + opts &= ~FOS_NOREADONLYRETURN; + opts |= add_opts; + if (dlg->lpVtbl->SetOptions(dlg, opts) != S_OK) + { + goto error_dlg; + } + if (dlg->lpVtbl->Show(dlg, w->priv.hwnd) != S_OK) + { + goto error_dlg; + } + if (dlg->lpVtbl->GetResult(dlg, &res) != S_OK) + { + goto error_dlg; + } + if (res->lpVtbl->GetDisplayName(res, SIGDN_FILESYSPATH, &ws) != S_OK) + { + goto error_result; + } + s = webview_from_utf16(ws); + strncpy(result, s, resultsz); + result[resultsz - 1] = '\0'; + CoTaskMemFree(ws); + error_result: + res->lpVtbl->Release(res); + error_dlg: + dlg->lpVtbl->Release(dlg); + return; + } + else if (dlgtype == WEBVIEW_DIALOG_TYPE_ALERT) + { +#if 0 + /* MinGW often doesn't contain TaskDialog, we'll use MessageBox for now */ + WCHAR *wtitle = webview_to_utf16(title); + WCHAR *warg = webview_to_utf16(arg); + TaskDialog(w->priv.hwnd, NULL, NULL, wtitle, warg, 0, NULL, NULL); + GlobalFree(warg); + GlobalFree(wtitle); +#else + UINT type = MB_OK; + switch (flags & WEBVIEW_DIALOG_FLAG_ALERT_MASK) + { + case WEBVIEW_DIALOG_FLAG_INFO: + type |= MB_ICONINFORMATION; + break; + case WEBVIEW_DIALOG_FLAG_WARNING: + type |= MB_ICONWARNING; + break; + case WEBVIEW_DIALOG_FLAG_ERROR: + type |= MB_ICONERROR; + break; + } + MessageBox(w->priv.hwnd, arg, title, type); +#endif + } + } + + WEBVIEW_API void webview_terminate(struct webview *w) { PostQuitMessage(0); } + WEBVIEW_API void webview_exit(struct webview *w) { OleUninitialize(); } + WEBVIEW_API void webview_print_log(const char *s) { OutputDebugString(s); } + +#endif /* WEBVIEW_WINAPI */ + +#if defined(WEBVIEW_COCOA) +#if (!defined MAC_OS_X_VERSION_10_12) || \ + MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12 +#define NSAlertStyleWarning NSWarningAlertStyle +#define NSAlertStyleCritical NSCriticalAlertStyle +#define NSWindowStyleMaskResizable NSResizableWindowMask +#define NSWindowStyleMaskMiniaturizable NSMiniaturizableWindowMask +#define NSWindowStyleMaskTitled NSTitledWindowMask +#define NSWindowStyleMaskClosable NSClosableWindowMask +#define NSWindowStyleMaskFullScreen NSFullScreenWindowMask +#define NSEventMaskAny NSAnyEventMask +#define NSEventModifierFlagCommand NSCommandKeyMask +#define NSEventModifierFlagOption NSAlternateKeyMask +#define NSAlertStyleInformational NSInformationalAlertStyle +#endif /* MAC_OS_X_VERSION_10_12 */ +#if (!defined MAC_OS_X_VERSION_10_13) || \ + MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_13 +#define NSModalResponseOK NSFileHandlingPanelOKButton +#endif /* MAC_OS_X_VERSION_10_12, MAC_OS_X_VERSION_10_13 */ + static void webview_window_will_close(id self, SEL cmd, id notification) + { + struct webview *w = + (struct webview *)objc_getAssociatedObject(self, "webview"); + webview_terminate(w); + } + + static BOOL webview_is_selector_excluded_from_web_script(id self, SEL cmd, + SEL selector) + { + return selector != @selector(invoke:); + } + + static NSString *webview_webscript_name_for_selector(id self, SEL cmd, + SEL selector) + { + return selector == @selector(invoke:) ? @"invoke" : nil; + } + + static void webview_did_clear_window_object(id self, SEL cmd, id webview, + id script, id frame) + { + [script setValue:self forKey:@"external"]; + } + + static void webview_run_input_open_panel(id self, SEL cmd, id webview, + id listener, BOOL allowMultiple) + { + char filename[256] = ""; + struct webview *w = + (struct webview *)objc_getAssociatedObject(self, "webview"); + + webview_dialog(w, WEBVIEW_DIALOG_TYPE_OPEN, WEBVIEW_DIALOG_FLAG_FILE, "", "", + filename, 255, ""); + filename[255] = '\0'; + if (strlen(filename) > 0) + { + [listener chooseFilename:[NSString stringWithUTF8String:filename]]; + } + else + { + [listener cancel]; + } + } + + static void webview_external_invoke(id self, SEL cmd, id arg) + { + struct webview *w = + (struct webview *)objc_getAssociatedObject(self, "webview"); + if (w == NULL || w->external_invoke_cb == NULL) + { + return; + } + if ([arg isKindOfClass:[NSString class]] == NO) + { + return; + } + w->external_invoke_cb(w, [(NSString *)(arg) UTF8String]); + } + + WEBVIEW_API int webview_init(struct webview *w) + { + w->priv.pool = [[NSAutoreleasePool alloc] init]; + [NSApplication sharedApplication]; + + Class webViewDelegateClass = + objc_allocateClassPair([NSObject class], "WebViewDelegate", 0); + class_addMethod(webViewDelegateClass, sel_registerName("windowWillClose:"), + (IMP)webview_window_will_close, "v@:@"); + class_addMethod(object_getClass(webViewDelegateClass), + sel_registerName("isSelectorExcludedFromWebScript:"), + (IMP)webview_is_selector_excluded_from_web_script, "c@::"); + class_addMethod(object_getClass(webViewDelegateClass), + sel_registerName("webScriptNameForSelector:"), + (IMP)webview_webscript_name_for_selector, "c@::"); + class_addMethod(webViewDelegateClass, + sel_registerName("webView:didClearWindowObject:forFrame:"), + (IMP)webview_did_clear_window_object, "v@:@@@"); + class_addMethod( + webViewDelegateClass, + sel_registerName("webView:runOpenPanelForFileButtonWithResultListener:" + "allowMultipleFiles:"), + (IMP)webview_run_input_open_panel, "v@:@@c"); + class_addMethod(webViewDelegateClass, sel_registerName("invoke:"), + (IMP)webview_external_invoke, "v@:@"); + objc_registerClassPair(webViewDelegateClass); + + w->priv.delegate = [[webViewDelegateClass alloc] init]; + objc_setAssociatedObject(w->priv.delegate, "webview", (id)(w), + OBJC_ASSOCIATION_ASSIGN); + + // Disable damn smart quotes + // Credit: https://stackoverflow.com/a/31640511 + [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"NSAutomaticQuoteSubstitutionEnabled"]; + + NSRect r = NSMakeRect(0, 0, w->width, w->height); + NSUInteger style = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | + NSWindowStyleMaskMiniaturizable; + if (w->resizable) + { + style = style | NSWindowStyleMaskResizable; + // style = style | NSTexturedBackgroundWindowMask; + // style = style | NSUnifiedTitleAndToolbarWindowMask; + } + + // Transparent title bar + // if (w->transparentTitlebar) { + // style = style | NSFullSizeContentViewWindowMask | NSUnifiedTitleAndToolbarWindowMask | NSTexturedBackgroundWindowMask; + // } + + w->priv.window = [[NSWindow alloc] initWithContentRect:r + styleMask:style + backing:NSBackingStoreBuffered + defer:NO]; + [w->priv.window autorelease]; + + // Title + NSString *nsTitle = [NSString stringWithUTF8String:w->title]; + [w->priv.window setTitle:nsTitle]; + + [w->priv.window setDelegate:w->priv.delegate]; + [w->priv.window center]; + + // NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:@"wat"]; + // toolbar.showsBaselineSeparator = NO; + // [w->priv.window setToolbar:toolbar]; + + // if (w->transparentTitlebar) { + + // // Configure window look with hidden toolbar + // [w->priv.window setTitlebarAppearsTransparent:YES]; + // [w->priv.window setTitleVisibility:NSWindowTitleHidden]; + // // w->priv.window.isMovableByWindowBackground = true; + // } + + [[NSUserDefaults standardUserDefaults] setBool:!!w->debug + forKey:@"WebKitDeveloperExtras"]; + [[NSUserDefaults standardUserDefaults] synchronize]; + w->priv.webview = + [[WebView alloc] initWithFrame:r + frameName:@"WebView" + groupName:nil]; + NSURL *nsURL = [NSURL + URLWithString:[NSString stringWithUTF8String:webview_check_url(w->url)]]; + [[w->priv.webview mainFrame] loadRequest:[NSURLRequest requestWithURL:nsURL]]; + + [w->priv.webview setAutoresizesSubviews:YES]; + [w->priv.webview + setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + w->priv.webview.frameLoadDelegate = w->priv.delegate; + w->priv.webview.UIDelegate = w->priv.delegate; + [[w->priv.window contentView] addSubview:w->priv.webview]; + [w->priv.window orderFrontRegardless]; + + // Disable scrolling - make this configurable + // [[[w->priv.webview mainFrame] frameView] setAllowsScrolling:NO]; + + // ----> Enables WebGL but won't pass the app store guidelines + // + // WebPreferences *p = [w->priv.webview preferences]; + // if ([p respondsToSelector:@selector(setWebGLEnabled:)]) { + // [p setWebGLEnabled:YES]; + // } + + [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; + [NSApp finishLaunching]; + [NSApp activateIgnoringOtherApps:YES]; + + NSMenu *menubar = [[[NSMenu alloc] initWithTitle:@""] autorelease]; + + NSMenuItem *appMenuItem = + [[[NSMenuItem alloc] initWithTitle:@"wails app" action:NULL keyEquivalent:@""] + autorelease]; + NSMenu *appMenu = [[[NSMenu alloc] initWithTitle:@"wails app"] autorelease]; + [appMenuItem setSubmenu:appMenu]; + [menubar addItem:appMenuItem]; + + NSMenuItem *item = [[[NSMenuItem alloc] initWithTitle:@"Hide" + action:@selector(hide:) + keyEquivalent:@"h"] autorelease]; + [appMenu addItem:item]; + item = [[[NSMenuItem alloc] initWithTitle:@"Hide Others" + action:@selector(hideOtherApplications:) + keyEquivalent:@"h"] autorelease]; + [item setKeyEquivalentModifierMask:(NSEventModifierFlagOption | + NSEventModifierFlagCommand)]; + [appMenu addItem:item]; + item = [[[NSMenuItem alloc] initWithTitle:@"Show All" + action:@selector(unhideAllApplications:) + keyEquivalent:@""] autorelease]; + [appMenu addItem:item]; + [appMenu addItem:[NSMenuItem separatorItem]]; + + NSMenuItem *editMenuItem = + [[[NSMenuItem alloc] initWithTitle:@"Edit" action:NULL keyEquivalent:@""] + autorelease]; + NSMenu *editMenu = [[[NSMenu alloc] initWithTitle:@"Edit"] autorelease]; + [editMenuItem setSubmenu:editMenu]; + [menubar addItem:editMenuItem]; + + item = [[[NSMenuItem alloc] initWithTitle:@"Cut" + action:@selector(cut:) + keyEquivalent:@"x"] autorelease]; + [editMenu addItem:item]; + + item = [[[NSMenuItem alloc] initWithTitle:@"Copy" + action:@selector(copy:) + keyEquivalent:@"c"] autorelease]; + [editMenu addItem:item]; + + item = [[[NSMenuItem alloc] initWithTitle:@"Paste" + action:@selector(paste:) + keyEquivalent:@"v"] autorelease]; + [editMenu addItem:item]; + + item = [[[NSMenuItem alloc] initWithTitle:@"Select All" + action:@selector(selectAll:) + keyEquivalent:@"a"] autorelease]; + [editMenu addItem:item]; + + [appMenu addItem:[NSMenuItem separatorItem]]; + + item = [[[NSMenuItem alloc] initWithTitle:@"Quit" + action:@selector(terminate:) + keyEquivalent:@"q"] autorelease]; + [appMenu addItem:item]; + + [NSApp setMainMenu:menubar]; + + w->priv.should_exit = 0; + return 0; + } + + WEBVIEW_API int webview_loop(struct webview *w, int blocking) + { + NSDate *until = (blocking ? [NSDate distantFuture] : [NSDate distantPast]); + NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny + untilDate:until + inMode:NSDefaultRunLoopMode + dequeue:YES]; + if (event) + { + [NSApp sendEvent:event]; + } + return w->priv.should_exit; + } + + WEBVIEW_API int webview_eval(struct webview *w, const char *js) + { + NSString *nsJS = [NSString stringWithUTF8String:js]; + [[w->priv.webview windowScriptObject] evaluateWebScript:nsJS]; + return 0; + } + + WEBVIEW_API void webview_set_title(struct webview *w, const char *title) + { + NSString *nsTitle = [NSString stringWithUTF8String:title]; + [w->priv.window setTitle:nsTitle]; + } + + WEBVIEW_API void webview_focus(struct webview *w) + { + [w->priv.window makeKeyWindow]; + } + + WEBVIEW_API void webview_minsize(struct webview *w, int width, int height) { + NSSize size; + size.width = width; + size.height = height; + [w->priv.window setMinSize:size]; + } + + WEBVIEW_API void webview_maxsize(struct webview *w, int width, int height) { + NSSize size; + size.width = width; + size.height = height; + [w->priv.window setMaxSize:size]; + + NSButton *button = [w->priv.window standardWindowButton:NSWindowZoomButton]; + [button performSelectorOnMainThread:@selector(setEnabled:) withObject:NO + waitUntilDone:NO]; + } + + WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen) + { + int b = ((([w->priv.window styleMask] & NSWindowStyleMaskFullScreen) == + NSWindowStyleMaskFullScreen) + ? 1 + : 0); + if (b != fullscreen) + { + [w->priv.window toggleFullScreen:nil]; + } + } + + WEBVIEW_API void webview_set_color(struct webview *w, uint8_t r, uint8_t g, + uint8_t b, uint8_t a) + { + [w->priv.window setBackgroundColor:[NSColor colorWithRed:(CGFloat)r / 255.0 + green:(CGFloat)g / 255.0 + blue:(CGFloat)b / 255.0 + alpha:(CGFloat)a / 255.0]]; + if (0.5 >= ((r / 255.0 * 299.0) + (g / 255.0 * 587.0) + (b / 255.0 * 114.0)) / + 1000.0) + { + [w->priv.window + setAppearance:[NSAppearance + appearanceNamed:NSAppearanceNameVibrantDark]]; + } + else + { + [w->priv.window + setAppearance:[NSAppearance + appearanceNamed:NSAppearanceNameVibrantLight]]; + } + [w->priv.window setOpaque:NO]; + [w->priv.window setTitlebarAppearsTransparent:YES]; + [w->priv.webview setDrawsBackground:NO]; + } + + WEBVIEW_API void webview_dialog(struct webview *w, + enum webview_dialog_type dlgtype, int flags, + const char *title, const char *arg, + char *result, size_t resultsz, char *filter) + { + if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN || + dlgtype == WEBVIEW_DIALOG_TYPE_SAVE) + { + NSSavePanel *panel; + NSString *filter_str = [NSString stringWithUTF8String:filter]; + filter_str = [filter_str stringByReplacingOccurrencesOfString:@"*." + withString:@""]; + NSArray *fileTypes = [filter_str componentsSeparatedByString:@","]; + if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN) + { + NSOpenPanel *openPanel = [NSOpenPanel openPanel]; + if (flags & WEBVIEW_DIALOG_FLAG_DIRECTORY) + { + [openPanel setCanChooseFiles:NO]; + [openPanel setCanChooseDirectories:YES]; + } + else + { + [openPanel setCanChooseFiles:YES]; + [openPanel setCanChooseDirectories:NO]; + if(filter[0] != NULL) + { + [openPanel setAllowedFileTypes:fileTypes]; + } + } + [openPanel setResolvesAliases:NO]; + [openPanel setAllowsMultipleSelection:NO]; + panel = openPanel; + } + else + { + panel = [NSSavePanel savePanel]; + } + [panel setCanCreateDirectories:YES]; + [panel setShowsHiddenFiles:YES]; + [panel setExtensionHidden:NO]; + [panel setCanSelectHiddenExtension:NO]; + if(filter[0] != NULL) + { + [panel setAllowedFileTypes:fileTypes]; + } + [panel setTreatsFilePackagesAsDirectories:YES]; + [panel setNameFieldStringValue:@"Temp"]; // Necessary to prevent crash when replacing files + [panel setNameFieldStringValue:@"Untitled"]; + [panel beginSheetModalForWindow:w->priv.window + completionHandler:^(NSInteger result) { + [NSApp stopModalWithCode:result]; + }]; + if ([NSApp runModalForWindow:panel] == NSModalResponseOK) + { + const char *filename = [[[panel URL] path] UTF8String]; + strlcpy(result, filename, resultsz); + } + } + else if (dlgtype == WEBVIEW_DIALOG_TYPE_ALERT) + { + NSAlert *a = [NSAlert new]; + switch (flags & WEBVIEW_DIALOG_FLAG_ALERT_MASK) + { + case WEBVIEW_DIALOG_FLAG_INFO: + [a setAlertStyle:NSAlertStyleInformational]; + break; + case WEBVIEW_DIALOG_FLAG_WARNING: + NSLog(@"warning"); + [a setAlertStyle:NSAlertStyleWarning]; + break; + case WEBVIEW_DIALOG_FLAG_ERROR: + NSLog(@"error"); + [a setAlertStyle:NSAlertStyleCritical]; + break; + } + [a setShowsHelp:NO]; + [a setShowsSuppressionButton:NO]; + [a setMessageText:[NSString stringWithUTF8String:title]]; + [a setInformativeText:[NSString stringWithUTF8String:arg]]; + [a addButtonWithTitle:@"OK"]; + [a runModal]; + [a release]; + } + } + + static void webview_dispatch_cb(void *arg) + { + struct webview_dispatch_arg *context = (struct webview_dispatch_arg *)arg; + (context->fn)(context->w, context->arg); + free(context); + } + + WEBVIEW_API void webview_dispatch(struct webview *w, webview_dispatch_fn fn, + void *arg) + { + struct webview_dispatch_arg *context = (struct webview_dispatch_arg *)malloc( + sizeof(struct webview_dispatch_arg)); + context->w = w; + context->arg = arg; + context->fn = fn; + dispatch_async_f(dispatch_get_main_queue(), context, webview_dispatch_cb); + } + + WEBVIEW_API void webview_terminate(struct webview *w) + { + w->priv.should_exit = 1; + } + WEBVIEW_API void webview_exit(struct webview *w) { [NSApp terminate:NSApp]; } + WEBVIEW_API void webview_print_log(const char *s) { NSLog(@"%s", s); } + +#endif /* WEBVIEW_COCOA */ + +#endif /* WEBVIEW_IMPLEMENTATION */ + +#ifdef __cplusplus +} +#endif + +#endif /* WEBVIEW_H */ diff --git a/licenses/github.com/dchest/cssmin/LICENSE b/licenses/github.com/dchest/cssmin/LICENSE new file mode 100644 index 000000000..c9b4ec5dd --- /dev/null +++ b/licenses/github.com/dchest/cssmin/LICENSE @@ -0,0 +1,29 @@ +Go Port: +Copyright (c) 2013 Dmitry Chestnykh + +Original: +Copyright (c) 2008 Ryan Grove +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of this project nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/licenses/github.com/dchest/htmlmin/LICENSE b/licenses/github.com/dchest/htmlmin/LICENSE new file mode 100644 index 000000000..9ddea1fd3 --- /dev/null +++ b/licenses/github.com/dchest/htmlmin/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2013 Dmitry Chestnykh. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/licenses/github.com/fatih/color/LICENSE.md b/licenses/github.com/fatih/color/LICENSE.md new file mode 100644 index 000000000..25fdaf639 --- /dev/null +++ b/licenses/github.com/fatih/color/LICENSE.md @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013 Fatih Arslan + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/licenses/github.com/go-playground/colors/LICENSE b/licenses/github.com/go-playground/colors/LICENSE new file mode 100644 index 000000000..6a2ae9aa4 --- /dev/null +++ b/licenses/github.com/go-playground/colors/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Dean Karn + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/licenses/github.com/gorilla/websocket/LICENSE b/licenses/github.com/gorilla/websocket/LICENSE new file mode 100644 index 000000000..9171c9722 --- /dev/null +++ b/licenses/github.com/gorilla/websocket/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2013 The Gorilla WebSocket Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/licenses/github.com/jackmordaunt/icns/LICENSE b/licenses/github.com/jackmordaunt/icns/LICENSE new file mode 100644 index 000000000..787939ec2 --- /dev/null +++ b/licenses/github.com/jackmordaunt/icns/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Jack Mordaunt + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/licenses/github.com/konsorten/go-windows-terminal-sequences/LICENSE b/licenses/github.com/konsorten/go-windows-terminal-sequences/LICENSE new file mode 100644 index 000000000..14127cd83 --- /dev/null +++ b/licenses/github.com/konsorten/go-windows-terminal-sequences/LICENSE @@ -0,0 +1,9 @@ +(The MIT License) + +Copyright (c) 2017 marvin + konsorten GmbH (open-source@konsorten.de) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/licenses/github.com/leaanthony/mewn/LICENSE b/licenses/github.com/leaanthony/mewn/LICENSE new file mode 100644 index 000000000..1cf398a90 --- /dev/null +++ b/licenses/github.com/leaanthony/mewn/LICENSE @@ -0,0 +1,7 @@ +© 2019-Present Lea Anthony + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/licenses/github.com/leaanthony/slicer/LICENSE b/licenses/github.com/leaanthony/slicer/LICENSE new file mode 100644 index 000000000..558a6a271 --- /dev/null +++ b/licenses/github.com/leaanthony/slicer/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Lea Anthony + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/licenses/github.com/leaanthony/spinner/LICENSE b/licenses/github.com/leaanthony/spinner/LICENSE new file mode 100644 index 000000000..7e01c45c9 --- /dev/null +++ b/licenses/github.com/leaanthony/spinner/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2018 Lea Anthony + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/licenses/github.com/leaanthony/synx/LICENSE b/licenses/github.com/leaanthony/synx/LICENSE new file mode 100644 index 000000000..75ba4230d --- /dev/null +++ b/licenses/github.com/leaanthony/synx/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2018-Present Lea Anthony + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/licenses/github.com/leaanthony/wincursor/LICENSE b/licenses/github.com/leaanthony/wincursor/LICENSE new file mode 100644 index 000000000..75ba4230d --- /dev/null +++ b/licenses/github.com/leaanthony/wincursor/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2018-Present Lea Anthony + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/licenses/github.com/mattn/go-colorable/LICENSE b/licenses/github.com/mattn/go-colorable/LICENSE new file mode 100644 index 000000000..91b5cef30 --- /dev/null +++ b/licenses/github.com/mattn/go-colorable/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Yasuhiro Matsumoto + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/licenses/github.com/mattn/go-isatty/LICENSE b/licenses/github.com/mattn/go-isatty/LICENSE new file mode 100644 index 000000000..65dc692b6 --- /dev/null +++ b/licenses/github.com/mattn/go-isatty/LICENSE @@ -0,0 +1,9 @@ +Copyright (c) Yasuhiro MATSUMOTO + +MIT License (Expat) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/licenses/github.com/mitchellh/go-homedir/LICENSE b/licenses/github.com/mitchellh/go-homedir/LICENSE new file mode 100644 index 000000000..f9c841a51 --- /dev/null +++ b/licenses/github.com/mitchellh/go-homedir/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013 Mitchell Hashimoto + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/licenses/github.com/nfnt/resize/LICENSE b/licenses/github.com/nfnt/resize/LICENSE new file mode 100644 index 000000000..7836cad5f --- /dev/null +++ b/licenses/github.com/nfnt/resize/LICENSE @@ -0,0 +1,13 @@ +Copyright (c) 2012, Jan Schlicht + +Permission to use, copy, modify, and/or distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright notice +and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. diff --git a/licenses/github.com/pkg/errors/LICENSE b/licenses/github.com/pkg/errors/LICENSE new file mode 100644 index 000000000..835ba3e75 --- /dev/null +++ b/licenses/github.com/pkg/errors/LICENSE @@ -0,0 +1,23 @@ +Copyright (c) 2015, Dave Cheney +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/licenses/github.com/sirupsen/logrus/LICENSE b/licenses/github.com/sirupsen/logrus/LICENSE new file mode 100644 index 000000000..f090cb42f --- /dev/null +++ b/licenses/github.com/sirupsen/logrus/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Simon Eskildsen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/licenses/github.com/wailsapp/webview/LICENSE b/licenses/github.com/wailsapp/webview/LICENSE new file mode 100644 index 000000000..b18604bf4 --- /dev/null +++ b/licenses/github.com/wailsapp/webview/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Serge Zaitsev + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/licenses/golang.org/x/crypto/LICENSE b/licenses/golang.org/x/crypto/LICENSE new file mode 100644 index 000000000..6a66aea5e --- /dev/null +++ b/licenses/golang.org/x/crypto/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/licenses/golang.org/x/net/LICENSE b/licenses/golang.org/x/net/LICENSE new file mode 100644 index 000000000..6a66aea5e --- /dev/null +++ b/licenses/golang.org/x/net/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/licenses/golang.org/x/sys/LICENSE b/licenses/golang.org/x/sys/LICENSE new file mode 100644 index 000000000..6a66aea5e --- /dev/null +++ b/licenses/golang.org/x/sys/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/logo.png b/logo.png new file mode 100644 index 000000000..8cfad9043 Binary files /dev/null and b/logo.png differ diff --git a/assets/images/logo_cropped.png b/logo_cropped.png similarity index 100% rename from assets/images/logo_cropped.png rename to logo_cropped.png diff --git a/pace.jpeg b/pace.jpeg new file mode 100644 index 000000000..897885637 Binary files /dev/null and b/pace.jpeg differ diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..48e341a09 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,3 @@ +{ + "lockfileVersion": 1 +} diff --git a/runtime/assets.go b/runtime/assets.go new file mode 100644 index 000000000..96aaad29b --- /dev/null +++ b/runtime/assets.go @@ -0,0 +1,15 @@ +package runtime + +import _ "embed" + +//go:embed assets/bridge.js +var BridgeJS []byte + +//go:embed assets/wails.js +var WailsJS string + +//go:embed assets/wails.css +var WailsCSS string + +//go:embed js/runtime/init.js +var InitJS []byte diff --git a/runtime/assets/bridge.js b/runtime/assets/bridge.js new file mode 100644 index 000000000..5c2f73ee3 --- /dev/null +++ b/runtime/assets/bridge.js @@ -0,0 +1,210 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The lightweight framework for web-like apps +(c) Lea Anthony 2019-present +*/ +/* jshint esversion: 6 */ + +function init() { + // Bridge object + window.wailsbridge = { + reconnectOverlay: null, + reconnectTimer: 300, + wsURL: 'ws://' + window.location.hostname + ':34115/bridge', + connectionState: null, + config: {}, + websocket: null, + callback: null, + overlayHTML: + '
Wails Bridge


Waiting for backend
', + overlayCSS: + '.wails-reconnect-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,.6);font-family:sans-serif;display:none;z-index:999999}.wails-reconnect-overlay-content{padding:20px 30px;text-align:center;width:20em;position:relative;height:14em;border-radius:1em;margin:5% auto 0;background-color:#fff;box-shadow:1px 1px 20px 3px;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC8AAAAuCAMAAACPpbA7AAAAqFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQAAAAAAAAEBAQAAAAAAAAAAAAEBAQEBAQDAwMBAQEAAAABAQEAAAAAAAAAAAABAQEAAAAAAAACAgICAgIBAQEAAAAAAAAAAAAAAAAAAAAAAAABAQEAAAACAgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBQWKCj6oAAAAN3RSTlMALiIqDhkGBAswJjP0GxP6NR4W9/ztjRDMhWU50G9g5eHXvbZ9XEI9xZTcqZl2aldKo55QwoCvZUgzhAAAAs9JREFUSMeNleeWqjAUhU0BCaH3Itiw9zKT93+zG02QK1hm/5HF+jzZJ6fQe6cyXE+jg9X7o9wxuylIIf4Tv2V3+bOrEXnf8dwQ/KQIGDN2/S+4OmVCVXL/ScBnfibxURqIByP/hONE8r8T+bDMlQ98KSl7Y8hzjpS8v1qtDh8u5f8KQpGpfnPPhqG8JeogN37Hq9eaN2xRhIwAaGnvws8F1ShxqK5ob2twYi1FAMD4rXsYtnC/JEiRbl4cUrCWhnMCLRFemXezXbb59QK4WASOsm6n2W1+4CBT2JmtzQ6fsrbGubR/NFbd2g5Y179+5w/GEHaKsHjYCet7CgrXU3txarNC7YxOVJtIj4/ERzMdZfzc31hp+8cD6eGILgarZY9uZ12hAs03vfBD9C171gS5Omz7OcvxALQIn4u8RRBBBcsi9WW2woO9ipLgfzpYlggg3ZRdROUC8KT7QLqq3W9KB5BbdFVg4929kdwp6+qaZnMCCNBdj+NyN1W885Ry/AL3D4AQbsVV4noCiM/C83kyYq80XlDAYQtralOiDzoRAHlotWl8q2tjvYlOgcg1A8jEApZa+C06TBdAz2Qv0wu11I/zZOyJQ6EwGez2P2b8PIQr1hwwnAZsAxwA4UAYOyXUxM/xp6tHAn4GUmPGM9R28oVxgC0e/zQJJI6DyhyZ1r7uzRQhpcW7x7vTaWSzKSG6aep77kroTEl3U81uSVaUTtgEINfC8epx+Q4F9SpplHG84Ek6m4RAq9/TLkOBrxyeuddZhHvGIp1XXfFy3Z3vtwNblKGiDn+J+92vwwABHghj7HnzlS1H5kB49AZvdGCFgiBPq69qfXPr3y++yilF0ON4R8eR7spAsLpZ95NqAW5tab1c4vkZm6aleajchMwYTdILQQTwE2OV411ZM9WztDjPql12caBi6gDpUKmDd4U1XNdQxZ4LIXQ5/Tr4P7I9tYcFrDK3AAAAAElFTkSuQmCC);background-repeat:no-repeat;background-position:center}.wails-reconnect-overlay-title{font-size:2em}.wails-reconnect-overlay-message{font-size:1.3em}.wails-reconnect-overlay-loadingspinner{pointer-events:none;width:2.5em;height:2.5em;border:.4em solid transparent;border-color:#3E67EC #eee #eee;border-radius:50%;animation:loadingspin 1s linear infinite;margin:auto;padding:2.5em}@keyframes loadingspin{100%{transform:rotate(360deg)}}', + log: function (message) { + // eslint-disable-next-line + console.log( + '%c wails bridge %c ' + message + ' ', + 'background: #aa0000; color: #fff; border-radius: 3px 0px 0px 3px; padding: 1px; font-size: 0.7rem', + 'background: #009900; color: #fff; border-radius: 0px 3px 3px 0px; padding: 1px; font-size: 0.7rem' + ); + } + }; +} + +// Adapted from webview - thanks zserge! +function injectCSS(css) { + var elem = document.createElement('style'); + elem.setAttribute('type', 'text/css'); + if (elem.styleSheet) { + elem.styleSheet.cssText = css; + } else { + elem.appendChild(document.createTextNode(css)); + } + var head = document.head || document.getElementsByTagName('head')[0]; + head.appendChild(elem); +} + +// Creates a node in the Dom +function createNode(parent, elementType, id, className, content) { + var d = document.createElement(elementType); + if (id) { + d.id = id; + } + if (className) { + d.className = className; + } + if (content) { + d.innerHTML = content; + } + parent.appendChild(d); + return d; +} + +// Sets up the overlay +function setupOverlay() { + var body = document.body; + var wailsBridgeNode = createNode(body, 'div', 'wails-bridge'); + wailsBridgeNode.innerHTML = window.wailsbridge.overlayHTML; + + // Inject the overlay CSS + injectCSS(window.wailsbridge.overlayCSS); +} + +// Start the Wails Bridge +function startBridge() { + // Setup the overlay + setupOverlay(); + + window.wailsbridge.websocket = null; + window.wailsbridge.connectTimer = null; + window.wailsbridge.reconnectOverlay = document.querySelector( + '.wails-reconnect-overlay' + ); + window.wailsbridge.connectionState = 'disconnected'; + + // Shows the overlay + function showReconnectOverlay() { + window.wailsbridge.reconnectOverlay.style.display = 'block'; + } + + // Hides the overlay + function hideReconnectOverlay() { + window.wailsbridge.reconnectOverlay.style.display = 'none'; + } + + // Adds a script to the Dom. + // Removes it if second parameter is true. + function addScript(script, remove) { + var s = document.createElement('script'); + s.setAttribute('type', 'text/javascript'); + s.textContent = script; + document.head.appendChild(s); + + // Remove internal messages from the DOM + if (remove) { + s.parentNode.removeChild(s); + } + } + + // Handles incoming websocket connections + function handleConnect() { + window.wailsbridge.log('Connected to backend'); + hideReconnectOverlay(); + clearInterval(window.wailsbridge.connectTimer); + window.wailsbridge.websocket.onclose = handleDisconnect; + window.wailsbridge.websocket.onmessage = handleMessage; + window.wailsbridge.connectionState = 'connected'; + } + + // Handles websocket disconnects + function handleDisconnect() { + window.wailsbridge.log('Disconnected from backend'); + window.wailsbridge.websocket = null; + window.wailsbridge.connectionState = 'disconnected'; + showReconnectOverlay(); + connect(); + } + + // Try to connect to the backend every 300ms (default value). + // Change this value in the main wailsbridge object. + function connect() { + window.wailsbridge.connectTimer = setInterval(function () { + if (window.wailsbridge.websocket == null) { + window.wailsbridge.websocket = new WebSocket(window.wailsbridge.wsURL); + window.wailsbridge.websocket.onopen = handleConnect; + window.wailsbridge.websocket.onerror = function (e) { + e.stopImmediatePropagation(); + e.stopPropagation(); + e.preventDefault(); + window.wailsbridge.websocket = null; + return false; + }; + } + }, window.wailsbridge.reconnectTimer); + } + + function handleMessage(message) { + // As a bridge we ignore js and css injections + switch (message.data[0]) { + // Wails library - inject! + case 'w': + addScript(message.data.slice(1)); + + // Now wails runtime is loaded, wails for the ready event + // and callback to the main app + window.wails.Events.On('wails:loaded', function () { + window.wailsbridge.log('Wails Ready'); + if (window.wailsbridge.callback) { + window.wailsbridge.log('Notifying application'); + window.wailsbridge.callback(window.wails); + } + }); + window.wailsbridge.log('Loaded Wails Runtime'); + break; + // Notifications + case 'n': + addScript(message.data.slice(1), true); + break; + // Binding + case 'b': + var binding = message.data.slice(1); + //log("Binding: " + binding) + window.wails._.NewBinding(binding); + break; + // Call back + case 'c': + var callbackData = message.data.slice(1); + window.wails._.Callback(callbackData); + break; + default: + window.wails.Log.Error('Unknown message type received: ' + message.data[0]); + } + } + + // Start by showing the overlay... + showReconnectOverlay(); + + // ...and attempt to connect + connect(); +} + +function start(callback) { + + // Set up the bridge + init(); + + // Save the callback + window.wailsbridge.callback = callback; + + // Start Bridge + startBridge(); +} + +function Init(callback) { + start(callback); +} + +module.exports = Init; diff --git a/runtime/assets/console.js b/runtime/assets/console.js new file mode 100644 index 000000000..e64867d25 --- /dev/null +++ b/runtime/assets/console.js @@ -0,0 +1,175 @@ +(function () { + + window.wailsconsole = {}; + + var debugconsole = document.createElement("div"); + var header = document.createElement("div"); + var consoleOut = document.createElement("div"); + + + document.addEventListener('keyup', logKey); + + debugconsole.id = "wailsdebug"; + debugconsole.style.fontSize = "18px"; + debugconsole.style.width = "100%"; + debugconsole.style.height = "35%"; + debugconsole.style.maxHeight = "35%"; + debugconsole.style.position = "fixed"; + debugconsole.style.left = "0px"; + debugconsole.style.backgroundColor = "rgba(255,255,255,0.8)"; + debugconsole.style.borderTop = '1px solid black'; + debugconsole.style.color = "black"; + debugconsole.style.display = "none"; + + header.style.width = "100%"; + header.style.height = "30px"; + header.style.display = "block"; + // header.style.paddingTop = "3px"; + header.style.verticalAlign = "middle"; + header.style.paddingLeft = "10px"; + header.style.background = "rgba(255,255,255,0.8)"; + header.innerHTML = " Wails Console > Clear"; + + consoleOut.style.position = "absolute"; + consoleOut.style.width = "100%"; + consoleOut.style.height = "auto"; + consoleOut.style.top = "30px"; + // consoleOut.style.paddingLeft = "10px"; + consoleOut.style.bottom = "0px"; + consoleOut.style.backgroundColor = "rgba(200,200,200,1)"; + consoleOut.style.overflowY = "scroll"; + consoleOut.style.msOverflowStyle = "-ms-autohiding-scrollbar"; + + debugconsole.appendChild(header); + debugconsole.appendChild(consoleOut); + document.body.appendChild(debugconsole); + console.log(debugconsole.style.display) + + function logKey(e) { + var conin = document.getElementById('conin'); + if (e.which == 27 && e.shiftKey) { + toggleConsole(conin); + } + if (e.which == 13 && consoleVisible()) { + var command = conin.value.trim(); + if (command.length > 0) { + console.log("> " + command) + try { + evaluateInput(command); + } catch (e) { + console.error(e.message); + } + conin.value = ""; + } + } + }; + + + function consoleVisible() { + return debugconsole.style.display == "block"; + } + + function toggleConsole(conin) { + var display = "none" + if (debugconsole.style.display == "none") display = "block"; + debugconsole.style.display = display; + if (display == "block") { + conin.focus(); + } + } + + function evaluateExpression(expression) { + + var pathSegments = [].concat(expression.split('.')); + if (pathSegments[0] == 'window') { + pathSegments.shift() + } + var currentObject = window; + for (var i = 0; i < pathSegments.length; i++) { + var pathSegment = pathSegments[i]; + if (currentObject[pathSegment] == undefined) { + return false; + } + currentObject = currentObject[pathSegment]; + } + console.log(JSON.stringify(currentObject)); + + return true; + } + + function evaluateInput(command) { + try { + if (evaluateExpression(command)) { + return + } else { + eval(command); + } + } catch (e) { + console.error(e.message) + } + } + + + // Set us up as a listener + function hookIntoIPC() { + if (window.wails && window.wails._ && window.wails._.AddIPCListener) { + window.wails._.AddIPCListener(processIPCMessage); + } else { + setTimeout(hookIntoIPC, 100); + } + } + hookIntoIPC(); + + function processIPCMessage(message) { + console.log(message); + var parsedMessage; + try { + parsedMessage = JSON.parse(message); + } catch (e) { + console.error("Error in parsing IPC message: " + e.message); + return false; + } + var logmessage = "[IPC] " + switch (parsedMessage.type) { + case 'call': + logmessage += " Call: " + parsedMessage.payload.bindingName; + var params = ""; + var parsedParams = JSON.parse(parsedMessage.payload.data); + if (parsedParams.length > 0) { + params = parsedParams; + } + logmessage += "(" + params + ")"; + break; + case 'log': + logmessage += "Log (" + parsedMessage.payload.level + "): " + parsedMessage.payload.message; + break; + default: + logmessage = message; + } + console.log(logmessage); + } + + window.wailsconsole.clearConsole = function () { + consoleOut.innerHTML = ""; + } + + console.log = function (message) { + consoleOut.innerHTML = consoleOut.innerHTML + "" + message + '
'; + consoleOut.scrollTop = consoleOut.scrollHeight; + + }; + console.error = function (message) { + consoleOut.innerHTML = consoleOut.innerHTML + " Error: " + message + '
'; + consoleOut.scrollTop = consoleOut.scrollHeight; + }; + // var h = document.getElementsByTagName("html")[0]; + // console.log("html margin: " + h.style.marginLeft); + // console.log("html padding: " + h.style.paddingLeft); + + // setInterval(function() { console.log("test");}, 1000); + // setInterval(function() { console.error("oops");}, 3000); + // var script = document.createElement('script'); + // script.src = "https://cdnjs.cloudflare.com/ajax/libs/firebug-lite/1.4.0/firebug-lite.js#startOpened=true"; + // document.body.appendChild(script); + +})(); \ No newline at end of file diff --git a/runtime/assets/wails.css b/runtime/assets/wails.css new file mode 100644 index 000000000..b807abe69 --- /dev/null +++ b/runtime/assets/wails.css @@ -0,0 +1,39 @@ +/* + Some css from https://gist.github.com/abelaska/9c9eda70d31315f27a564be2ee490cf4 + Many thanks! +*/ + +/* https://fonts.google.com/specimen/Roboto?selection.family=Roboto:300,400,500,700 https://www.fontsquirrel.com/tools/webfont-generator */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 300; + src:url(data:application/font-woff;charset=utf-8;base64,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) format('woff'); +} +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + src: url(data:application/font-woff;charset=utf-8;base64,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) format('woff'); +} +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 500; + src: url(data:application/font-woff;charset=utf-8;base64,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) format('woff'); +} +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 700; + src: url(data:application/font-woff;charset=utf-8;base64,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) format('woff'); +} + +html { + font-family: 'Roboto' +} + +.wails-logo { + background-image: url(data:image/png;base64,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); + background-size: cover; +} \ No newline at end of file diff --git a/runtime/assets/wails.js b/runtime/assets/wails.js new file mode 100644 index 000000000..0971f49ea --- /dev/null +++ b/runtime/assets/wails.js @@ -0,0 +1 @@ +!function(n){var e={};function t(r){if(e[r])return e[r].exports;var o=e[r]={i:r,l:!1,exports:{}};return n[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,r){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:r})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var r=Object.create(null);if(t.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(r,o,function(e){return n[e]}.bind(null,o));return r},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){"use strict";t.r(e),t.d(e,"Init",(function(){return L}));var r={};t.r(r),t.d(r,"Debug",(function(){return l})),t.d(r,"Info",(function(){return s})),t.d(r,"Warning",(function(){return d})),t.d(r,"Error",(function(){return f})),t.d(r,"Fatal",(function(){return w}));var o={};t.r(o),t.d(o,"OpenURL",(function(){return h})),t.d(o,"OpenFile",(function(){return y}));var i={};t.r(i),t.d(i,"New",(function(){return N}));var a=[];function c(n,e,t){var r={type:n,callbackID:t,payload:e};!function(n){if(window.wailsbridge?window.wailsbridge.websocket.send(n):window.external.invoke(n),a.length>0)for(var e=0;e0)var a=setTimeout((function(){o(Error("Call to "+n+" timed out. Request ID: "+i))}),t);v[i]={timeoutHandle:a,reject:o,resolve:r};try{c("call",{bindingName:n,data:JSON.stringify(e)},i)}catch(n){console.error(n)}}))}function b(n,e){return g(".wails."+n,e)}function h(n){return b("Browser.OpenURL",n)}function y(n){return b("Browser.OpenFile",n)}p=window.crypto?function(){var n=new Uint32Array(1);return window.crypto.getRandomValues(n)[0]}:function(){return 9007199254740991*Math.random()};var m=function n(e,t){!function(n,e){if(!(n instanceof e))throw new TypeError("Cannot call a class as a function")}(this,n),t=t||-1,this.Callback=function(n){return e.apply(null,n),-1!==t&&0===(t-=1)}},E={};function O(n,e,t){E[n]=E[n]||[];var r=new m(e,t);E[n].push(r)}function S(n){var e=JSON.stringify([].slice.apply(arguments).slice(1)),t={name:n,data:e};c("event",t)}var j={};function k(n){try{return new Function("var "+n),!0}catch(n){return!1}}function N(n,e){var t,r=this;if(!window.wails)throw Error("Wails is not initialised");var o=[];return this.subscribe=function(n){o.push(n)},this.set=function(e){t=e,window.wails.Events.Emit("wails:sync:store:updatedbyfrontend:"+n,JSON.stringify(t)),o.forEach((function(n){n(t)}))},this.update=function(n){var e=n(t);r.set(e)},window.wails.Events.On("wails:sync:store:updatedbybackend:"+n,(function(n){n=JSON.parse(n),t=n,o.forEach((function(n){n(t)}))})),e&&this.set(e),this}function C(){return(C=Object.assign||function(n){for(var e=1;e1)for(var r=0;r 0 { + title = params[0] + } + if len(params) > 1 { + filter = strings.Replace(params[1], " ", "", -1) + } + return r.renderer.SelectFile(title, filter) +} + +// SelectDirectory prompts the user to select a directory +func (r *Dialog) SelectDirectory() string { + return r.renderer.SelectDirectory() +} + +// SelectSaveFile prompts the user to select a file for saving +func (r *Dialog) SelectSaveFile(params ...string) string { + title := "Select Save" + filter := "" + if len(params) > 0 { + title = params[0] + } + if len(params) > 1 { + filter = strings.Replace(params[1], " ", "", -1) + } + return r.renderer.SelectSaveFile(title, filter) +} diff --git a/runtime/events.go b/runtime/events.go new file mode 100644 index 000000000..ffbeaa5a7 --- /dev/null +++ b/runtime/events.go @@ -0,0 +1,35 @@ +package runtime + +import "github.com/wailsapp/wails/lib/interfaces" + +// Events exposes the events interface +type Events struct { + eventManager interfaces.EventManager +} + +// NewEvents creates a new Events struct +func NewEvents(eventManager interfaces.EventManager) *Events { + return &Events{ + eventManager: eventManager, + } +} + +// On pass through +func (r *Events) On(eventName string, callback func(optionalData ...interface{})) { + r.eventManager.On(eventName, callback) +} + +// Once pass through +func (r *Events) Once(eventName string, callback func(optionalData ...interface{})) { + r.eventManager.Once(eventName, callback) +} + +// OnMultiple pass through +func (r *Events) OnMultiple(eventName string, callback func(optionalData ...interface{}), counter uint) { + r.eventManager.OnMultiple(eventName, callback, counter) +} + +// Emit pass through +func (r *Events) Emit(eventName string, optionalData ...interface{}) { + r.eventManager.Emit(eventName, optionalData...) +} diff --git a/runtime/filesystem.go b/runtime/filesystem.go new file mode 100644 index 000000000..ebb4feda0 --- /dev/null +++ b/runtime/filesystem.go @@ -0,0 +1,16 @@ +package runtime + +import "os" + +// FileSystem exposes file system utilities to the runtime +type FileSystem struct{} + +// NewFileSystem creates a new FileSystem struct +func NewFileSystem() *FileSystem { + return &FileSystem{} +} + +// HomeDir returns the user's home directory +func (r *FileSystem) HomeDir() (string, error) { + return os.UserHomeDir() +} diff --git a/runtime/js/.eslintrc b/runtime/js/.eslintrc new file mode 100644 index 000000000..426ccc63d --- /dev/null +++ b/runtime/js/.eslintrc @@ -0,0 +1,28 @@ +{ + "env": { + "browser": true, + "es6": true, + "amd": true, + "node": true + }, + "extends": "eslint:recommended", + "parserOptions": { + "ecmaVersion": 2016, + "sourceType": "module" + }, + "rules": { + "indent": [ + "error", + "tab" + ], + "linebreak-style": 0, + "quotes": [ + "error", + "single" + ], + "semi": [ + "error", + "always" + ] + } +} diff --git a/runtime/js/babel.config.js b/runtime/js/babel.config.js new file mode 100644 index 000000000..39d867cc4 --- /dev/null +++ b/runtime/js/babel.config.js @@ -0,0 +1,22 @@ +/* eslint-disable */ + +module.exports = function (api) { + api.cache(true); + + const presets = [ + [ + "@babel/preset-env", + { + "useBuiltIns": "entry", + "corejs": { + "version": 3, + "proposals": true + } + } + ] + ]; + + return { + presets, + }; +} \ No newline at end of file diff --git a/runtime/js/core/bindings.js b/runtime/js/core/bindings.js new file mode 100644 index 000000000..32df6161f --- /dev/null +++ b/runtime/js/core/bindings.js @@ -0,0 +1,94 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The lightweight framework for web-like apps +(c) Lea Anthony 2019-present +*/ +/* jshint esversion: 6 */ + +import { Call } from './calls'; + +window.backend = {}; + +/** + * Determines if the given identifier is valid Javascript + * + * @param {boolean} name + * @returns + */ +function isValidIdentifier(name) { + // Don't xss yourself :-) + try { + new Function('var ' + name); + return true; + } catch (e) { + return false; + } +} + +/** + * NewBinding creates a new binding from the given binding name + * + * @export + * @param {string} bindingName + * @returns + */ +// eslint-disable-next-line max-lines-per-function +export function NewBinding(bindingName) { + + // Get all the sections of the binding + var bindingSections = [].concat(bindingName.split('.').splice(1)); + var pathToBinding = window.backend; + + // Check if we have a path (IE Struct) + if (bindingSections.length > 1) { + // Iterate over binding sections, adding them to the window.backend object + for (let index = 0; index < bindingSections.length-1; index += 1) { + const name = bindingSections[index]; + // Is name a valid javascript identifier? + if (!isValidIdentifier(name)) { + return new Error(`${name} is not a valid javascript identifier.`); + } + if (!pathToBinding[name]) { + pathToBinding[name] = {}; + } + pathToBinding = pathToBinding[name]; + } + } + + // Get the actual function/method call name + const name = bindingSections.pop(); + + // Is name a valid javascript identifier? + if (!isValidIdentifier(name)) { + return new Error(`${name} is not a valid javascript identifier.`); + } + + // Add binding call + pathToBinding[name] = function () { + + // No timeout by default + var timeout = 0; + + // Actual function + function dynamic() { + var args = [].slice.call(arguments); + return Call(bindingName, args, timeout); + } + + // Allow setting timeout to function + dynamic.setTimeout = function (newTimeout) { + timeout = newTimeout; + }; + + // Allow getting timeout to function + dynamic.getTimeout = function () { + return timeout; + }; + + return dynamic; + }(); +} diff --git a/runtime/js/core/browser.js b/runtime/js/core/browser.js new file mode 100644 index 000000000..dd7856897 --- /dev/null +++ b/runtime/js/core/browser.js @@ -0,0 +1,34 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The lightweight framework for web-like apps +(c) Lea Anthony 2019-present +*/ +/* jshint esversion: 6 */ + +import { SystemCall } from './calls'; + +/** + * Opens the given URL in the system browser + * + * @export + * @param {string} url + * @returns + */ +export function OpenURL(url) { + return SystemCall('Browser.OpenURL', url); +} + +/** + * Opens the given filename using the system's default file handler + * + * @export + * @param {string} filename + * @returns + */ +export function OpenFile(filename) { + return SystemCall('Browser.OpenFile', filename); +} diff --git a/runtime/js/core/calls.js b/runtime/js/core/calls.js new file mode 100644 index 000000000..9919ff803 --- /dev/null +++ b/runtime/js/core/calls.js @@ -0,0 +1,158 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The lightweight framework for web-like apps +(c) Lea Anthony 2019-present +*/ +/* jshint esversion: 6 */ + +import { Debug } from './log'; +import { SendMessage } from './ipc'; + +var callbacks = {}; + +/** + * Returns a number from the native browser random function + * + * @returns number + */ +function cryptoRandom() { + var array = new Uint32Array(1); + return window.crypto.getRandomValues(array)[0]; +} + +/** + * Returns a number using da old-skool Math.Random + * I likes to call it LOLRandom + * + * @returns number + */ +function basicRandom() { + return Math.random() * 9007199254740991; +} + +// Pick a random number function based on browser capability +var randomFunc; +if (window.crypto) { + randomFunc = cryptoRandom; +} else { + randomFunc = basicRandom; +} + + + + +/** + * Call sends a message to the backend to call the binding with the + * given data. A promise is returned and will be completed when the + * backend responds. This will be resolved when the call was successful + * or rejected if an error is passed back. + * There is a timeout mechanism. If the call doesn't respond in the given + * time (in milliseconds) then the promise is rejected. + * + * @export + * @param {string} bindingName + * @param {string} data + * @param {number=} timeout + * @returns + */ +export function Call(bindingName, data, timeout) { + + // Timeout infinite by default + if (timeout == null) { + timeout = 0; + } + + // Create a promise + return new Promise(function (resolve, reject) { + + // Create a unique callbackID + var callbackID; + do { + callbackID = bindingName + '-' + randomFunc(); + } while (callbacks[callbackID]); + + // Set timeout + if (timeout > 0) { + var timeoutHandle = setTimeout(function () { + reject(Error('Call to ' + bindingName + ' timed out. Request ID: ' + callbackID)); + }, timeout); + } + + // Store callback + callbacks[callbackID] = { + timeoutHandle: timeoutHandle, + reject: reject, + resolve: resolve + }; + + try { + const payload = { + bindingName: bindingName, + data: JSON.stringify(data), + }; + + // Make the call + SendMessage('call', payload, callbackID); + } catch (e) { + // eslint-disable-next-line + console.error(e); + } + }); +} + + + +/** + * Called by the backend to return data to a previously called + * binding invocation + * + * @export + * @param {string} incomingMessage + */ +export function Callback(incomingMessage) { + + // Decode the message - Credit: https://stackoverflow.com/a/13865680 + incomingMessage = decodeURIComponent(incomingMessage.replace(/\s+/g, '').replace(/[0-9a-f]{2}/g, '%$&')); + + // Parse the message + var message; + try { + message = JSON.parse(incomingMessage); + } catch (e) { + const error = `Invalid JSON passed to callback: ${e.message}. Message: ${incomingMessage}`; + Debug(error); + throw new Error(error); + } + var callbackID = message.callbackid; + var callbackData = callbacks[callbackID]; + if (!callbackData) { + const error = `Callback '${callbackID}' not registed!!!`; + console.error(error); // eslint-disable-line + throw new Error(error); + } + clearTimeout(callbackData.timeoutHandle); + + delete callbacks[callbackID]; + + if (message.error) { + callbackData.reject(message.error); + } else { + callbackData.resolve(message.data); + } +} + +/** + * SystemCall is used to call wails methods from the frontend + * + * @export + * @param {string} method + * @param {any[]=} data + * @returns + */ +export function SystemCall(method, data) { + return Call('.wails.' + method, data); +} \ No newline at end of file diff --git a/runtime/js/core/events.js b/runtime/js/core/events.js new file mode 100644 index 000000000..81a663bdc --- /dev/null +++ b/runtime/js/core/events.js @@ -0,0 +1,194 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The lightweight framework for web-like apps +(c) Lea Anthony 2019-present +*/ +/* jshint esversion: 6 */ + +import { Error } from './log'; +import { SendMessage } from './ipc'; + +// Defines a single listener with a maximum number of times to callback +/** + * The Listener class defines a listener! :-) + * + * @class Listener + */ +class Listener { + /** + * Creates an instance of Listener. + * @param {function} callback + * @param {number} maxCallbacks + * @memberof Listener + */ + constructor(callback, maxCallbacks) { + // Default of -1 means infinite + maxCallbacks = maxCallbacks || -1; + // Callback invokes the callback with the given data + // Returns true if this listener should be destroyed + this.Callback = (data) => { + callback.apply(null, data); + // If maxCallbacks is infinite, return false (do not destroy) + if (maxCallbacks === -1) { + return false; + } + // Decrement maxCallbacks. Return true if now 0, otherwise false + maxCallbacks -= 1; + return maxCallbacks === 0; + }; + } +} + +var eventListeners = {}; + +/** + * Registers an event listener that will be invoked `maxCallbacks` times before being destroyed + * + * @export + * @param {string} eventName + * @param {function} callback + * @param {number} maxCallbacks + */ +export function OnMultiple(eventName, callback, maxCallbacks) { + eventListeners[eventName] = eventListeners[eventName] || []; + const thisListener = new Listener(callback, maxCallbacks); + eventListeners[eventName].push(thisListener); +} + +/** + * Registers an event listener that will be invoked every time the event is emitted + * + * @export + * @param {string} eventName + * @param {function} callback + */ +export function On(eventName, callback) { + OnMultiple(eventName, callback); +} + +/** + * Registers an event listener that will be invoked once then destroyed + * + * @export + * @param {string} eventName + * @param {function} callback + */ +export function Once(eventName, callback) { + OnMultiple(eventName, callback, 1); +} + +/** + * Notify informs frontend listeners that an event was emitted with the given data + * + * @export + * @param {string} eventName + * @param {string} data + */ +export function Notify(eventName, data) { + + // Check if we have any listeners for this event + if (eventListeners[eventName]) { + + // Keep a list of listener indexes to destroy + const newEventListenerList = eventListeners[eventName].slice(); + + // Iterate listeners + for (let count = 0; count < eventListeners[eventName].length; count += 1) { + + // Get next listener + const listener = eventListeners[eventName][count]; + + // Parse data if we have it + var parsedData = []; + if (data) { + try { + parsedData = JSON.parse(data); + } catch (e) { + Error('Invalid JSON data sent to notify. Event name = ' + eventName); + } + } + // Do the callback + const destroy = listener.Callback(parsedData); + if (destroy) { + // if the listener indicated to destroy itself, add it to the destroy list + newEventListenerList.splice(count, 1); + } + } + + // Update callbacks with new list of listners + eventListeners[eventName] = newEventListenerList; + } +} + +/** + * Emit an event with the given name and data + * + * @export + * @param {string} eventName + */ +export function Emit(eventName) { + + // Calculate the data + var data = JSON.stringify([].slice.apply(arguments).slice(1)); + + // Notify backend + const payload = { + name: eventName, + data: data, + }; + SendMessage('event', payload); +} + +// Callbacks for the heartbeat calls +const heartbeatCallbacks = {}; + +/** + * Heartbeat emits the event `eventName`, every `timeInMilliseconds` milliseconds until + * the event is acknowledged via `Event.Acknowledge`. Once this happens, `callback` is invoked ONCE + * + * @export + * @param {string} eventName + * @param {number} timeInMilliseconds + * @param {function} callback + */ +export function Heartbeat(eventName, timeInMilliseconds, callback) { + + // Declare interval variable + let interval = null; + + // Setup callback + function dynamicCallback() { + // Kill interval + clearInterval(interval); + // Callback + callback(); + } + + // Register callback + heartbeatCallbacks[eventName] = dynamicCallback; + + // Start emitting the event + interval = setInterval(function () { + Emit(eventName); + }, timeInMilliseconds); +} + +/** + * Acknowledges a heartbeat event by name + * + * @export + * @param {string} eventName + */ +export function Acknowledge(eventName) { + // If we are waiting for acknowledgement for this event type + if (heartbeatCallbacks[eventName]) { + // Acknowledge! + heartbeatCallbacks[eventName](); + } else { + throw new Error(`Cannot acknowledge unknown heartbeat '${eventName}'`); + } +} \ No newline at end of file diff --git a/runtime/js/core/ipc.js b/runtime/js/core/ipc.js new file mode 100644 index 000000000..b453d3ac7 --- /dev/null +++ b/runtime/js/core/ipc.js @@ -0,0 +1,59 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The lightweight framework for web-like apps +(c) Lea Anthony 2019-present +*/ +/* jshint esversion: 6 */ + +// IPC Listeners +var listeners = []; + +/** + * Adds a listener to IPC messages + * @param {function} callback + */ +export function AddIPCListener(callback) { + listeners.push(callback); +} + +/** + * Invoke sends the given message to the backend + * + * @param {string} message + */ +function Invoke(message) { + if (window.wailsbridge) { + window.wailsbridge.websocket.send(message); + } else { + window.external.invoke(message); + } + + // Also send to listeners + if (listeners.length > 0) { + for (var i = 0; i < listeners.length; i++) { + listeners[i](message); + } + } +} + +/** + * Sends a message to the backend based on the given type, payload and callbackID + * + * @export + * @param {string} type + * @param {Object} payload + * @param {string=} callbackID + */ +export function SendMessage(type, payload, callbackID) { + const message = { + type, + callbackID, + payload + }; + + Invoke(JSON.stringify(message)); +} diff --git a/runtime/js/core/log.js b/runtime/js/core/log.js new file mode 100644 index 000000000..e113e8731 --- /dev/null +++ b/runtime/js/core/log.js @@ -0,0 +1,80 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The lightweight framework for web-like apps +(c) Lea Anthony 2019-present +*/ + +/* jshint esversion: 6 */ + +import { SendMessage } from './ipc'; + +/** + * Sends a log message to the backend with the given level + message + * + * @param {string} level + * @param {string} message + */ +function sendLogMessage(level, message) { + + // Log Message + const payload = { + level: level, + message: message, + }; + SendMessage('log', payload); +} + +/** + * Log the given debug message with the backend + * + * @export + * @param {string} message + */ +export function Debug(message) { + sendLogMessage('debug', message); +} + +/** + * Log the given info message with the backend + * + * @export + * @param {string} message + */ +export function Info(message) { + sendLogMessage('info', message); +} + +/** + * Log the given warning message with the backend + * + * @export + * @param {string} message + */ +export function Warning(message) { + sendLogMessage('warning', message); +} + +/** + * Log the given error message with the backend + * + * @export + * @param {string} message + */ +export function Error(message) { + sendLogMessage('error', message); +} + +/** + * Log the given fatal message with the backend + * + * @export + * @param {string} message + */ +export function Fatal(message) { + sendLogMessage('fatal', message); +} + diff --git a/runtime/js/core/main.js b/runtime/js/core/main.js new file mode 100644 index 000000000..51581aadc --- /dev/null +++ b/runtime/js/core/main.js @@ -0,0 +1,88 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The lightweight framework for web-like apps +(c) Lea Anthony 2019-present +*/ +/* jshint esversion: 6 */ +import * as Log from './log'; +import * as Browser from './browser'; +import {Acknowledge, Emit, Heartbeat, Notify, On, OnMultiple} from './events'; +import {NewBinding} from './bindings'; +import {Callback} from './calls'; +import {AddScript, InjectCSS, InjectFirebug} from './utils'; +import {AddIPCListener} from './ipc'; +import * as Store from './store'; + +// Initialise global if not already +window.wails = window.wails || {}; +window.backend = {}; + +// On webkit2gtk >= 2.32, the external object is not passed to the window context. +// However, IE will throw a strict mode error if window.external is assigned to +// so we need to make sure that line of code isn't reached in IE + +// Using !window.external transpiles to `window.external = window.external || ...` +// so we have to use an explicit if statement to prevent webpack from optimizing the code. +if (window.external == undefined) { + window.external = { + invoke: function (x) { + window.webkit.messageHandlers.external.postMessage(x); + } + }; +} + +// Setup internal calls +var internal = { + NewBinding, + Callback, + Notify, + AddScript, + InjectCSS, + Init, + AddIPCListener, +}; + +// Setup runtime structure +var runtime = { + Log, + Browser, + Events: { + On, + OnMultiple, + Emit, + Heartbeat, + Acknowledge, + }, + Store, + _: internal, +}; + +// Augment global +Object.assign(window.wails, runtime); + +// Setup global error handler +window.onerror = function (msg, url, lineNo, columnNo, error) { + window.wails.Log.Error('**** Caught Unhandled Error ****'); + window.wails.Log.Error('Message: ' + msg); + window.wails.Log.Error('URL: ' + url); + window.wails.Log.Error('Line No: ' + lineNo); + window.wails.Log.Error('Column No: ' + columnNo); + window.wails.Log.Error('error: ' + error); +}; + +// Use firebug? +if (window.usefirebug) { + InjectFirebug(); +} + +// Emit loaded event +Emit('wails:loaded'); + +// Nothing to init in production +export function Init(callback) { + callback(); +} diff --git a/runtime/js/core/store.js b/runtime/js/core/store.js new file mode 100644 index 000000000..58e471781 --- /dev/null +++ b/runtime/js/core/store.js @@ -0,0 +1,82 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The lightweight framework for web-like apps +(c) Lea Anthony 2019-present +*/ +/* jshint esversion: 6 */ + +/** + * Creates a new sync store with the given name and optional default value + * + * @export + * @param {string} name + * @param {*} optionalDefault + */ +export function New(name, optionalDefault) { + + var data; + + // Check we are initialised + if( !window.wails) { + throw Error('Wails is not initialised'); + } + + // Store for the callbacks + let callbacks = []; + + // Subscribe to updates by providing a callback + this.subscribe = (callback) => { + callbacks.push(callback); + }; + + // sets the store data to the provided `newdata` value + this.set = (newdata) => { + + data = newdata; + + // Emit a notification to back end + window.wails.Events.Emit('wails:sync:store:updatedbyfrontend:'+name, JSON.stringify(data)); + + // Notify callbacks + callbacks.forEach( function(callback) { + callback(data); + }); + }; + + // update mutates the value in the store by calling the + // provided method with the current value. The value returned + // by the updater function will be set as the new store value + this.update = (updater) => { + var newValue = updater(data); + this.set(newValue); + }; + + // Setup event callback + window.wails.Events.On('wails:sync:store:updatedbybackend:'+name, function(result) { + + // Parse data + result = JSON.parse(result); + + // Todo: Potential preprocessing? + + // Save data + data = result; + + // Notify callbacks + callbacks.forEach( function(callback) { + callback(data); + }); + + }); + + // Set to the optional default if set + if( optionalDefault ) { + this.set(optionalDefault); + } + + return this; +} \ No newline at end of file diff --git a/runtime/js/core/utils.js b/runtime/js/core/utils.js new file mode 100644 index 000000000..425fe1f04 --- /dev/null +++ b/runtime/js/core/utils.js @@ -0,0 +1,46 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The lightweight framework for web-like apps +(c) Lea Anthony 2019-present +*/ +/* jshint esversion: 6 */ + +import { Emit } from './events'; + +export function AddScript(js, callbackID) { + var script = document.createElement('script'); + script.text = js; + document.body.appendChild(script); + if (callbackID) { + Emit(callbackID); + } +} + +export function InjectFirebug() { + // set the debug attribute on HTML + var html = document.getElementsByTagName('html')[0]; + html.setAttribute('debug', 'true'); + var firebugURL = 'https://wails.app/assets/js/firebug-lite.js#startOpened=true,disableWhenFirebugActive=false'; + var script = document.createElement('script'); + script.src = firebugURL; + script.type = 'application/javascript'; + document.head.appendChild(script); + window.wails.Log.Info('Injected firebug'); +} + +// Adapted from webview - thanks zserge! +export function InjectCSS(css) { + var elem = document.createElement('style'); + elem.setAttribute('type', 'text/css'); + if (elem.styleSheet) { + elem.styleSheet.cssText = css; + } else { + elem.appendChild(document.createTextNode(css)); + } + var head = document.head || document.getElementsByTagName('head')[0]; + head.appendChild(elem); +} diff --git a/runtime/js/package-lock.json b/runtime/js/package-lock.json new file mode 100644 index 000000000..5f513aa48 --- /dev/null +++ b/runtime/js/package-lock.json @@ -0,0 +1,6625 @@ +{ + "name": "wails-runtime", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/cli": { + "version": "7.11.6", + "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.11.6.tgz", + "integrity": "sha512-+w7BZCvkewSmaRM6H4L2QM3RL90teqEIHDIFXAmrW33+0jhlymnDAEdqVeCZATvxhQuio1ifoGVlJJbIiH9Ffg==", + "dev": true, + "requires": { + "chokidar": "^2.1.8", + "commander": "^4.0.1", + "convert-source-map": "^1.1.0", + "fs-readdir-recursive": "^1.1.0", + "glob": "^7.0.0", + "lodash": "^4.17.19", + "make-dir": "^2.1.0", + "slash": "^2.0.0", + "source-map": "^0.5.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/compat-data": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.11.0.tgz", + "integrity": "sha512-TPSvJfv73ng0pfnEOh17bYMPQbI95+nGWc71Ss4vZdRBHTDqmM9Z8ZV4rYz8Ks7sfzc95n30k6ODIq5UGnXcYQ==", + "dev": true, + "requires": { + "browserslist": "^4.12.0", + "invariant": "^2.2.4", + "semver": "^5.5.0" + } + }, + "@babel/core": { + "version": "7.11.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.11.6.tgz", + "integrity": "sha512-Wpcv03AGnmkgm6uS6k8iwhIwTrcP0m17TL1n1sy7qD0qelDu4XNeW0dN0mHfa+Gei211yDaLoEe/VlbXQzM4Bg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.11.6", + "@babel/helper-module-transforms": "^7.11.0", + "@babel/helpers": "^7.10.4", + "@babel/parser": "^7.11.5", + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.11.5", + "@babel/types": "^7.11.5", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.19", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.11.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.11.6.tgz", + "integrity": "sha512-DWtQ1PV3r+cLbySoHrwn9RWEgKMBLLma4OBQloPRyDYvc5msJM9kvTLo1YnlJd1P/ZuKbdli3ijr5q3FvAF3uA==", + "dev": true, + "requires": { + "@babel/types": "^7.11.5", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz", + "integrity": "sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz", + "integrity": "sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg==", + "dev": true, + "requires": { + "@babel/helper-explode-assignable-expression": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.4.tgz", + "integrity": "sha512-a3rYhlsGV0UHNDvrtOXBg8/OpfV0OKTkxKPzIplS1zpx7CygDcWWxckxZeDd3gzPzC4kUT0A4nVFDK0wGMh4MQ==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.10.4", + "browserslist": "^4.12.0", + "invariant": "^2.2.4", + "levenary": "^1.1.1", + "semver": "^5.5.0" + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.5.tgz", + "integrity": "sha512-0nkdeijB7VlZoLT3r/mY3bUkw3T8WG/hNw+FATs/6+pG2039IJWjTYL0VTISqsNHMUTEnwbVnc89WIJX9Qed0A==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-member-expression-to-functions": "^7.10.5", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-replace-supers": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.10.4" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz", + "integrity": "sha512-2/hu58IEPKeoLF45DBwx3XFqsbCXmkdAay4spVr2x0jYgRxrSNp+ePwvSsy9g6YSaNDcKIQVPXk1Ov8S2edk2g==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-regex": "^7.10.4", + "regexpu-core": "^4.7.0" + } + }, + "@babel/helper-define-map": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz", + "integrity": "sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.10.4", + "@babel/types": "^7.10.5", + "lodash": "^4.17.19" + } + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.11.4", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.11.4.tgz", + "integrity": "sha512-ux9hm3zR4WV1Y3xXxXkdG/0gxF9nvI0YVmKVhvK9AfMoaQkemL3sJpXw+Xbz65azo8qJiEz2XVDUpK3KYhH3ZQ==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-function-name": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", + "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", + "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz", + "integrity": "sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz", + "integrity": "sha512-JbFlKHFntRV5qKw3YC0CvQnDZ4XMwgzzBbld7Ly4Mj4cbFy3KywcR8NtNctRToMWJOVvLINJv525Gd6wwVEx/Q==", + "dev": true, + "requires": { + "@babel/types": "^7.11.0" + } + }, + "@babel/helper-module-imports": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz", + "integrity": "sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-module-transforms": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz", + "integrity": "sha512-02EVu8COMuTRO1TAzdMtpBPbe6aQ1w/8fePD2YgQmxZU4gpNWaL9gK3Jp7dxlkUlUCJOTaSeA+Hrm1BRQwqIhg==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.10.4", + "@babel/helper-replace-supers": "^7.10.4", + "@babel/helper-simple-access": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/template": "^7.10.4", + "@babel/types": "^7.11.0", + "lodash": "^4.17.19" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz", + "integrity": "sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + }, + "@babel/helper-regex": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.10.5.tgz", + "integrity": "sha512-68kdUAzDrljqBrio7DYAEgCoJHxppJOERHOgOrDN7WjOzP0ZQ1LsSDRXcemzVZaLvjaJsJEESb6qt+znNuENDg==", + "dev": true, + "requires": { + "lodash": "^4.17.19" + } + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.11.4", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.11.4.tgz", + "integrity": "sha512-tR5vJ/vBa9wFy3m5LLv2faapJLnDFxNWff2SAYkSE4rLUdbp7CdObYFgI7wK4T/Mj4UzpjPwzR8Pzmr5m7MHGA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-wrap-function": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-replace-supers": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz", + "integrity": "sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.10.4", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-simple-access": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz", + "integrity": "sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw==", + "dev": true, + "requires": { + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.11.0.tgz", + "integrity": "sha512-0XIdiQln4Elglgjbwo9wuJpL/K7AGCY26kmEt0+pRP0TAj4jjyNq1MjoRvikrTVqKcx4Gysxt4cXvVFXP/JO2Q==", + "dev": true, + "requires": { + "@babel/types": "^7.11.0" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz", + "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==", + "dev": true, + "requires": { + "@babel/types": "^7.11.0" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "@babel/helper-wrap-function": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz", + "integrity": "sha512-6py45WvEF0MhiLrdxtRjKjufwLL1/ob2qDJgg5JgNdojBAZSAKnAjkyOCNug6n+OBl4VW76XjvgSFTdaMcW0Ug==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helpers": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.10.4.tgz", + "integrity": "sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA==", + "dev": true, + "requires": { + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.11.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.5.tgz", + "integrity": "sha512-X9rD8qqm695vgmeaQ4fvz/o3+Wk4ZzQvSHkDBgpYKxpD4qTAUm88ZKtHkVqIOsYFFbIQ6wQYhC6q7pjqVK0E0Q==", + "dev": true + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.5.tgz", + "integrity": "sha512-cNMCVezQbrRGvXJwm9fu/1sJj9bHdGAgKodZdLqOQIpfoH3raqmRPBM17+lh7CzhiKRRBrGtZL9WcjxSoGYUSg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-remap-async-to-generator": "^7.10.4", + "@babel/plugin-syntax-async-generators": "^7.8.0" + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.4.tgz", + "integrity": "sha512-vhwkEROxzcHGNu2mzUC0OFFNXdZ4M23ib8aRRcJSsW8BZK9pQMD7QB7csl97NBbgGZO7ZyHUyKDnxzOaP4IrCg==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.10.4.tgz", + "integrity": "sha512-up6oID1LeidOOASNXgv/CFbgBqTuKJ0cJjz6An5tWD+NVBNlp3VNSBxv2ZdU7SYl3NxJC7agAQDApZusV6uFwQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-dynamic-import": "^7.8.0" + } + }, + "@babel/plugin-proposal-export-namespace-from": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.10.4.tgz", + "integrity": "sha512-aNdf0LY6/3WXkhh0Fdb6Zk9j1NMD8ovj3F6r0+3j837Pn1S1PdNtcwJ5EG9WkVPNHPxyJDaxMaAOVq4eki0qbg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.10.4.tgz", + "integrity": "sha512-fCL7QF0Jo83uy1K0P2YXrfX11tj3lkpN7l4dMv9Y9VkowkhkQDwFHFd8IiwyK5MZjE8UpbgokkgtcReH88Abaw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.0" + } + }, + "@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.11.0.tgz", + "integrity": "sha512-/f8p4z+Auz0Uaf+i8Ekf1iM7wUNLcViFUGiPxKeXvxTSl63B875YPiVdUDdem7hREcI0E0kSpEhS8tF5RphK7Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" + }, + "regexpu-core": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.5.4.tgz", + "integrity": "sha512-BtizvGtFQKGPUcTy56o3nk1bGRp4SZOTYrDtGNlqCQufptV5IkkLN6Emw+yunAJjzf+C9FQFtvq7IoA3+oMYHQ==", + "requires": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.0.2", + "regjsgen": "^0.5.0", + "regjsparser": "^0.6.0", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.1.0" + }, + "dependencies": { + "regenerate": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.1.tgz", + "integrity": "sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A==" + }, + "regenerate-unicode-properties": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", + "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", + "requires": { + "regenerate": "^1.4.0" + } + }, + "unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "requires": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", + "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==" + } + } + }, + "regjsgen": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.0.tgz", + "integrity": "sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA==" + }, + "regjsparser": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz", + "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==", + "requires": { + "jsesc": "~0.5.0" + } + } + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.10.4.tgz", + "integrity": "sha512-wq5n1M3ZUlHl9sqT2ok1T2/MTt6AXE0e1Lz4WzWBr95LsAZ5qDXe4KnFuauYyEyLiohvXFMdbsOTMyLZs91Zlw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.10.4.tgz", + "integrity": "sha512-73/G7QoRoeNkLZFxsoCCvlg4ezE4eM+57PnOqgaPOozd5myfj7p0muD1mRVJvbUWbOzD+q3No2bWbaKy+DJ8DA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.11.0.tgz", + "integrity": "sha512-wzch41N4yztwoRw0ak+37wxwJM2oiIiy6huGCoqkvSTA9acYWcPfn9Y4aJqmFFJ70KTJUu29f3DQ43uJ9HXzEA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-transform-parameters": "^7.10.4" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.10.4.tgz", + "integrity": "sha512-LflT6nPh+GK2MnFiKDyLiqSqVHkQnVf7hdoAvyTnnKj9xB3docGRsdPuxp6qqqW19ifK3xgc9U5/FwrSaCNX5g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.11.0.tgz", + "integrity": "sha512-v9fZIu3Y8562RRwhm1BbMRxtqZNFmFA2EG+pT2diuU8PT3H6T/KXoZ54KgYisfOFZHV6PfvAiBIZ9Rcz+/JCxA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-skip-transparent-expression-wrappers": "^7.11.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.0" + } + }, + "@babel/plugin-proposal-private-methods": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.10.4.tgz", + "integrity": "sha512-wh5GJleuI8k3emgTg5KkJK6kHNsGEr0uBTDBuQUBJwckk9xs1ez79ioheEVVxMLyPscB0LfkbVHslQqIzWV6Bw==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.10.4.tgz", + "integrity": "sha512-H+3fOgPnEXFL9zGYtKQe4IDOPKYlZdF1kqFDQRRb8PK4B8af1vAGK04tF5iQAAsui+mHNBQSAtd2/ndEDe9wuA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.4.tgz", + "integrity": "sha512-GCSBF7iUle6rNugfURwNmCGG3Z/2+opxAMLs1nND4bhEG5PuxTIggDBoeYYSujAlLtsupzOHYJQgPS3pivwXIA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.10.4.tgz", + "integrity": "sha512-ni1brg4lXEmWyafKr0ccFWkJG0CeMt4WV1oyeBW6EFObF4oOHclbkj5cARxAPQyAQ2UTuplJyK4nfkXIMMFvsQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.10.4.tgz", + "integrity": "sha512-9J/oD1jV0ZCBcgnoFWFq1vJd4msoKb/TCpGNFyyLt0zABdcvgK3aYikZ8HjzB14c26bc7E3Q1yugpwGy2aTPNA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.10.4.tgz", + "integrity": "sha512-F6nREOan7J5UXTLsDsZG3DXmZSVofr2tGNwfdrVwkDWHfQckbQXnXSPfD7iO+c/2HGqycwyLST3DnZ16n+cBJQ==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-remap-async-to-generator": "^7.10.4" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.10.4.tgz", + "integrity": "sha512-WzXDarQXYYfjaV1szJvN3AD7rZgZzC1JtjJZ8dMHUyiK8mxPRahynp14zzNjU3VkPqPsO38CzxiWO1c9ARZ8JA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.11.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.11.1.tgz", + "integrity": "sha512-00dYeDE0EVEHuuM+26+0w/SCL0BH2Qy7LwHuI4Hi4MH5gkC8/AqMN5uWFJIsoXZrAphiMm1iXzBw6L2T+eA0ew==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.10.4.tgz", + "integrity": "sha512-2oZ9qLjt161dn1ZE0Ms66xBncQH4In8Sqw1YWgBUZuGVJJS5c0OFZXL6dP2MRHrkU/eKhWg8CzFJhRQl50rQxA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-define-map": "^7.10.4", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-replace-supers": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.10.4", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.10.4.tgz", + "integrity": "sha512-JFwVDXcP/hM/TbyzGq3l/XWGut7p46Z3QvqFMXTfk6/09m7xZHJUN9xHfsv7vqqD4YnfI5ueYdSJtXqqBLyjBw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.10.4.tgz", + "integrity": "sha512-+WmfvyfsyF603iPa6825mq6Qrb7uLjTOsa3XOFzlYcYDHSS4QmpOWOL0NNBY5qMbvrcf3tq0Cw+v4lxswOBpgA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.4.tgz", + "integrity": "sha512-ZEAVvUTCMlMFAbASYSVQoxIbHm2OkG2MseW6bV2JjIygOjdVv8tuxrCTzj1+Rynh7ODb8GivUy7dzEXzEhuPaA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.10.4.tgz", + "integrity": "sha512-GL0/fJnmgMclHiBTTWXNlYjYsA7rDrtsazHG6mglaGSTh0KsrW04qml+Bbz9FL0LcJIRwBWL5ZqlNHKTkU3xAA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.10.4.tgz", + "integrity": "sha512-S5HgLVgkBcRdyQAHbKj+7KyuWx8C6t5oETmUuwz1pt3WTWJhsUV0WIIXuVvfXMxl/QQyHKlSCNNtaIamG8fysw==", + "dev": true, + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.10.4.tgz", + "integrity": "sha512-ItdQfAzu9AlEqmusA/65TqJ79eRcgGmpPPFvBnGILXZH975G0LNjP1yjHvGgfuCxqrPPueXOPe+FsvxmxKiHHQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.10.4.tgz", + "integrity": "sha512-OcDCq2y5+E0dVD5MagT5X+yTRbcvFjDI2ZVAottGH6tzqjx/LKpgkUepu3hp/u4tZBzxxpNGwLsAvGBvQ2mJzg==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.10.4.tgz", + "integrity": "sha512-Xd/dFSTEVuUWnyZiMu76/InZxLTYilOSr1UlHV+p115Z/Le2Fi1KXkJUYz0b42DfndostYlPub3m8ZTQlMaiqQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.10.4.tgz", + "integrity": "sha512-0bFOvPyAoTBhtcJLr9VcwZqKmSjFml1iVxvPL0ReomGU53CX53HsM4h2SzckNdkQcHox1bpAqzxBI1Y09LlBSw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.10.5.tgz", + "integrity": "sha512-elm5uruNio7CTLFItVC/rIzKLfQ17+fX7EVz5W0TMgIHFo1zY0Ozzx+lgwhL4plzl8OzVn6Qasx5DeEFyoNiRw==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.10.5", + "@babel/helper-plugin-utils": "^7.10.4", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.4.tgz", + "integrity": "sha512-Xj7Uq5o80HDLlW64rVfDBhao6OX89HKUmb+9vWYaLXBZOma4gA6tw4Ni1O5qVDoZWUV0fxMYA0aYzOawz0l+1w==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-simple-access": "^7.10.4", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.10.5.tgz", + "integrity": "sha512-f4RLO/OL14/FP1AEbcsWMzpbUz6tssRaeQg11RH1BP/XnPpRoVwgeYViMFacnkaw4k4wjRSjn3ip1Uw9TaXuMw==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.10.4", + "@babel/helper-module-transforms": "^7.10.5", + "@babel/helper-plugin-utils": "^7.10.4", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.10.4.tgz", + "integrity": "sha512-mohW5q3uAEt8T45YT7Qc5ws6mWgJAaL/8BfWD9Dodo1A3RKWli8wTS+WiQ/knF+tXlPirW/1/MqzzGfCExKECA==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.10.4.tgz", + "integrity": "sha512-V6LuOnD31kTkxQPhKiVYzYC/Jgdq53irJC/xBSmqcNcqFGV+PER4l6rU5SH2Vl7bH9mLDHcc0+l9HUOe4RNGKA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.10.4" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.10.4.tgz", + "integrity": "sha512-YXwWUDAH/J6dlfwqlWsztI2Puz1NtUAubXhOPLQ5gjR/qmQ5U96DY4FQO8At33JN4XPBhrjB8I4eMmLROjjLjw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-object-assign": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-assign/-/plugin-transform-object-assign-7.10.4.tgz", + "integrity": "sha512-6zccDhYEICfMeQqIjuY5G09/yhKzG30DKHJeYBQUHIsJH7c2jXSGvgwRalufLAXAq432OSlsEfAOLlzEsQzxVw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.10.4.tgz", + "integrity": "sha512-5iTw0JkdRdJvr7sY0vHqTpnruUpTea32JHmq/atIWqsnNussbRzjEDyWep8UNztt1B5IusBYg8Irb0bLbiEBCQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-replace-supers": "^7.10.4" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.10.5.tgz", + "integrity": "sha512-xPHwUj5RdFV8l1wuYiu5S9fqWGM2DrYc24TMvUiRrPVm+SM3XeqU9BcokQX/kEUe+p2RBwy+yoiR1w/Blq6ubw==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.10.4.tgz", + "integrity": "sha512-ofsAcKiUxQ8TY4sScgsGeR2vJIsfrzqvFb9GvJ5UdXDzl+MyYCaBj/FGzXuv7qE0aJcjWMILny1epqelnFlz8g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.4.tgz", + "integrity": "sha512-3thAHwtor39A7C04XucbMg17RcZ3Qppfxr22wYzZNcVIkPHfpM9J0SO8zuCV6SZa265kxBJSrfKTvDCYqBFXGw==", + "dev": true, + "requires": { + "regenerator-transform": "^0.14.2" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.10.4.tgz", + "integrity": "sha512-hGsw1O6Rew1fkFbDImZIEqA8GoidwTAilwCyWqLBM9f+e/u/sQMQu7uX6dyokfOayRuuVfKOW4O7HvaBWM+JlQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.10.4.tgz", + "integrity": "sha512-AC2K/t7o07KeTIxMoHneyX90v3zkm5cjHJEokrPEAGEy3UCp8sLKfnfOIGdZ194fyN4wfX/zZUWT9trJZ0qc+Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.11.0.tgz", + "integrity": "sha512-UwQYGOqIdQJe4aWNyS7noqAnN2VbaczPLiEtln+zPowRNlD+79w3oi2TWfYe0eZgd+gjZCbsydN7lzWysDt+gw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-skip-transparent-expression-wrappers": "^7.11.0" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.10.4.tgz", + "integrity": "sha512-Ddy3QZfIbEV0VYcVtFDCjeE4xwVTJWTmUtorAJkn6u/92Z/nWJNV+mILyqHKrUxXYKA2EoCilgoPePymKL4DvQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-regex": "^7.10.4" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.10.5.tgz", + "integrity": "sha512-V/lnPGIb+KT12OQikDvgSuesRX14ck5FfJXt6+tXhdkJ+Vsd0lDCVtF6jcB4rNClYFzaB2jusZ+lNISDk2mMMw==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.10.4.tgz", + "integrity": "sha512-QqNgYwuuW0y0H+kUE/GWSR45t/ccRhe14Fs/4ZRouNNQsyd4o3PG4OtHiIrepbM2WKUBDAXKCAK/Lk4VhzTaGA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.10.4.tgz", + "integrity": "sha512-y5XJ9waMti2J+e7ij20e+aH+fho7Wb7W8rNuu72aKRwCHFqQdhkdU2lo3uZ9tQuboEJcUFayXdARhcxLQ3+6Fg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.10.4.tgz", + "integrity": "sha512-wNfsc4s8N2qnIwpO/WP2ZiSyjfpTamT2C9V9FDH/Ljub9zw6P3SjkXcFmc0RQUt96k2fmIvtla2MMjgTwIAC+A==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/preset-env": { + "version": "7.11.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.11.5.tgz", + "integrity": "sha512-kXqmW1jVcnB2cdueV+fyBM8estd5mlNfaQi6lwLgRwCby4edpavgbFhiBNjmWA3JpB/yZGSISa7Srf+TwxDQoA==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.11.0", + "@babel/helper-compilation-targets": "^7.10.4", + "@babel/helper-module-imports": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-proposal-async-generator-functions": "^7.10.4", + "@babel/plugin-proposal-class-properties": "^7.10.4", + "@babel/plugin-proposal-dynamic-import": "^7.10.4", + "@babel/plugin-proposal-export-namespace-from": "^7.10.4", + "@babel/plugin-proposal-json-strings": "^7.10.4", + "@babel/plugin-proposal-logical-assignment-operators": "^7.11.0", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.10.4", + "@babel/plugin-proposal-numeric-separator": "^7.10.4", + "@babel/plugin-proposal-object-rest-spread": "^7.11.0", + "@babel/plugin-proposal-optional-catch-binding": "^7.10.4", + "@babel/plugin-proposal-optional-chaining": "^7.11.0", + "@babel/plugin-proposal-private-methods": "^7.10.4", + "@babel/plugin-proposal-unicode-property-regex": "^7.10.4", + "@babel/plugin-syntax-async-generators": "^7.8.0", + "@babel/plugin-syntax-class-properties": "^7.10.4", + "@babel/plugin-syntax-dynamic-import": "^7.8.0", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.0", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.0", + "@babel/plugin-syntax-top-level-await": "^7.10.4", + "@babel/plugin-transform-arrow-functions": "^7.10.4", + "@babel/plugin-transform-async-to-generator": "^7.10.4", + "@babel/plugin-transform-block-scoped-functions": "^7.10.4", + "@babel/plugin-transform-block-scoping": "^7.10.4", + "@babel/plugin-transform-classes": "^7.10.4", + "@babel/plugin-transform-computed-properties": "^7.10.4", + "@babel/plugin-transform-destructuring": "^7.10.4", + "@babel/plugin-transform-dotall-regex": "^7.10.4", + "@babel/plugin-transform-duplicate-keys": "^7.10.4", + "@babel/plugin-transform-exponentiation-operator": "^7.10.4", + "@babel/plugin-transform-for-of": "^7.10.4", + "@babel/plugin-transform-function-name": "^7.10.4", + "@babel/plugin-transform-literals": "^7.10.4", + "@babel/plugin-transform-member-expression-literals": "^7.10.4", + "@babel/plugin-transform-modules-amd": "^7.10.4", + "@babel/plugin-transform-modules-commonjs": "^7.10.4", + "@babel/plugin-transform-modules-systemjs": "^7.10.4", + "@babel/plugin-transform-modules-umd": "^7.10.4", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.10.4", + "@babel/plugin-transform-new-target": "^7.10.4", + "@babel/plugin-transform-object-super": "^7.10.4", + "@babel/plugin-transform-parameters": "^7.10.4", + "@babel/plugin-transform-property-literals": "^7.10.4", + "@babel/plugin-transform-regenerator": "^7.10.4", + "@babel/plugin-transform-reserved-words": "^7.10.4", + "@babel/plugin-transform-shorthand-properties": "^7.10.4", + "@babel/plugin-transform-spread": "^7.11.0", + "@babel/plugin-transform-sticky-regex": "^7.10.4", + "@babel/plugin-transform-template-literals": "^7.10.4", + "@babel/plugin-transform-typeof-symbol": "^7.10.4", + "@babel/plugin-transform-unicode-escapes": "^7.10.4", + "@babel/plugin-transform-unicode-regex": "^7.10.4", + "@babel/preset-modules": "^0.1.3", + "@babel/types": "^7.11.5", + "browserslist": "^4.12.0", + "core-js-compat": "^3.6.2", + "invariant": "^2.2.2", + "levenary": "^1.1.1", + "semver": "^5.5.0" + } + }, + "@babel/preset-modules": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.4.tgz", + "integrity": "sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + } + }, + "@babel/runtime": { + "version": "7.11.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.11.2.tgz", + "integrity": "sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/template": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", + "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/traverse": { + "version": "7.11.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.11.5.tgz", + "integrity": "sha512-EjiPXt+r7LiCZXEfRpSJd+jUMnBd4/9OUv7Nx3+0u9+eimMwJmG0Q98lw4/289JCoxSE8OolDMNZaaF/JZ69WQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.11.5", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/parser": "^7.11.5", + "@babel/types": "^7.11.5", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.19" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.11.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.5.tgz", + "integrity": "sha512-bvM7Qz6eKnJVFIn+1LPtjlBFPVN5jNDc1XmN15vWe7Q3DPBufWWsLiIvUu7xW87uTG6QoggpIDnUgLQvPheU+Q==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + }, + "@eslint/eslintrc": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.1.3.tgz", + "integrity": "sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "dev": true + }, + "@types/json-schema": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", + "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==", + "dev": true + }, + "@webassemblyjs/ast": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", + "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==", + "dev": true, + "requires": { + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz", + "integrity": "sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz", + "integrity": "sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz", + "integrity": "sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==", + "dev": true + }, + "@webassemblyjs/helper-code-frame": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz", + "integrity": "sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==", + "dev": true, + "requires": { + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "@webassemblyjs/helper-fsm": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz", + "integrity": "sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==", + "dev": true + }, + "@webassemblyjs/helper-module-context": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz", + "integrity": "sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0" + }, + "dependencies": { + "@webassemblyjs/ast": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", + "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==", + "dev": true, + "requires": { + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0" + } + }, + "@webassemblyjs/helper-module-context": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz", + "integrity": "sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g==" + } + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz", + "integrity": "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz", + "integrity": "sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz", + "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz", + "integrity": "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz", + "integrity": "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz", + "integrity": "sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/helper-wasm-section": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-opt": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz", + "integrity": "sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz", + "integrity": "sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz", + "integrity": "sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "@webassemblyjs/wast-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz", + "integrity": "sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/floating-point-hex-parser": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-code-frame": "1.9.0", + "@webassemblyjs/helper-fsm": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz", + "integrity": "sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "acorn": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz", + "integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==", + "dev": true + }, + "acorn-jsx": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", + "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", + "dev": true + }, + "ajv": { + "version": "6.12.4", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz", + "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", + "dev": true + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "optional": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "optional": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, + "assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "dev": true, + "requires": { + "object-assign": "^4.1.1", + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "requires": { + "inherits": "2.0.1" + } + } + } + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "dev": true, + "optional": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "babel-helper-evaluate-path": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.5.0.tgz", + "integrity": "sha512-mUh0UhS607bGh5wUMAQfOpt2JX2ThXMtppHRdRU1kL7ZLRWIXxoV2UIV1r2cAeeNeU1M5SB5/RSUgUxrK8yOkA==", + "dev": true + }, + "babel-helper-flip-expressions": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.4.3.tgz", + "integrity": "sha1-NpZzahKKwYvCUlS19AoizrPB0/0=", + "dev": true + }, + "babel-helper-is-nodes-equiv": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/babel-helper-is-nodes-equiv/-/babel-helper-is-nodes-equiv-0.0.1.tgz", + "integrity": "sha1-NOmzALFHnd2Y7HfqC76TQt/jloQ=", + "dev": true + }, + "babel-helper-is-void-0": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-helper-is-void-0/-/babel-helper-is-void-0-0.4.3.tgz", + "integrity": "sha1-fZwBtFYee5Xb2g9u7kj1tg5nMT4=", + "dev": true + }, + "babel-helper-mark-eval-scopes": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.4.3.tgz", + "integrity": "sha1-0kSjvvmESHJgP/tG4izorN9VFWI=", + "dev": true + }, + "babel-helper-remove-or-void": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.4.3.tgz", + "integrity": "sha1-pPA7QAd6D/6I5F0HAQ3uJB/1rmA=", + "dev": true + }, + "babel-helper-to-multiple-sequence-expressions": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.5.0.tgz", + "integrity": "sha512-m2CvfDW4+1qfDdsrtf4dwOslQC3yhbgyBFptncp4wvtdrDHqueW7slsYv4gArie056phvQFhT2nRcGS4bnm6mA==", + "dev": true + }, + "babel-loader": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.1.0.tgz", + "integrity": "sha512-7q7nC1tYOrqvUrN3LQK4GwSk/TQorZSOlO9C+RZDZpODgyN4ZlCqE5q9cDsyWOliN+aU9B4JX01xK9eJXowJLw==", + "dev": true, + "requires": { + "find-cache-dir": "^2.1.0", + "loader-utils": "^1.4.0", + "mkdirp": "^0.5.3", + "pify": "^4.0.1", + "schema-utils": "^2.6.5" + } + }, + "babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dev": true, + "requires": { + "object.assign": "^4.1.0" + } + }, + "babel-plugin-minify-builtins": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.5.0.tgz", + "integrity": "sha512-wpqbN7Ov5hsNwGdzuzvFcjgRlzbIeVv1gMIlICbPj0xkexnfoIDe7q+AZHMkQmAE/F9R5jkrB6TLfTegImlXag==", + "dev": true + }, + "babel-plugin-minify-constant-folding": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-constant-folding/-/babel-plugin-minify-constant-folding-0.5.0.tgz", + "integrity": "sha512-Vj97CTn/lE9hR1D+jKUeHfNy+m1baNiJ1wJvoGyOBUx7F7kJqDZxr9nCHjO/Ad+irbR3HzR6jABpSSA29QsrXQ==", + "dev": true, + "requires": { + "babel-helper-evaluate-path": "^0.5.0" + } + }, + "babel-plugin-minify-dead-code-elimination": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.5.1.tgz", + "integrity": "sha512-x8OJOZIrRmQBcSqxBcLbMIK8uPmTvNWPXH2bh5MDCW1latEqYiRMuUkPImKcfpo59pTUB2FT7HfcgtG8ZlR5Qg==", + "dev": true, + "requires": { + "babel-helper-evaluate-path": "^0.5.0", + "babel-helper-mark-eval-scopes": "^0.4.3", + "babel-helper-remove-or-void": "^0.4.3", + "lodash": "^4.17.11" + } + }, + "babel-plugin-minify-flip-comparisons": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-flip-comparisons/-/babel-plugin-minify-flip-comparisons-0.4.3.tgz", + "integrity": "sha1-AMqHDLjxO0XAOLPB68DyJyk8llo=", + "dev": true, + "requires": { + "babel-helper-is-void-0": "^0.4.3" + } + }, + "babel-plugin-minify-guarded-expressions": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.4.4.tgz", + "integrity": "sha512-RMv0tM72YuPPfLT9QLr3ix9nwUIq+sHT6z8Iu3sLbqldzC1Dls8DPCywzUIzkTx9Zh1hWX4q/m9BPoPed9GOfA==", + "dev": true, + "requires": { + "babel-helper-evaluate-path": "^0.5.0", + "babel-helper-flip-expressions": "^0.4.3" + } + }, + "babel-plugin-minify-infinity": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-infinity/-/babel-plugin-minify-infinity-0.4.3.tgz", + "integrity": "sha1-37h2obCKBldjhO8/kuZTumB7Oco=", + "dev": true + }, + "babel-plugin-minify-mangle-names": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.5.0.tgz", + "integrity": "sha512-3jdNv6hCAw6fsX1p2wBGPfWuK69sfOjfd3zjUXkbq8McbohWy23tpXfy5RnToYWggvqzuMOwlId1PhyHOfgnGw==", + "dev": true, + "requires": { + "babel-helper-mark-eval-scopes": "^0.4.3" + } + }, + "babel-plugin-minify-numeric-literals": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-numeric-literals/-/babel-plugin-minify-numeric-literals-0.4.3.tgz", + "integrity": "sha1-jk/VYcefeAEob/YOjF/Z3u6TwLw=", + "dev": true + }, + "babel-plugin-minify-replace": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-replace/-/babel-plugin-minify-replace-0.5.0.tgz", + "integrity": "sha512-aXZiaqWDNUbyNNNpWs/8NyST+oU7QTpK7J9zFEFSA0eOmtUNMU3fczlTTTlnCxHmq/jYNFEmkkSG3DDBtW3Y4Q==", + "dev": true + }, + "babel-plugin-minify-simplify": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.5.1.tgz", + "integrity": "sha512-OSYDSnoCxP2cYDMk9gxNAed6uJDiDz65zgL6h8d3tm8qXIagWGMLWhqysT6DY3Vs7Fgq7YUDcjOomhVUb+xX6A==", + "dev": true, + "requires": { + "babel-helper-evaluate-path": "^0.5.0", + "babel-helper-flip-expressions": "^0.4.3", + "babel-helper-is-nodes-equiv": "^0.0.1", + "babel-helper-to-multiple-sequence-expressions": "^0.5.0" + } + }, + "babel-plugin-minify-type-constructors": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-type-constructors/-/babel-plugin-minify-type-constructors-0.4.3.tgz", + "integrity": "sha1-G8bxW4f3qxCF1CszC3F2V6IVZQA=", + "dev": true, + "requires": { + "babel-helper-is-void-0": "^0.4.3" + } + }, + "babel-plugin-transform-inline-consecutive-adds": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.4.3.tgz", + "integrity": "sha1-Mj1Ho+pjqDp6w8gRro5pQfrysNE=", + "dev": true + }, + "babel-plugin-transform-member-expression-literals": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.9.4.tgz", + "integrity": "sha1-NwOcmgwzE6OUlfqsL/OmtbnQOL8=", + "dev": true + }, + "babel-plugin-transform-merge-sibling-variables": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.9.4.tgz", + "integrity": "sha1-hbQi/DN3tEnJ0c3kQIcgNTJAHa4=", + "dev": true + }, + "babel-plugin-transform-minify-booleans": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.9.4.tgz", + "integrity": "sha1-rLs+VqNVXdI5KOS1gtKFFi3SsZg=", + "dev": true + }, + "babel-plugin-transform-property-literals": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.9.4.tgz", + "integrity": "sha1-mMHSHiVXNlc/k+zlRFn2ziSYXTk=", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "babel-plugin-transform-regexp-constructors": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.4.3.tgz", + "integrity": "sha1-WLd3W2OvzzMyj66aX4j71PsLSWU=", + "dev": true + }, + "babel-plugin-transform-remove-console": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.9.4.tgz", + "integrity": "sha1-uYA2DAZzhOJLNXpYjYB9PINSd4A=", + "dev": true + }, + "babel-plugin-transform-remove-debugger": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.9.4.tgz", + "integrity": "sha1-QrcnYxyXl44estGZp67IShgznvI=", + "dev": true + }, + "babel-plugin-transform-remove-undefined": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-undefined/-/babel-plugin-transform-remove-undefined-0.5.0.tgz", + "integrity": "sha512-+M7fJYFaEE/M9CXa0/IRkDbiV3wRELzA1kKQFCJ4ifhrzLKn/9VCCgj9OFmYWwBd8IB48YdgPkHYtbYq+4vtHQ==", + "dev": true, + "requires": { + "babel-helper-evaluate-path": "^0.5.0" + } + }, + "babel-plugin-transform-simplify-comparison-operators": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.9.4.tgz", + "integrity": "sha1-9ir+CWyrDh9ootdT/fKDiIRxzrk=", + "dev": true + }, + "babel-plugin-transform-undefined-to-void": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.9.4.tgz", + "integrity": "sha1-viQcqBQEAwZ4t0hxcyK4nQyP4oA=", + "dev": true + }, + "babel-preset-minify": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/babel-preset-minify/-/babel-preset-minify-0.5.1.tgz", + "integrity": "sha512-1IajDumYOAPYImkHbrKeiN5AKKP9iOmRoO2IPbIuVp0j2iuCcj0n7P260z38siKMZZ+85d3mJZdtW8IgOv+Tzg==", + "dev": true, + "requires": { + "babel-plugin-minify-builtins": "^0.5.0", + "babel-plugin-minify-constant-folding": "^0.5.0", + "babel-plugin-minify-dead-code-elimination": "^0.5.1", + "babel-plugin-minify-flip-comparisons": "^0.4.3", + "babel-plugin-minify-guarded-expressions": "^0.4.4", + "babel-plugin-minify-infinity": "^0.4.3", + "babel-plugin-minify-mangle-names": "^0.5.0", + "babel-plugin-minify-numeric-literals": "^0.4.3", + "babel-plugin-minify-replace": "^0.5.0", + "babel-plugin-minify-simplify": "^0.5.1", + "babel-plugin-minify-type-constructors": "^0.4.3", + "babel-plugin-transform-inline-consecutive-adds": "^0.4.3", + "babel-plugin-transform-member-expression-literals": "^6.9.4", + "babel-plugin-transform-merge-sibling-variables": "^6.9.4", + "babel-plugin-transform-minify-booleans": "^6.9.4", + "babel-plugin-transform-property-literals": "^6.9.4", + "babel-plugin-transform-regexp-constructors": "^0.4.3", + "babel-plugin-transform-remove-console": "^6.9.4", + "babel-plugin-transform-remove-debugger": "^6.9.4", + "babel-plugin-transform-remove-undefined": "^0.5.0", + "babel-plugin-transform-simplify-comparison-operators": "^6.9.4", + "babel-plugin-transform-undefined-to-void": "^6.9.4", + "lodash": "^4.17.11" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", + "dev": true + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true, + "optional": true + }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "optional": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "randombytes": "^2.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } + } + }, + "browserify-sign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", + "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", + "dev": true, + "requires": { + "bn.js": "^4.1.1", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.2", + "elliptic": "^6.0.0", + "inherits": "^2.0.1", + "parse-asn1": "^5.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dev": true, + "requires": { + "pako": "~1.0.5" + } + }, + "browserslist": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.14.0.tgz", + "integrity": "sha512-pUsXKAF2lVwhmtpeA3LJrZ76jXuusrNyhduuQs7CDFf9foT4Y38aQOserd2lMe5DSSrjf3fx34oHwryuvxAUgQ==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001111", + "electron-to-chromium": "^1.3.523", + "escalade": "^3.0.2", + "node-releases": "^1.1.60" + } + }, + "buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", + "dev": true + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001124", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001124.tgz", + "integrity": "sha512-zQW8V3CdND7GHRH6rxm6s59Ww4g/qGWTheoboW9nfeMg7sUoopIfKCcNZUjwYRCOrvereh3kwDpZj4VLQ7zGtA==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "optional": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + }, + "dependencies": { + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "optional": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "optional": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + } + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "chrome-trace-event": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", + "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "console-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "dev": true, + "requires": { + "date-now": "^0.1.4" + } + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", + "dev": true + }, + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "core-js": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz", + "integrity": "sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==", + "dev": true + }, + "core-js-compat": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.5.tgz", + "integrity": "sha512-7ItTKOhOZbznhXAQ2g/slGg1PJV5zDO/WdkTwi7UEOJmkvsE32PWvx6mKtDjiMpjnR2CNf6BAD6sSxIlv7ptng==", + "dev": true, + "requires": { + "browserslist": "^4.8.5", + "semver": "7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true + } + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dev": true, + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "cyclist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", + "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", + "dev": true + }, + "date-now": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "dev": true + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "dev": true + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dev": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "electron-to-chromium": { + "version": "1.3.562", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.562.tgz", + "integrity": "sha512-WhRe6liQ2q/w1MZc8mD8INkenHivuHdrr4r5EQHNomy3NJux+incP6M6lDMd0paShP3MD0WGe5R1TWmEClf+Bg==", + "dev": true + }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dev": true, + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "enhanced-resolve": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.3.0.tgz", + "integrity": "sha512-3e87LvavsdxyoCfGusJnrZ5G8SLPOFeHSNpZI/ATL9a5leXo2k0w6MKnbqhdBad9qTobSfB20Ld7UmgoNbAZkQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + }, + "dependencies": { + "memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + } + } + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "errno": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "dev": true, + "requires": { + "prr": "~1.0.1" + } + }, + "escalade": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.0.2.tgz", + "integrity": "sha512-gPYAU37hYCUhW5euPeR+Y74F7BL+IBsV93j5cvGriSaD1aG6MGsqsV1yamRdrWrb2j3aiZvb0X+UBOWpx3JWtQ==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eslint": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.8.1.tgz", + "integrity": "sha512-/2rX2pfhyUG0y+A123d0ccXtMm7DV7sH1m3lk9nk2DZ2LReq39FXHueR9xZwshE5MdfSf0xunSaMWRqyIA6M1w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@eslint/eslintrc": "^0.1.3", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "eslint-scope": "^5.1.0", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^1.3.0", + "espree": "^7.3.0", + "esquery": "^1.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "eslint-scope": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz", + "integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "espree": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.0.tgz", + "integrity": "sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.3.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", + "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "events": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz", + "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==", + "dev": true + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "figgy-pudding": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", + "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==", + "dev": true + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "optional": true + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "findup-sync": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "dev": true, + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + } + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-readdir-recursive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", + "dev": true + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "dev": true, + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "gensync": { + "version": "1.0.0-beta.1", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", + "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", + "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "requires": { + "global-prefix": "^3.0.0" + }, + "dependencies": { + "global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "requires": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + }, + "dependencies": { + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "graceful-fs": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz", + "integrity": "sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hash-base": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "requires": { + "parse-passwd": "^1.0.0" + } + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", + "dev": true + }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", + "dev": true + }, + "iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", + "dev": true + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "dev": true, + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "requires": { + "loose-envify": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "optional": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "json5": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", + "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, + "levenary": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/levenary/-/levenary-1.1.1.tgz", + "integrity": "sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ==", + "dev": true, + "requires": { + "leven": "^3.1.0" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", + "dev": true + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + } + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "dev": true, + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + } + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "nan": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", + "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==", + "dev": true, + "optional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" + }, + "node-libs-browser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", + "dev": true, + "requires": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.1", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "^1.0.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } + } + }, + "node-releases": { + "version": "1.1.60", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.60.tgz", + "integrity": "sha512-gsO4vjEdQaTusZAEebUWp2a5d7dF5DYoIpDG7WySnk7BuZDW+GPpHXoXXuYawRBr/9t5q54tirPz79kFIWg4dA==", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "optional": true, + "dependencies": { + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" + } + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "dependencies": { + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + } + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", + "dev": true + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "parallel-transform": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", + "dev": true, + "requires": { + "cyclist": "^1.0.1", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-asn1": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", + "dev": true, + "requires": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true, + "optional": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "pbkdf2": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz", + "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==", + "dev": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true, + "optional": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "optional": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "regenerate": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.1.tgz", + "integrity": "sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A==", + "dev": true + }, + "regenerate-unicode-properties": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", + "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", + "dev": true, + "requires": { + "regenerate": "^1.4.0" + } + }, + "regenerator-runtime": { + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", + "dev": true + }, + "regenerator-transform": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", + "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "dev": true, + "requires": { + "@babel/runtime": "^7.8.4" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true + }, + "regexpu-core": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.0.tgz", + "integrity": "sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ==", + "dev": true, + "requires": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.2.0", + "regjsgen": "^0.5.1", + "regjsparser": "^0.6.4", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.2.0" + } + }, + "regjsgen": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", + "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==", + "dev": true + }, + "regjsparser": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz", + "integrity": "sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + } + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true, + "optional": true + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + } + } + }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "dependencies": { + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + } + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "dev": true, + "requires": { + "aproba": "^1.1.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + } + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "dev": true, + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "ssri": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz", + "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "stream-each": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", + "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "dev": true, + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + } + }, + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "dev": true + }, + "terser": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", + "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "source-map-support": { + "version": "0.5.12", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.12.tgz", + "integrity": "sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "timers-browserify": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.10.tgz", + "integrity": "sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==", + "dev": true, + "requires": { + "setimmediate": "^1.0.4" + } + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "tslib": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", + "dev": true + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", + "dev": true + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "unicode-canonical-property-names-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==" + }, + "unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", + "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", + "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==" + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "upath": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz", + "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==", + "dev": true, + "optional": true + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + } + } + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "dev": true, + "requires": { + "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "v8-compile-cache": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", + "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==", + "dev": true + }, + "vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "dev": true + }, + "watchpack": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.4.tgz", + "integrity": "sha512-aWAgTW4MoSJzZPAicljkO1hsi1oKj/RRq/OJQh2PKI2UKL04c2Bs+MBOB+BBABHTXJpf9mCwHN7ANCvYsvY2sg==", + "dev": true, + "requires": { + "chokidar": "^3.4.1", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0", + "watchpack-chokidar2": "^2.0.0" + }, + "dependencies": { + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "optional": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "binary-extensions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", + "dev": true, + "optional": true + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "optional": true, + "requires": { + "fill-range": "^7.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "chokidar": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.2.tgz", + "integrity": "sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A==", + "dev": true, + "optional": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.4.0" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "optional": true, + "requires": { + "to-regex-range": "^5.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "optional": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "optional": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "optional": true + }, + "readdirp": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz", + "integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==", + "dev": true, + "optional": true, + "requires": { + "picomatch": "^2.2.1" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "optional": true, + "requires": { + "is-number": "^7.0.0" + } + } + } + }, + "watchpack-chokidar2": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.0.tgz", + "integrity": "sha512-9TyfOyN/zLUbA288wZ8IsMZ+6cbzvsNyEzSBp6e/zkifi6xxbl8SmQ/CxQq32k8NNqrdVEVUVSEf56L4rQ/ZxA==", + "dev": true, + "optional": true, + "requires": { + "chokidar": "^2.1.8" + } + }, + "webpack": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.44.1.tgz", + "integrity": "sha512-4UOGAohv/VGUNQJstzEywwNxqX417FnjZgZJpJQegddzPmTvph37eBIRbRTfdySXzVtJXLJfbMN3mMYhM6GdmQ==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/wasm-edit": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "acorn": "^6.4.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^4.3.0", + "eslint-scope": "^4.0.3", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.3", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", + "schema-utils": "^1.0.0", + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.3", + "watchpack": "^1.7.4", + "webpack-sources": "^1.4.1" + }, + "dependencies": { + "acorn": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", + "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==", + "dev": true + }, + "cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "dev": true, + "requires": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "terser-webpack-plugin": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", + "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", + "dev": true, + "requires": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + } + } + } + }, + "webpack-cli": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.12.tgz", + "integrity": "sha512-NVWBaz9k839ZH/sinurM+HcDvJOTXwSjYp1ku+5XKeOC03z8v5QitnK/x+lAxGXFyhdayoIf/GOpv85z3/xPag==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "cross-spawn": "^6.0.5", + "enhanced-resolve": "^4.1.1", + "findup-sync": "^3.0.0", + "global-modules": "^2.0.0", + "import-local": "^2.0.0", + "interpret": "^1.4.0", + "loader-utils": "^1.4.0", + "supports-color": "^6.1.0", + "v8-compile-cache": "^2.1.1", + "yargs": "^13.3.2" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "dev": true, + "requires": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "worker-farm": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", + "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", + "dev": true, + "requires": { + "errno": "~0.1.7" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true + }, + "y18n": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", + "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } +} diff --git a/runtime/js/package.json b/runtime/js/package.json new file mode 100644 index 000000000..f5426cac0 --- /dev/null +++ b/runtime/js/package.json @@ -0,0 +1,43 @@ +{ + "name": "wails-runtime", + "version": "1.0.0", + "description": "The Javascript Wails Runtime", + "main": "index.js", + "scripts": { + "build": "./node_modules/.bin/eslint core/ && npm run build:prod", + "build:prod": "./node_modules/.bin/webpack --env prod --colors", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/wailsapp/runtime.git" + }, + "keywords": [ + "Wails", + "Go", + "Javascript", + "Runtime" + ], + "browserslist": [ + "> 5%", + "IE 9" + ], + "author": "Lea Anthony ", + "license": "MIT", + "bugs": { + "url": "https://github.com/wailsapp/runtime/issues" + }, + "homepage": "https://github.com/wailsapp/runtime#readme", + "devDependencies": { + "@babel/cli": "^7.11.5", + "@babel/core": "^7.11.5", + "@babel/plugin-transform-object-assign": "^7.10.4", + "@babel/preset-env": "^7.11.5", + "babel-loader": "^8.1.0", + "babel-preset-minify": "^0.5.1", + "core-js": "^3.6.5", + "eslint": "^7.8.1", + "webpack": "^4.44.1", + "webpack-cli": "^3.3.12" + } +} diff --git a/runtime/js/runtime/.npmignore b/runtime/js/runtime/.npmignore new file mode 100644 index 000000000..945ce43a9 --- /dev/null +++ b/runtime/js/runtime/.npmignore @@ -0,0 +1 @@ +index.js \ No newline at end of file diff --git a/runtime/js/runtime/README.md b/runtime/js/runtime/README.md new file mode 100644 index 000000000..bb608fdca --- /dev/null +++ b/runtime/js/runtime/README.md @@ -0,0 +1,3 @@ +# Wails Runtime + +This module is the Javascript runtime library for the [Wails](https://wails.app) framework. It is intended to be installed as part of a [Wails](https://wails.app) project, not a standalone module. diff --git a/runtime/js/runtime/browser.js b/runtime/js/runtime/browser.js new file mode 100644 index 000000000..70167883f --- /dev/null +++ b/runtime/js/runtime/browser.js @@ -0,0 +1,37 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The lightweight framework for web-like apps +(c) Lea Anthony 2019-present +*/ +/* jshint esversion: 6 */ + +/** + * Opens the given URL in the system browser + * + * @export + * @param {string} url + * @returns + */ +function OpenURL(url) { + return window.wails.Browser.OpenURL(url); +} + +/** + * Opens the given filename using the system's default file handler + * + * @export + * @param {sting} filename + * @returns + */ +function OpenFile(filename) { + return window.wails.Browser.OpenFile(filename); +} + +module.exports = { + OpenURL: OpenURL, + OpenFile: OpenFile +}; \ No newline at end of file diff --git a/runtime/js/runtime/events.js b/runtime/js/runtime/events.js new file mode 100644 index 000000000..30a23a01e --- /dev/null +++ b/runtime/js/runtime/events.js @@ -0,0 +1,90 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The lightweight framework for web-like apps +(c) Lea Anthony 2019-present +*/ +/* jshint esversion: 6 */ + + +/** + * Registers an event listener that will be invoked `maxCallbacks` times before being destroyed + * + * @export + * @param {string} eventName + * @param {function} callback + * @param {number} maxCallbacks + */ +function OnMultiple(eventName, callback, maxCallbacks) { + window.wails.Events.OnMultiple(eventName, callback, maxCallbacks); +} + +/** + * Registers an event listener that will be invoked every time the event is emitted + * + * @export + * @param {string} eventName + * @param {function} callback + */ +function On(eventName, callback) { + OnMultiple(eventName, callback); +} + +/** + * Registers an event listener that will be invoked once then destroyed + * + * @export + * @param {string} eventName + * @param {function} callback + */ +function Once(eventName, callback) { + OnMultiple(eventName, callback, 1); +} + + +/** + * Emit an event with the given name and data + * + * @export + * @param {string} eventName + */ +function Emit(eventName) { + var args = [eventName].slice.call(arguments); + return window.wails.Events.Emit.apply(null, args); +} + + +/** + * Heartbeat emits the event `eventName`, every `timeInMilliseconds` milliseconds until + * the event is acknowledged via `Event.Acknowledge`. Once this happens, `callback` is invoked ONCE + * + * @export + * @param {string} eventName + * @param {number} timeInMilliseconds + * @param {function} callback + */ +function Heartbeat(eventName, timeInMilliseconds, callback) { + window.wails.Events.Heartbeat(eventName, timeInMilliseconds, callback); +} + +/** + * Acknowledges a heartbeat event by name + * + * @export + * @param {string} eventName + */ +function Acknowledge(eventName) { + return window.wails.Events.Acknowledge(eventName); +} + +module.exports = { + OnMultiple: OnMultiple, + On: On, + Once: Once, + Emit: Emit, + Heartbeat: Heartbeat, + Acknowledge: Acknowledge +}; \ No newline at end of file diff --git a/runtime/js/runtime/init.js b/runtime/js/runtime/init.js new file mode 100644 index 000000000..14de18624 --- /dev/null +++ b/runtime/js/runtime/init.js @@ -0,0 +1,21 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The lightweight framework for web-like apps +(c) Lea Anthony 2019-present +*/ +/* jshint esversion: 6 */ + +/** + * Initialises the Wails runtime + * + * @param {function} callback + */ +function Init(callback) { + window.wails._.Init(callback); +} + +module.exports = Init; diff --git a/runtime/js/runtime/log.js b/runtime/js/runtime/log.js new file mode 100644 index 000000000..2defed8f7 --- /dev/null +++ b/runtime/js/runtime/log.js @@ -0,0 +1,70 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The lightweight framework for web-like apps +(c) Lea Anthony 2019-present +*/ + +/* jshint esversion: 6 */ + + +/** + * Log the given debug message with the backend + * + * @export + * @param {string} message + */ +function Debug(message) { + window.wails.Log.Debug(message); +} + +/** + * Log the given info message with the backend + * + * @export + * @param {string} message + */ +function Info(message) { + window.wails.Log.Info(message); +} + +/** + * Log the given warning message with the backend + * + * @export + * @param {string} message + */ +function Warning(message) { + window.wails.Log.Warning(message); +} + +/** + * Log the given error message with the backend + * + * @export + * @param {string} message + */ +function Error(message) { + window.wails.Log.Error(message); +} + +/** + * Log the given fatal message with the backend + * + * @export + * @param {string} message + */ +function Fatal(message) { + window.wails.Log.Fatal(message); +} + +module.exports = { + Debug: Debug, + Info: Info, + Warning: Warning, + Error: Error, + Fatal: Fatal +}; diff --git a/runtime/js/runtime/main.js b/runtime/js/runtime/main.js new file mode 100644 index 000000000..9310b8099 --- /dev/null +++ b/runtime/js/runtime/main.js @@ -0,0 +1,24 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The lightweight framework for web-like apps +(c) Lea Anthony 2019-present +*/ +/* jshint esversion: 6 */ + +const Log = require('./log'); +const Browser = require('./browser'); +const Events = require('./events'); +const Init = require('./init'); +const Store = require('./store'); + +module.exports = { + Log: Log, + Browser: Browser, + Events: Events, + Init: Init, + Store: Store, +}; \ No newline at end of file diff --git a/runtime/js/runtime/package-lock.json b/runtime/js/runtime/package-lock.json new file mode 100644 index 000000000..1efda3274 --- /dev/null +++ b/runtime/js/runtime/package-lock.json @@ -0,0 +1,492 @@ +{ + "name": "@wailsapp/runtime", + "version": "1.1.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "dts-dom": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/dts-dom/-/dts-dom-3.6.0.tgz", + "integrity": "sha512-on5jxTgt+A6r0Zyyz6ZRHXaAO7J1VPnOd6+AmvI1vH440AlAZZNc5rUHzgPuTjGlrVr1rOWQYNl7ZJK6rDohbw==", + "dev": true + }, + "dts-gen": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/dts-gen/-/dts-gen-0.5.8.tgz", + "integrity": "sha512-kIAV6dlHaF7r5J+tIuOC1BJls2P72YM0cyWQUR88zcJEpX2ccRZe+HmXLfkkvfPwjvSO3FEqUiyC8On/grx5qw==", + "dev": true, + "requires": { + "dts-dom": "^3.6.0", + "parse-git-config": "^1.1.1", + "typescript": "^3.5.1", + "yargs": "^4.8.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "fs-exists-sync": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz", + "integrity": "sha1-mC1ok6+RjnLQjeyehnP/K1qNat0=", + "dev": true + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "git-config-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/git-config-path/-/git-config-path-1.0.1.tgz", + "integrity": "sha1-bTP37WPbDQ4RgTFQO6s6ykfVRmQ=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "fs-exists-sync": "^0.1.0", + "homedir-polyfill": "^1.0.0" + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "requires": { + "parse-passwd": "^1.0.0" + } + }, + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "requires": { + "invert-kv": "^1.0.0" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + } + }, + "lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "dev": true, + "requires": { + "lcid": "^1.0.0" + } + }, + "parse-git-config": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/parse-git-config/-/parse-git-config-1.1.1.tgz", + "integrity": "sha1-06mYQxcTL1c5hxK7pDjhKVkN34w=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "fs-exists-sync": "^0.1.0", + "git-config-path": "^1.0.1", + "ini": "^1.3.4" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "dev": true + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + }, + "typescript": { + "version": "3.9.7", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz", + "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", + "dev": true + }, + "window-size": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", + "integrity": "sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU=", + "dev": true + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + } + }, + "y18n": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", + "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==", + "dev": true + }, + "yargs": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", + "integrity": "sha1-wMQpJMpKqmsObaFznfshZDn53cA=", + "dev": true, + "requires": { + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "lodash.assign": "^4.0.3", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.1", + "which-module": "^1.0.0", + "window-size": "^0.2.0", + "y18n": "^3.2.1", + "yargs-parser": "^2.4.1" + } + }, + "yargs-parser": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", + "integrity": "sha1-hVaN488VD/SfpRgl8DqMiA3cxcQ=", + "dev": true, + "requires": { + "camelcase": "^3.0.0", + "lodash.assign": "^4.0.6" + } + } + } +} diff --git a/runtime/js/runtime/package.json b/runtime/js/runtime/package.json new file mode 100644 index 000000000..835d176ac --- /dev/null +++ b/runtime/js/runtime/package.json @@ -0,0 +1,28 @@ +{ + "name": "@wailsapp/runtime", + "version": "1.1.1", + "description": "Wails Javascript runtime library", + "main": "main.js", + "types": "runtime.d.ts", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/wailsapp/wails.git" + }, + "keywords": [ + "Wails", + "Javascript", + "Go" + ], + "author": "Lea Anthony ", + "license": "MIT", + "bugs": { + "url": "https://github.com/wailsapp/wails/issues" + }, + "homepage": "https://github.com/wailsapp/wails#readme", + "devDependencies": { + "dts-gen": "^0.5.8" + } +} diff --git a/runtime/js/runtime/runtime.d.ts b/runtime/js/runtime/runtime.d.ts new file mode 100644 index 000000000..21e07da5b --- /dev/null +++ b/runtime/js/runtime/runtime.d.ts @@ -0,0 +1,29 @@ +export = wailsapp__runtime; + +declare const wailsapp__runtime: { + Browser: { + OpenFile(filename: string): Promise; + OpenURL(url: string): Promise; + }; + Events: { + Acknowledge(eventName: string): void; + Emit(eventName: string, data?: any): void; + Heartbeat(eventName: string, timeInMilliseconds: number, callback: (data?: any) => void): void; + On(eventName: string, callback: (data?: any) => void): void; + OnMultiple(eventName: string, callback: (data?: any) => void, maxCallbacks: number): void; + Once(eventName: string, callback: (data?: any) => void): void; + }; + Init(callback: () => void): void; + Log: { + Debug(message: string): void; + Error(message: string): void; + Fatal(message: string): void; + Info(message: string): void; + Warning(message: string): void; + }; + Store: { + New(name: string, optionalDefault?: any): any; + }; +}; + + diff --git a/runtime/js/runtime/store.js b/runtime/js/runtime/store.js new file mode 100644 index 000000000..3f12fe93b --- /dev/null +++ b/runtime/js/runtime/store.js @@ -0,0 +1,27 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The lightweight framework for web-like apps +(c) Lea Anthony 2019-present +*/ + +/* jshint esversion: 6 */ + + +/** + * Create a new Store with the given name and optional default value + * + * @export + * @param {string} name + * @param {*} optionalDefault + */ +function New(name, optionalDefault) { + return window.wails.Store.New(name, optionalDefault); +} + +module.exports = { + New: New, +}; diff --git a/runtime/js/webpack.config.js b/runtime/js/webpack.config.js new file mode 100644 index 000000000..62cb81a20 --- /dev/null +++ b/runtime/js/webpack.config.js @@ -0,0 +1,4 @@ +/* eslint-disable */ +module.exports = (env) => { + return require(`./webpack.${env}.js`); +}; \ No newline at end of file diff --git a/runtime/js/webpack.prod.js b/runtime/js/webpack.prod.js new file mode 100644 index 000000000..8821d9c56 --- /dev/null +++ b/runtime/js/webpack.prod.js @@ -0,0 +1,38 @@ +/* eslint-disable */ + +const path = require('path'); + +module.exports = { + entry: './core/main', + mode: 'production', + output: { + path: path.resolve(__dirname, '..', 'assets'), + filename: 'wails.js' + }, + module: { + rules: [ + { + test: /\.m?js$/, + exclude: /(node_modules|bower_components)/, + use: { + loader: 'babel-loader', + options: { + plugins: ['@babel/plugin-transform-object-assign'], + presets: [ + [ + '@babel/preset-env', + { + 'useBuiltIns': 'entry', + 'corejs': { + 'version': 3, + 'proposals': true + } + } + ] + ] + } + } + } + ] + } +}; diff --git a/runtime/log.go b/runtime/log.go new file mode 100644 index 000000000..dd609ce51 --- /dev/null +++ b/runtime/log.go @@ -0,0 +1,16 @@ +package runtime + +import "github.com/wailsapp/wails/lib/logger" + +// Log exposes the logging interface to the runtime +type Log struct{} + +// NewLog creates a new Log struct +func NewLog() *Log { + return &Log{} +} + +// New creates a new logger +func (r *Log) New(prefix string) *logger.CustomLogger { + return logger.NewCustomLogger(prefix) +} diff --git a/runtime/runtime.go b/runtime/runtime.go new file mode 100644 index 000000000..7097de7a1 --- /dev/null +++ b/runtime/runtime.go @@ -0,0 +1,29 @@ +package runtime + +import "github.com/wailsapp/wails/lib/interfaces" + +// Runtime is the Wails Runtime Interface, given to a user who has defined the WailsInit method +type Runtime struct { + Events *Events + Log *Log + Dialog *Dialog + Window *Window + Browser *Browser + FileSystem *FileSystem + Store *StoreProvider +} + +// NewRuntime creates a new Runtime struct +func NewRuntime(eventManager interfaces.EventManager, renderer interfaces.Renderer) *Runtime { + result := &Runtime{ + Events: NewEvents(eventManager), + Log: NewLog(), + Dialog: NewDialog(renderer), + Window: NewWindow(renderer), + Browser: NewBrowser(), + FileSystem: NewFileSystem(), + } + // We need a reference to itself + result.Store = NewStoreProvider(result) + return result +} diff --git a/runtime/store.go b/runtime/store.go new file mode 100644 index 000000000..4468296b1 --- /dev/null +++ b/runtime/store.go @@ -0,0 +1,298 @@ +// Package runtime contains all the methods and data structures related to the +// runtime library of Wails. This includes both Go and JS runtimes. +package runtime + +import ( + "bytes" + "encoding/json" + "fmt" + "log" + "reflect" + "sync" +) + +// Options defines the optional data that may be used +// when creating a Store +type Options struct { + + // The name of the store + Name string + + // The runtime to attach the store to + Runtime *Runtime + + // Indicates if notifying Go listeners should be notified of updates + // synchronously (on the current thread) or asynchronously using + // goroutines + NotifySynchronously bool +} + +// StoreProvider is a struct that creates Stores +type StoreProvider struct { + runtime *Runtime +} + +// NewStoreProvider creates new stores using the provided Runtime reference. +func NewStoreProvider(runtime *Runtime) *StoreProvider { + return &StoreProvider{ + runtime: runtime, + } +} + +// Store is where we keep named data +type Store struct { + name string + data reflect.Value + dataType reflect.Type + eventPrefix string + callbacks []reflect.Value + runtime *Runtime + notifySynchronously bool + + // Lock + mux sync.Mutex + + // Error handler + errorHandler func(error) +} + +// New creates a new store +func (p *StoreProvider) New(name string, defaultValue interface{}) *Store { + + dataType := reflect.TypeOf(defaultValue) + + result := Store{ + name: name, + runtime: p.runtime, + data: reflect.ValueOf(defaultValue), + dataType: dataType, + } + + // Setup the sync listener + result.setupListener() + + return &result +} + +// OnError takes a function that will be called +// whenever an error occurs +func (s *Store) OnError(callback func(error)) { + s.errorHandler = callback +} + +// Processes the updates sent by the front end +func (s *Store) processUpdatedData(data string) error { + + // Decode incoming data + var rawdata json.RawMessage + d := json.NewDecoder(bytes.NewBufferString(data)) + err := d.Decode(&rawdata) + if err != nil { + return err + } + + // Create a new instance of our data and unmarshal + // the received value into it + newData := reflect.New(s.dataType).Interface() + err = json.Unmarshal(rawdata, &newData) + if err != nil { + return err + } + + // Lock mutex for writing + s.mux.Lock() + + // Handle nulls + if newData == nil { + s.data = reflect.Zero(s.dataType) + } else { + // Store the resultant value in the data store + s.data = reflect.ValueOf(newData).Elem() + } + + // Unlock mutex + s.mux.Unlock() + + return nil +} + +// Setup listener for front end changes +func (s *Store) setupListener() { + + // Listen for updates from the front end + s.runtime.Events.On("wails:sync:store:updatedbyfrontend:"+s.name, func(data ...interface{}) { + + // Process the incoming data + err := s.processUpdatedData(data[0].(string)) + + if err != nil { + if s.errorHandler != nil { + s.errorHandler(err) + return + } + } + + // Notify listeners + s.notify() + }) +} + +// notify the listeners of the current data state +func (s *Store) notify() { + + // Execute callbacks + for _, callback := range s.callbacks { + + // Build args + args := []reflect.Value{s.data} + + if s.notifySynchronously { + callback.Call(args) + } else { + go callback.Call(args) + } + + } +} + +// Set will update the data held by the store +// and notify listeners of the change +func (s *Store) Set(data interface{}) error { + + inType := reflect.TypeOf(data) + + if inType != s.dataType { + return fmt.Errorf("invalid data given in Store.Set(). Expected %s, got %s", s.dataType.String(), inType.String()) + } + + // Save data + s.mux.Lock() + s.data = reflect.ValueOf(data) + s.mux.Unlock() + + // Stringify data + newdata, err := json.Marshal(data) + if err != nil { + if s.errorHandler != nil { + return err + } + } + + // Emit event to front end + s.runtime.Events.Emit("wails:sync:store:updatedbybackend:"+s.name, string(newdata)) + + // Notify subscribers + s.notify() + + return nil +} + +// callbackCheck ensures the given function to Subscribe() is +// of the correct signature. Absolutely cannot wait for +// generics to land rather than writing this nonsense. +func (s *Store) callbackCheck(callback interface{}) error { + + // Get type + callbackType := reflect.TypeOf(callback) + + // Check callback is a function + if callbackType.Kind() != reflect.Func { + return fmt.Errorf("invalid value given to store.Subscribe(). Expected 'func(%s)'", s.dataType.String()) + } + + // Check input param + if callbackType.NumIn() != 1 { + return fmt.Errorf("invalid number of parameters given in callback function. Expected 1") + } + + // Check input data type + if callbackType.In(0) != s.dataType { + return fmt.Errorf("invalid type for input parameter given in callback function. Expected %s, got %s", s.dataType.String(), callbackType.In(0)) + } + + // Check output param + if callbackType.NumOut() != 0 { + return fmt.Errorf("invalid number of return parameters given in callback function. Expected 0") + } + + return nil +} + +// Subscribe will subscribe to updates to the store by +// providing a callback. Any updates to the store are sent +// to the callback +func (s *Store) Subscribe(callback interface{}) { + + err := s.callbackCheck(callback) + if err != nil { + log.Fatal(err) + } + + callbackFunc := reflect.ValueOf(callback) + + s.callbacks = append(s.callbacks, callbackFunc) +} + +// updaterCheck ensures the given function to Update() is +// of the correct signature. Absolutely cannot wait for +// generics to land rather than writing this nonsense. +func (s *Store) updaterCheck(updater interface{}) error { + + // Get type + updaterType := reflect.TypeOf(updater) + + // Check updater is a function + if updaterType.Kind() != reflect.Func { + return fmt.Errorf("invalid value given to store.Update(). Expected 'func(%s) %s'", s.dataType.String(), s.dataType.String()) + } + + // Check input param + if updaterType.NumIn() != 1 { + return fmt.Errorf("invalid number of parameters given in updater function. Expected 1") + } + + // Check input data type + if updaterType.In(0) != s.dataType { + return fmt.Errorf("invalid type for input parameter given in updater function. Expected %s, got %s", s.dataType.String(), updaterType.In(0)) + } + + // Check output param + if updaterType.NumOut() != 1 { + return fmt.Errorf("invalid number of return parameters given in updater function. Expected 1") + } + + // Check output data type + if updaterType.Out(0) != s.dataType { + return fmt.Errorf("invalid type for return parameter given in updater function. Expected %s, got %s", s.dataType.String(), updaterType.Out(0)) + } + + return nil +} + +// Update takes a function that is passed the current state. +// The result of that function is then set as the new state +// of the store. This will notify listeners of the change +func (s *Store) Update(updater interface{}) { + + err := s.updaterCheck(updater) + if err != nil { + log.Fatal(err) + } + + // Build args + args := []reflect.Value{s.data} + + // Make call + results := reflect.ValueOf(updater).Call(args) + + // We will only have 1 result. Set the store to it + err = s.Set(results[0].Interface()) + if err != nil && s.errorHandler != nil { + s.errorHandler(err) + } +} + +// Get returns the value of the data that's kept in the current state / Store +func (s *Store) Get() interface{} { + return s.data.Interface() +} diff --git a/runtime/window.go b/runtime/window.go new file mode 100644 index 000000000..3665cbaaf --- /dev/null +++ b/runtime/window.go @@ -0,0 +1,99 @@ +package runtime + +import ( + "bytes" + "runtime" + + "github.com/abadojack/whatlanggo" + "github.com/wailsapp/wails/lib/interfaces" + "golang.org/x/text/encoding" + "golang.org/x/text/encoding/japanese" + "golang.org/x/text/encoding/korean" + "golang.org/x/text/encoding/simplifiedchinese" + "golang.org/x/text/transform" +) + +func detectEncoding(text string) (encoding.Encoding, string) { + // korean + var enc encoding.Encoding + info := whatlanggo.Detect(text) + //fmt.Println("Language:", info.Lang.String(), " Script:", whatlanggo.Scripts[info.Script], " Confidence: ", info.Confidence) + switch info.Lang.String() { + case "Korean": + enc = korean.EUCKR + case "Mandarin": + enc = simplifiedchinese.GBK + case "Japanese": + enc = japanese.EUCJP + } + return enc, info.Lang.String() +} + +// ProcessEncoding attempts to convert CKJ strings to UTF-8 +func ProcessEncoding(text string) string { + if runtime.GOOS != "windows" { + return text + } + + encoding, _ := detectEncoding(text) + if encoding != nil { + var bufs bytes.Buffer + wr := transform.NewWriter(&bufs, encoding.NewEncoder()) + _, err := wr.Write([]byte(text)) + defer wr.Close() + if err != nil { + return "" + } + + return bufs.String() + } + return text +} + +// Window exposes an interface for manipulating the window +type Window struct { + renderer interfaces.Renderer +} + +// NewWindow creates a new Window struct +func NewWindow(renderer interfaces.Renderer) *Window { + return &Window{ + renderer: renderer, + } +} + +// SetColour sets the the window colour +func (r *Window) SetColour(colour string) error { + return r.renderer.SetColour(colour) +} + +// SetMinSize sets the minimum size of a resizable window +func (r *Window) SetMinSize(width, height int) { + r.renderer.SetMinSize(width, height) +} + +// SetMaxSize sets the maximum size of a resizable window +func (r *Window) SetMaxSize(width, height int) { + r.renderer.SetMaxSize(width, height) +} + +// Fullscreen makes the window fullscreen +func (r *Window) Fullscreen() { + r.renderer.Fullscreen() +} + +// UnFullscreen attempts to restore the window to the size/position before fullscreen +func (r *Window) UnFullscreen() { + r.renderer.UnFullscreen() +} + +// SetTitle sets the the window title +func (r *Window) SetTitle(title string) { + title = ProcessEncoding(title) + r.renderer.SetTitle(title) +} + +// Close shuts down the window and therefore the app +func (r *Window) Close() { + r.renderer.Close() +} diff --git a/scripts/AUTOMATION-README.md b/scripts/AUTOMATION-README.md deleted file mode 100644 index 4096b1781..000000000 --- a/scripts/AUTOMATION-README.md +++ /dev/null @@ -1,123 +0,0 @@ -# Wails Issue Management Automation - -This directory contains automation workflows and scripts to help manage the Wails project with minimal time investment. - -## GitHub Workflow Files - -### 1. Auto-Label Issues (`auto-label-issues.yml`) -- Automatically labels issues and PRs based on their content and modified files -- Labels are defined in `issue-labeler.yml` and `file-labeler.yml` -- Activates when issues are opened, edited, or reopened - -### 2. Issue Triage Automation (`issue-triage-automation.yml`) -- Performs automated actions for issue triage -- Requests more info for incomplete bug reports -- Prioritizes security issues -- Adds issues to appropriate project boards - -## Configuration Files - -### 1. Issue Content Labeler (`issue-labeler.yml`) -- Defines patterns to match in issue title/body -- Categorizes by version (v2/v3), component, type, and priority -- Customize patterns as needed for your project - -### 2. File Path Labeler (`file-labeler.yml`) -- Labels PRs based on which files they modify -- Helps identify which areas of the codebase are affected -- Customize file patterns as needed - -### 3. Stale Issues Config (`stale.yml`) -- Marks issues as stale after 45 days of inactivity -- Closes stale issues after an additional 10 days -- Exempts issues with important labels - -## Helper Scripts - -### 1. Issue Triage Script (`scripts/issue-triage.ps1`) -- PowerShell script to quickly triage issues -- Lists recent issues needing attention -- Provides easy keyboard shortcuts for common actions -- Run during your dedicated issue triage time - -### 2. PR Review Helper (`scripts/pr-review-helper.ps1`) -- PowerShell script to efficiently review PRs -- Generates review checklists -- Provides easy shortcuts for common review actions -- Run during your dedicated PR review time - -## How to Use This System - -### Daily Workflow (2 hours max) - -**Monday (120 min):** -1. Run `scripts/issue-triage.ps1` (30 min) -2. Run `scripts/pr-review-helper.ps1` (30 min) -3. Check Discord for critical discussions (30 min) -4. Plan your week (30 min) - -**Tuesday-Wednesday (120 min/day):** -1. Quick check for urgent issues (10 min) -2. v3 development (110 min) - -**Thursday (120 min):** -1. v2 maintenance (90 min) -2. Documentation updates (30 min) - -**Friday (120 min):** -1. Run `scripts/pr-review-helper.ps1` (60 min) -2. Discord updates/newsletter (30 min) -3. Weekly reflection (30 min) - -## Installation - -1. The GitHub workflow files should be placed in `.github/workflows/` -2. Configuration files should be placed in `.github/` -3. Helper scripts should be placed in `scripts/` -4. Make sure you have GitHub CLI (`gh`) installed and authenticated - -## Customization - -Feel free to modify the configuration files and scripts to better suit your project's needs: - -1. **Adding New Label Categories**: - - Add new patterns to `issue-labeler.yml` for additional components or types - - Update `file-labeler.yml` if you add new directories or file types - -2. **Adjusting Automation Thresholds**: - - Modify `stale.yml` to change how long issues remain active - - Update `issue-triage-automation.yml` to change conditions for automated actions - -3. **Customizing Scripts**: - - Update the scripts with your specific GitHub username - - Add additional actions based on your workflow preferences - - Adjust time allocations based on which tasks need more attention - -## Benefits - -This automated issue management system will: - -1. **Save Time**: Reduce manual triage of most common issues -2. **Improve Consistency**: Apply the same categorization rules every time -3. **Increase Visibility**: Clear categorization helps community members find issues -4. **Focus Development**: Clearer separation of v2 and v3 work -5. **Reduce Backlog**: Better management of stale issues -6. **Streamline Reviews**: Faster PR processing with guided workflows - -## Requirements - -- GitHub CLI (`gh`) installed and authenticated -- PowerShell 5.1+ for Windows scripts -- GitHub Actions enabled on your repository -- Appropriate permissions to modify workflows - -## Maintenance - -This system requires minimal maintenance: - -- Periodically review and update label patterns as your project evolves -- Adjust time allocations based on where you need to focus -- Update scripts if GitHub CLI commands change -- Customize the workflow as you find pain points in your process - -Remember that the goal is to maximize your limited time (2 hours per day) by automating repetitive tasks and streamlining essential ones. diff --git a/scripts/build.go b/scripts/build.go new file mode 100644 index 000000000..046bc97c3 --- /dev/null +++ b/scripts/build.go @@ -0,0 +1,52 @@ +package main + +import ( + "fmt" + "log" + "os" + "os/exec" + "path/filepath" +) + +func runCommand(command string, args ...string) { + cmd := exec.Command(command, args...) + output, err := cmd.CombinedOutput() + fmt.Println(string(output)) + if err != nil { + log.Println(string(output)) + log.Fatal(err) + } + fmt.Println(string(output)) +} + +// A build step that requires additional params, or platform specific steps for example +func main() { + + dir, _ := os.Getwd() + + // Build Runtime + fmt.Println("**** Building Runtime ****") + runtimeDir, _ := filepath.Abs(filepath.Join(dir, "..", "runtime", "js")) + err := os.Chdir(runtimeDir) + if err != nil { + log.Fatal(err) + } + runCommand("npm", "install") + runCommand("npm", "run", "build") + + // Install Wails + fmt.Println("**** Installing Wails locally ****") + execDir, _ := filepath.Abs(filepath.Join(dir, "..", "cmd", "wails")) + err = os.Chdir(execDir) + if err != nil { + log.Fatal(err) + } + runCommand("go", "install") + + baseDir, _ := filepath.Abs(filepath.Join(dir, "..")) + err = os.Chdir(baseDir) + if err != nil { + log.Fatal(err) + } + runCommand("go", "mod", "tidy") +} diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100755 index 000000000..e99ad26ed --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash + +echo "**** Checking if Wails passes unit tests ****" +if ! go test ./lib/... ./runtime/... ./cmd/... +then + echo "" + echo "ERROR: Unit tests failed!" + exit 1; +fi + +# Build runtime +echo "**** Building Runtime ****" +cd runtime/js +npm install +npm run build +cd ../.. + +cd cmd/wails +echo "**** Checking if Wails compiles ****" +if ! go build . +then + echo "" + echo "ERROR: Build failed!" + exit 1; +fi + +echo "**** Installing Wails locally ****" +if ! go install +then + echo "" + echo "ERROR: Install failed!" + exit 1; +fi +cd ../.. + +echo "**** Tidying the mods! ****" +go mod tidy + +echo "**** WE ARE DONE! ****" diff --git a/scripts/issue-triage.ps1 b/scripts/issue-triage.ps1 deleted file mode 100644 index 6f6edd3ad..000000000 --- a/scripts/issue-triage.ps1 +++ /dev/null @@ -1,108 +0,0 @@ -# issue-triage.ps1 - Script to help with quick issue triage -# Run this at the start of your GitHub time to quickly process issues - -# Set your GitHub username -$GITHUB_USERNAME = "your-username" - -# Get the latest 10 open issues that aren't assigned and aren't labeled as "awaiting feedback" -Write-Host "Fetching recent unprocessed issues..." -gh issue list --repo wailsapp/wails --limit 10 --json number,title,labels,assignees | Out-File -Encoding utf8 -FilePath "issues_temp.json" -$issues = Get-Content -Raw -Path "issues_temp.json" | ConvertFrom-Json -$newIssues = $issues | Where-Object { - $_.assignees.Count -eq 0 -and - ($_.labels.Count -eq 0 -or -not ($_.labels | Where-Object { $_.name -eq "awaiting feedback" })) -} - -# Process each issue -Write-Host "`n===== Issues Needing Triage =====`n" -foreach ($issue in $newIssues) { - $number = $issue.number - $title = $issue.title - $labelNames = $issue.labels | ForEach-Object { $_.name } - $labelsStr = if ($labelNames) { $labelNames -join ", " } else { "none" } - - Write-Host "Issue #$number`: $title" - Write-Host "Labels: $labelsStr`n" - - $continue = $true - while ($continue) { - Write-Host "Options:" - Write-Host " [v] View issue in browser" - Write-Host " [2] Add v2-only label" - Write-Host " [3] Add v3-alpha label" - Write-Host " [b] Add bug label" - Write-Host " [e] Add enhancement label" - Write-Host " [d] Add documentation label" - Write-Host " [w] Add webview2 label" - Write-Host " [f] Request more info (awaiting feedback)" - Write-Host " [c] Close issue (duplicate/invalid)" - Write-Host " [a] Assign to yourself" - Write-Host " [s] Skip to next issue" - Write-Host " [q] Quit script" - $action = Read-Host "Enter action" - - switch ($action) { - "v" { - gh issue view $number --repo wailsapp/wails --web - } - "2" { - Write-Host "Adding v2-only label..." - gh issue edit $number --repo wailsapp/wails --add-label "v2-only" - } - "3" { - Write-Host "Adding v3-alpha label..." - gh issue edit $number --repo wailsapp/wails --add-label "v3-alpha" - } - "b" { - Write-Host "Adding bug label..." - gh issue edit $number --repo wailsapp/wails --add-label "Bug" - } - "e" { - Write-Host "Adding enhancement label..." - gh issue edit $number --repo wailsapp/wails --add-label "Enhancement" - } - "d" { - Write-Host "Adding documentation label..." - gh issue edit $number --repo wailsapp/wails --add-label "Documentation" - } - "w" { - Write-Host "Adding webview2 label..." - gh issue edit $number --repo wailsapp/wails --add-label "webview2" - } - "f" { - Write-Host "Requesting more info..." - gh issue comment $number --repo wailsapp/wails --body "Thank you for reporting this issue. Could you please provide additional information to help us investigate?`n`n- [Specific details needed]`n`nThis will help us address your issue more effectively." - gh issue edit $number --repo wailsapp/wails --add-label "awaiting feedback" - } - "c" { - $reason = Read-Host "Reason for closing (duplicate/invalid/etc)" - gh issue comment $number --repo wailsapp/wails --body "Closing this issue: $reason" - gh issue close $number --repo wailsapp/wails - } - "a" { - Write-Host "Assigning to yourself..." - gh issue edit $number --repo wailsapp/wails --add-assignee "$GITHUB_USERNAME" - } - "s" { - Write-Host "Skipping to next issue..." - $continue = $false - } - "q" { - Write-Host "Exiting script." - exit - } - default { - Write-Host "Invalid option. Please try again." - } - } - - Write-Host "" - } - - Write-Host "--------------------------------`n" -} - -Write-Host "No more issues to triage!" - -# Clean up temp file -Remove-Item -Path "issues_temp.json" diff --git a/scripts/issue-triage.sh b/scripts/issue-triage.sh deleted file mode 100644 index 5809b43a1..000000000 --- a/scripts/issue-triage.sh +++ /dev/null @@ -1,103 +0,0 @@ -#!/bin/bash -# issue-triage.sh - Script to help with quick issue triage -# Run this at the start of your GitHub time to quickly process issues - -# Set your GitHub username -GITHUB_USERNAME="your-username" - -# Get the latest 10 open issues that aren't assigned and aren't labeled as "awaiting feedback" -echo "Fetching recent unprocessed issues..." -gh issue list --repo wailsapp/wails --limit 10 --json number,title,labels,assignees --jq '.[] | select(.assignees | length == 0) | select(any(.labels[]; .name != "awaiting feedback"))' > new_issues.json - -# Process each issue -echo -e "\n===== Issues Needing Triage =====\n" -cat new_issues.json | jq -c '.[]' | while read -r issue; do - number=$(echo $issue | jq -r '.number') - title=$(echo $issue | jq -r '.title') - labels=$(echo $issue | jq -r '.labels[] | .name' 2>/dev/null | tr '\n' ', ' | sed 's/,$//') - - if [ -z "$labels" ]; then - labels="none" - fi - - echo -e "Issue #$number: $title" - echo -e "Labels: $labels\n" - - while true; do - echo "Options:" - echo " [v] View issue in browser" - echo " [2] Add v2-only label" - echo " [3] Add v3-alpha label" - echo " [b] Add bug label" - echo " [e] Add enhancement label" - echo " [d] Add documentation label" - echo " [w] Add webview2 label" - echo " [f] Request more info (awaiting feedback)" - echo " [c] Close issue (duplicate/invalid)" - echo " [a] Assign to yourself" - echo " [s] Skip to next issue" - echo " [q] Quit script" - read -p "Enter action: " action - - case $action in - v) - gh issue view $number --repo wailsapp/wails --web - ;; - 2) - echo "Adding v2-only label..." - gh issue edit $number --repo wailsapp/wails --add-label "v2-only" - ;; - 3) - echo "Adding v3-alpha label..." - gh issue edit $number --repo wailsapp/wails --add-label "v3-alpha" - ;; - b) - echo "Adding bug label..." - gh issue edit $number --repo wailsapp/wails --add-label "Bug" - ;; - e) - echo "Adding enhancement label..." - gh issue edit $number --repo wailsapp/wails --add-label "Enhancement" - ;; - d) - echo "Adding documentation label..." - gh issue edit $number --repo wailsapp/wails --add-label "Documentation" - ;; - w) - echo "Adding webview2 label..." - gh issue edit $number --repo wailsapp/wails --add-label "webview2" - ;; - f) - echo "Requesting more info..." - gh issue comment $number --repo wailsapp/wails --body "Thank you for reporting this issue. Could you please provide additional information to help us investigate?\n\n- [Specific details needed]\n\nThis will help us address your issue more effectively." - gh issue edit $number --repo wailsapp/wails --add-label "awaiting feedback" - ;; - c) - read -p "Reason for closing (duplicate/invalid/etc): " reason - gh issue comment $number --repo wailsapp/wails --body "Closing this issue: $reason" - gh issue close $number --repo wailsapp/wails - ;; - a) - echo "Assigning to yourself..." - gh issue edit $number --repo wailsapp/wails --add-assignee "$GITHUB_USERNAME" - ;; - s) - echo "Skipping to next issue..." - break - ;; - q) - echo "Exiting script." - exit 0 - ;; - *) - echo "Invalid option. Please try again." - ;; - esac - - echo "" - done - - echo -e "--------------------------------\n" -done - -echo "No more issues to triage!" diff --git a/scripts/pr-review-helper.ps1 b/scripts/pr-review-helper.ps1 deleted file mode 100644 index 75fae4c3b..000000000 --- a/scripts/pr-review-helper.ps1 +++ /dev/null @@ -1,152 +0,0 @@ -# pr-review-helper.ps1 - Script to help with efficient PR reviews -# Run this during your PR review time - -# Set your GitHub username -$GITHUB_USERNAME = "your-username" - -# Get open PRs that are ready for review -Write-Host "Fetching PRs ready for review..." -gh pr list --repo wailsapp/wails --json number,title,author,labels,reviewDecision,additions,deletions,baseRefName,headRefName --limit 10 | Out-File -Encoding utf8 -FilePath "prs_temp.json" -$prs = Get-Content -Raw -Path "prs_temp.json" | ConvertFrom-Json - -# Process each PR -Write-Host "`n===== PRs Needing Review =====`n" -foreach ($pr in $prs) { - $number = $pr.number - $title = $pr.title - $author = $pr.author.login - $labels = if ($pr.labels) { $pr.labels | ForEach-Object { $_.name } | Join-String -Separator ", " } else { "none" } - $reviewState = if ($pr.reviewDecision) { $pr.reviewDecision } else { "PENDING" } - $baseRef = $pr.baseRefName - $headRef = $pr.headRefName - $changes = $pr.additions + $pr.deletions - - Write-Host "PR #$number`: $title" - Write-Host "Author: $author" - Write-Host "Labels: $labels" - Write-Host "Branch: $headRef -> $baseRef" - Write-Host "Changes: +$($pr.additions)/-$($pr.deletions) lines" - Write-Host "Review state: $reviewState`n" - - # Determine complexity based on size - $complexity = if ($changes -lt 50) { - "Quick review" - } elseif ($changes -lt 300) { - "Moderate review" - } else { - "Extensive review" - } - - Write-Host "Complexity: $complexity" - - $continue = $true - while ($continue) { - Write-Host "`nOptions:" - Write-Host " [v] View PR in browser" - Write-Host " [d] View diff in browser" - Write-Host " [c] Generate review checklist" - Write-Host " [a] Approve PR" - Write-Host " [r] Request changes" - Write-Host " [m] Add comment" - Write-Host " [l] Add labels" - Write-Host " [s] Skip to next PR" - Write-Host " [q] Quit script" - $action = Read-Host "Enter action" - - switch ($action) { - "v" { - gh pr view $number --repo wailsapp/wails --web - } - "d" { - gh pr diff $number --repo wailsapp/wails --web - } - "c" { - # Generate review checklist - $checklist = @" -## PR Review: $title - -### Basic Checks: -- [ ] PR title is descriptive -- [ ] PR description explains the changes -- [ ] Related issues are linked - -### Technical Checks: -- [ ] Code follows project style -- [ ] No unnecessary commented code -- [ ] Error handling is appropriate -- [ ] Documentation updated (if needed) -- [ ] Tests included (if needed) - -### Impact Assessment: -- [ ] Changes are backward compatible (if applicable) -- [ ] No breaking changes to public APIs -- [ ] Performance impact considered - -### Version Specific: -"@ - - if ($baseRef -eq "master") { - $checklist += @" - -- [ ] Appropriate for v2 maintenance -- [ ] No features that should be v3-only -"@ - } elseif ($baseRef -eq "v3-alpha") { - $checklist += @" - -- [ ] Appropriate for v3 development -- [ ] Aligns with v3 roadmap -"@ - } - - # Write to clipboard - $checklist | Set-Clipboard - Write-Host "`nReview checklist copied to clipboard!`n" - } - "a" { - $comment = Read-Host "Approval comment (blank for none)" - if ($comment) { - gh pr review $number --repo wailsapp/wails --approve --body $comment - } else { - gh pr review $number --repo wailsapp/wails --approve - } - } - "r" { - $comment = Read-Host "Feedback for changes requested" - gh pr review $number --repo wailsapp/wails --request-changes --body $comment - } - "m" { - $comment = Read-Host "Comment text" - gh pr comment $number --repo wailsapp/wails --body $comment - } - "l" { - $labels = Read-Host "Labels to add (comma-separated)" - $labelArray = $labels -split "," - foreach ($label in $labelArray) { - $labelTrimmed = $label.Trim() - if ($labelTrimmed) { - gh pr edit $number --repo wailsapp/wails --add-label $labelTrimmed - } - } - } - "s" { - Write-Host "Skipping to next PR..." - $continue = $false - } - "q" { - Write-Host "Exiting script." - exit - } - default { - Write-Host "Invalid option. Please try again." - } - } - } - - Write-Host "--------------------------------`n" -} - -Write-Host "No more PRs to review!" - -# Clean up temp file -Remove-Item -Path "prs_temp.json" diff --git a/scripts/sponsors/generate-sponsor-image.sh b/scripts/sponsors/generate-sponsor-image.sh deleted file mode 100755 index b034a0176..000000000 --- a/scripts/sponsors/generate-sponsor-image.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash - -npm install sponsorkit@16.4.2 -npx sponsorkit -o ../../website/static/img/ diff --git a/scripts/sponsors/package-lock.json b/scripts/sponsors/package-lock.json deleted file mode 100644 index 2bb15b685..000000000 --- a/scripts/sponsors/package-lock.json +++ /dev/null @@ -1,723 +0,0 @@ -{ - "name": "sponsors", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "sponsors", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "sponsorkit": "^16.5.0" - }, - "engines": { - "node": ">=22.0.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.4.tgz", - "integrity": "sha512-hHyapA4A3gPaDCNfiqyZUStTMqIkKRshqPIuDOXv1hcBnD4U3l8cP0T1HMCfGRxQ6V64TGCcoswChANyOAwbQg==", - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@img/sharp-darwin-arm64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.3.tgz", - "integrity": "sha512-ryFMfvxxpQRsgZJqBd4wsttYQbCxsJksrv9Lw/v798JcQ8+w84mBWuXwl+TT0WJ/WrYOLaYpwQXi3sA9nTIaIg==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.2.0" - } - }, - "node_modules/@img/sharp-darwin-x64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.3.tgz", - "integrity": "sha512-yHpJYynROAj12TA6qil58hmPmAwxKKC7reUqtGLzsOHfP7/rniNGTL8tjWX6L3CTV4+5P4ypcS7Pp+7OB+8ihA==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.2.0" - } - }, - "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.0.tgz", - "integrity": "sha512-sBZmpwmxqwlqG9ueWFXtockhsxefaV6O84BMOrhtg/YqbTaRdqDE7hxraVE3y6gVM4eExmfzW4a8el9ArLeEiQ==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.0.tgz", - "integrity": "sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.0.tgz", - "integrity": "sha512-mWd2uWvDtL/nvIzThLq3fr2nnGfyr/XMXlq8ZJ9WMR6PXijHlC3ksp0IpuhK6bougvQrchUAfzRLnbsen0Cqvw==", - "cpu": [ - "arm" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.0.tgz", - "integrity": "sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-ppc64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.0.tgz", - "integrity": "sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ==", - "cpu": [ - "ppc64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.0.tgz", - "integrity": "sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw==", - "cpu": [ - "s390x" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.0.tgz", - "integrity": "sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.0.tgz", - "integrity": "sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.0.tgz", - "integrity": "sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-linux-arm": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.3.tgz", - "integrity": "sha512-oBK9l+h6KBN0i3dC8rYntLiVfW8D8wH+NPNT3O/WBHeW0OQWCjfWksLUaPidsrDKpJgXp3G3/hkmhptAW0I3+A==", - "cpu": [ - "arm" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.2.0" - } - }, - "node_modules/@img/sharp-linux-arm64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.3.tgz", - "integrity": "sha512-QdrKe3EvQrqwkDrtuTIjI0bu6YEJHTgEeqdzI3uWJOH6G1O8Nl1iEeVYRGdj1h5I21CqxSvQp1Yv7xeU3ZewbA==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.2.0" - } - }, - "node_modules/@img/sharp-linux-ppc64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.3.tgz", - "integrity": "sha512-GLtbLQMCNC5nxuImPR2+RgrviwKwVql28FWZIW1zWruy6zLgA5/x2ZXk3mxj58X/tszVF69KK0Is83V8YgWhLA==", - "cpu": [ - "ppc64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.2.0" - } - }, - "node_modules/@img/sharp-linux-s390x": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.3.tgz", - "integrity": "sha512-3gahT+A6c4cdc2edhsLHmIOXMb17ltffJlxR0aC2VPZfwKoTGZec6u5GrFgdR7ciJSsHT27BD3TIuGcuRT0KmQ==", - "cpu": [ - "s390x" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.2.0" - } - }, - "node_modules/@img/sharp-linux-x64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.3.tgz", - "integrity": "sha512-8kYso8d806ypnSq3/Ly0QEw90V5ZoHh10yH0HnrzOCr6DKAPI6QVHvwleqMkVQ0m+fc7EH8ah0BB0QPuWY6zJQ==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.2.0" - } - }, - "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.3.tgz", - "integrity": "sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.2.0" - } - }, - "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.3.tgz", - "integrity": "sha512-gCWUn9547K5bwvOn9l5XGAEjVTTRji4aPTqLzGXHvIr6bIDZKNTA34seMPgM0WmSf+RYBH411VavCejp3PkOeQ==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.2.0" - } - }, - "node_modules/@img/sharp-wasm32": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.3.tgz", - "integrity": "sha512-+CyRcpagHMGteySaWos8IbnXcHgfDn7pO2fiC2slJxvNq9gDipYBN42/RagzctVRKgxATmfqOSulgZv5e1RdMg==", - "cpu": [ - "wasm32" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", - "optional": true, - "dependencies": { - "@emnapi/runtime": "^1.4.4" - }, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-arm64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.3.tgz", - "integrity": "sha512-MjnHPnbqMXNC2UgeLJtX4XqoVHHlZNd+nPt1kRPmj63wURegwBhZlApELdtxM2OIZDRv/DFtLcNhVbd1z8GYXQ==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-ia32": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.3.tgz", - "integrity": "sha512-xuCdhH44WxuXgOM714hn4amodJMZl3OEvf0GVTm0BEyMeA2to+8HEdRPShH0SLYptJY1uBw+SCFP9WVQi1Q/cw==", - "cpu": [ - "ia32" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-x64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.3.tgz", - "integrity": "sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@quansync/fs": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@quansync/fs/-/fs-0.1.3.tgz", - "integrity": "sha512-G0OnZbMWEs5LhDyqy2UL17vGhSVHkQIfVojMtEWVenvj0V5S84VBgy86kJIuNsGDp2p7sTKlpSIpBUWdC35OKg==", - "license": "MIT", - "dependencies": { - "quansync": "^0.2.10" - }, - "engines": { - "node": ">=20.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sxzz" - } - }, - "node_modules/ansis": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.1.0.tgz", - "integrity": "sha512-BGcItUBWSMRgOCe+SVZJ+S7yTRG0eGt9cXAHev72yuGcY23hnLA7Bky5L/xLyPINoSN95geovfBkqoTlNZYa7w==", - "license": "ISC", - "engines": { - "node": ">=14" - } - }, - "node_modules/cac": { - "version": "6.7.14", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", - "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/color": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", - "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1", - "color-string": "^1.9.0" - }, - "engines": { - "node": ">=12.5.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT" - }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "license": "MIT", - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "node_modules/consola": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", - "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", - "license": "MIT", - "engines": { - "node": "^14.18.0 || >=16.10.0" - } - }, - "node_modules/defu": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", - "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", - "license": "MIT" - }, - "node_modules/destr": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.3.tgz", - "integrity": "sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ==", - "license": "MIT" - }, - "node_modules/detect-libc": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", - "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, - "node_modules/dotenv": { - "version": "16.6.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", - "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", - "license": "MIT" - }, - "node_modules/jiti": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", - "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", - "license": "MIT", - "bin": { - "jiti": "lib/jiti-cli.mjs" - } - }, - "node_modules/node-fetch-native": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.6.tgz", - "integrity": "sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ==", - "license": "MIT" - }, - "node_modules/ofetch": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-1.4.1.tgz", - "integrity": "sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw==", - "license": "MIT", - "dependencies": { - "destr": "^2.0.3", - "node-fetch-native": "^1.6.4", - "ufo": "^1.5.4" - } - }, - "node_modules/quansync": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.10.tgz", - "integrity": "sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/antfu" - }, - { - "type": "individual", - "url": "https://github.com/sponsors/sxzz" - } - ], - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/sharp": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.3.tgz", - "integrity": "sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg==", - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "color": "^4.2.3", - "detect-libc": "^2.0.4", - "semver": "^7.7.2" - }, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.34.3", - "@img/sharp-darwin-x64": "0.34.3", - "@img/sharp-libvips-darwin-arm64": "1.2.0", - "@img/sharp-libvips-darwin-x64": "1.2.0", - "@img/sharp-libvips-linux-arm": "1.2.0", - "@img/sharp-libvips-linux-arm64": "1.2.0", - "@img/sharp-libvips-linux-ppc64": "1.2.0", - "@img/sharp-libvips-linux-s390x": "1.2.0", - "@img/sharp-libvips-linux-x64": "1.2.0", - "@img/sharp-libvips-linuxmusl-arm64": "1.2.0", - "@img/sharp-libvips-linuxmusl-x64": "1.2.0", - "@img/sharp-linux-arm": "0.34.3", - "@img/sharp-linux-arm64": "0.34.3", - "@img/sharp-linux-ppc64": "0.34.3", - "@img/sharp-linux-s390x": "0.34.3", - "@img/sharp-linux-x64": "0.34.3", - "@img/sharp-linuxmusl-arm64": "0.34.3", - "@img/sharp-linuxmusl-x64": "0.34.3", - "@img/sharp-wasm32": "0.34.3", - "@img/sharp-win32-arm64": "0.34.3", - "@img/sharp-win32-ia32": "0.34.3", - "@img/sharp-win32-x64": "0.34.3" - } - }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, - "node_modules/sponsorkit": { - "version": "16.5.0", - "resolved": "https://registry.npmjs.org/sponsorkit/-/sponsorkit-16.5.0.tgz", - "integrity": "sha512-GvlLg88eAEbKzROwAspT+PQTMfHN9KQ+zgPqBBvV1W2jQmKxOtnv9vjgByXvXA2dvTjnksdvbTuwqhJZllyLQA==", - "license": "MIT", - "dependencies": { - "ansis": "^4.1.0", - "cac": "^6.7.14", - "consola": "^3.4.2", - "dotenv": "^16.5.0", - "ofetch": "^1.4.1", - "sharp": "^0.34.2", - "unconfig": "^7.3.2" - }, - "bin": { - "sponsorkit": "bin/sponsorkit.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD", - "optional": true - }, - "node_modules/ufo": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz", - "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==", - "license": "MIT" - }, - "node_modules/unconfig": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/unconfig/-/unconfig-7.3.2.tgz", - "integrity": "sha512-nqG5NNL2wFVGZ0NA/aCFw0oJ2pxSf1lwg4Z5ill8wd7K4KX/rQbHlwbh+bjctXL5Ly1xtzHenHGOK0b+lG6JVg==", - "license": "MIT", - "dependencies": { - "@quansync/fs": "^0.1.1", - "defu": "^6.1.4", - "jiti": "^2.4.2", - "quansync": "^0.2.8" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - } - } -} diff --git a/scripts/sponsors/package.json b/scripts/sponsors/package.json deleted file mode 100644 index c9f000b90..000000000 --- a/scripts/sponsors/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "sponsors", - "version": "1.0.0", - "description": "", - "main": "", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "keywords": [], - "author": "", - "license": "ISC", - "dependencies": { - "sponsorkit": "^16.5.0" - }, - "engines": { - "node": ">=22.0.0" - } -} diff --git a/scripts/sponsors/sponsorkit.config.js b/scripts/sponsors/sponsorkit.config.js deleted file mode 100644 index 6596348d1..000000000 --- a/scripts/sponsors/sponsorkit.config.js +++ /dev/null @@ -1,206 +0,0 @@ -import {defineConfig} from 'sponsorkit'; - -const helpers = { - avatar: { - size: 45 - }, - boxWidth: 55, - boxHeight: 55, - container: { - sidePadding: 30 - }, -}; - -const coffee = { - avatar: { - size: 50 - }, - boxWidth: 65, - boxHeight: 65, - container: { - sidePadding: 30 - }, -}; - -const breakfast = { - avatar: { - size: 55 - }, - boxWidth: 75, - boxHeight: 75, - container: { - sidePadding: 20 - }, - name: { - maxLength: 10 - } -}; - -const costs = { - avatar: { - size: 65 - }, - boxWidth: 90, - boxHeight: 80, - container: { - sidePadding: 30 - }, - name: { - maxLength: 10 - } -}; - -const bronze = { - avatar: { - size: 85 - }, - boxWidth: 110, - boxHeight: 100, - container: { - sidePadding: 30 - }, - name: { - maxLength: 20 - } -}; - -const silver = { - avatar: { - size: 100 - }, - boxWidth: 110, - boxHeight: 110, - container: { - sidePadding: 20 - }, - name: { - maxLength: 20 - } -}; - -const gold = { - avatar: { - size: 150 - }, - boxWidth: 175, - boxHeight: 175, - container: { - sidePadding: 25 - }, - name: { - maxLength: 25 - } -}; - -const champion = { - avatar: { - size: 175 - }, - boxWidth: 200, - boxHeight: 200, - container: { - sidePadding: 30 - }, - name: { - maxLength: 30 - } -}; - -const partner = { - avatar: { - size: 200 - }, - boxWidth: 225, - boxHeight: 225, - container: { - sidePadding: 40 - }, - name: { - maxLength: 40 - }, - -}; - -export default defineConfig({ - github: { - login: 'leaanthony', - type: 'user', - }, - - // Rendering configs - width: 800, - formats: ['svg'], - tiers: [ - { - title: 'Helpers', - preset: helpers, - composeAfter: function (composer, tierSponsors, config) { - composer.addSpan(20); - } - }, - { - title: 'Buying Coffee', - monthlyDollars: 5, - preset: coffee, - composeAfter: function (composer, tierSponsors, config) { - composer.addSpan(20); - } - }, - { - title: 'Buying Breakfast', - monthlyDollars: 10, - preset: breakfast, - composeAfter: function (composer, tierSponsors, config) { - composer.addSpan(20); - } - }, - { - title: 'Covering Costs', - monthlyDollars: 20, - preset: costs, - composeAfter: function (composer, tierSponsors, config) { - composer.addSpan(20); - } - }, - { - title: 'Bronze Sponsors', - monthlyDollars: 50, - preset: bronze, - composeAfter: function (composer, tierSponsors, config) { - composer.addSpan(20); - } - }, - { - title: 'Silver Sponsors', - monthlyDollars: 100, - preset: silver, - composeAfter: function (composer, tierSponsors, config) { - composer.addSpan(20); - } - }, - { - title: 'Gold Sponsors', - monthlyDollars: 200, - preset: gold, - composeAfter: function (composer, tierSponsors, config) { - composer.addSpan(20); - } - }, - { - title: 'Champion', - monthlyDollars: 500, - preset: champion, - composeAfter: function (composer, tierSponsors, config) { - composer.addSpan(20); - } - }, - { - title: 'Partner', - monthlyDollars: 1000, - preset: partner, - composeAfter: function (composer, tierSponsors, config) { - composer.addSpan(20); - } - }, - ], -}); \ No newline at end of file diff --git a/scripts/updateversion.sh b/scripts/updateversion.sh new file mode 100755 index 000000000..e0c4b6e82 --- /dev/null +++ b/scripts/updateversion.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +if [ "$#" != "1" ]; then + echo "Tag required" + exit 1 +fi +TAG=${1} +cat << EOF > cmd/version.go +package cmd + +// Version - Wails version +const Version = "${TAG}" +EOF + +# Build runtime +cd runtime/js +npm run build + +cd ../.. + +git add cmd/version.go +git commit cmd/version.go -m "Bump to ${TAG}" +git tag ${TAG} diff --git a/assets/images/sponsors/bronze-sponsor.png b/sponsors/bronze sponsor.png similarity index 100% rename from assets/images/sponsors/bronze-sponsor.png rename to sponsors/bronze sponsor.png diff --git a/v2/.golangci.yml b/v2/.golangci.yml deleted file mode 100644 index 66b77ba7f..000000000 --- a/v2/.golangci.yml +++ /dev/null @@ -1,162 +0,0 @@ -# Options for analysis runner. -run: - # Custom concurrency value - concurrency: 4 - - # Execution timeout - timeout: 10m - - # Exit code when an issue is found. - issues-exit-code: 1 - - # Inclusion of test files - tests: false - - modules-download-mode: readonly - - allow-parallel-runners: false - - go: '1.21' - - -output: - # Runner output format - format: tab - - # Print line of issue code - print-issued-lines: false - - # Append linter to the output - print-linter-name: true - - # Separate issues by line - uniq-by-line: true - - # Output path prefixing - path-prefix: "" - - # Sort results - sort-results: true - - -# Specific linter configs -linters-settings: - errcheck: - check-type-assertions: false - check-blank: false - ignore: fmt:.* - disable-default-exclusions: false - - gofmt: - simplify: true - - gofumpt: - extra-rules: false - -linters: - fast: false - # Enable all available linters. - enable-all: true - # Disable specific linters - disable: - - asasalint - - asciicheck - - bidichk - - bodyclose - - containedctx - - contextcheck - - cyclop - - deadcode - - decorder - - depguard - - dogsled - - dupl - - dupword - - durationcheck - - errchkjson - - errorlint - - execinquery - - exhaustive - - exhaustivestruct - - exhaustruct - - exportloopref - - forbidigo - - forcetypeassert - - funlen - - gci - - ginkgolinter - - gocheckcompilerdirectives - - gochecknoglobals - - gochecknoinits - - gocognit - - goconst - - gocritic - - gocyclo - - godot - - godox - - goerr113 - - goheader - - goimports - - golint - - gomnd - - gomoddirectives - - gomodguard - - goprintffuncname - - gosec - - gosmopolitan - - govet - - grouper - - ifshort - - importas - - ineffassign - - interfacebloat - - interfacer - - ireturn - - lll - - loggercheck - - maintidx - - makezero - - maligned - - mirror - - musttag - - nakedret - - nestif - - nilerr - - nilnil - - nlreturn - - noctx - - nolintlint - - nonamedreturns - - nosnakecase - - nosprintfhostport - - paralleltest - - prealloc - - predeclared - - promlinter - - reassign - - revive - - rowserrcheck - - scopelint - - sqlclosecheck - - staticcheck - - structcheck - - stylecheck - - tagalign - - tagliatelle - - tenv - - testableexamples - - testpackage - - thelper - - tparallel - - typecheck - - unconvert - - unparam - - unused - - usestdlibvars - - varcheck - - varnamelen - - wastedassign - - whitespace - - wrapcheck - - wsl - - zerologlint \ No newline at end of file diff --git a/v2/.prettierignore b/v2/.prettierignore deleted file mode 100644 index 94c6af38e..000000000 --- a/v2/.prettierignore +++ /dev/null @@ -1 +0,0 @@ -website \ No newline at end of file diff --git a/v2/.prettierrc.yml b/v2/.prettierrc.yml deleted file mode 100644 index 685d8b6e7..000000000 --- a/v2/.prettierrc.yml +++ /dev/null @@ -1,6 +0,0 @@ -overrides: - - files: - - "**/*.md" - options: - printWidth: 80 - proseWrap: always diff --git a/v2/NOTES.md b/v2/NOTES.md new file mode 100644 index 000000000..16bac7122 --- /dev/null +++ b/v2/NOTES.md @@ -0,0 +1,40 @@ + +# Packing linux + + * create app, app.desktop, app.png (512x512) + * chmod +x app! + * ./linuxdeploy-x86_64.AppImage --appdir AppDir -i react.png -d react.desktop -e react --output appimage + + +# Wails Doctor + +Tested on: + + * Debian 8 + * Ubuntu 20.04 + * Ubuntu 19.10 + * Solus 4.1 + * Centos 8 + * Gentoo + * OpenSUSE/leap + * Fedora 31 + +### Development + +Add a new package manager processor here: `v2/internal/system/packagemanager/`. IsAvailable should work even if the package is installed. +Add your new package manager to the list of package managers in `v2/internal/system/packagemanager/packagemanager.go`: + +``` +var db = map[string]PackageManager{ + "eopkg": NewEopkg(), + "apt": NewApt(), + "yum": NewYum(), + "pacman": NewPacman(), + "emerge": NewEmerge(), + "zypper": NewZypper(), +} +``` + +## Gentoo + + * Setup docker image using: emerge-webrsync -x -v diff --git a/v2/README.md b/v2/README.md index c69808f58..20ebb18b7 100644 --- a/v2/README.md +++ b/v2/README.md @@ -1,238 +1,6 @@ -

-
-

+# Wails v2 ALPHA -

- Build desktop applications using Go & Web Technologies. -
-
- - GitHub - - - - - - Go Reference - - - CodeFactor - - - - - - Awesome - -
- - Build - - - GitHub tag (latest SemVer pre-release) - -

+This branch contains WORK IN PROGRESS! There are no guarantees. Use at your peril! -
- - +This document will be updated as progress is made. -[English](README.md) · [简体中文](README.zh-Hans.md) · [日本語](README.ja.md) - - - -
- -## Table of Contents - -
- Click me to Open/Close the directory listing - -- [Table of Contents](#table-of-contents) -- [Introduction](#introduction) - - [Roadmap](#roadmap) -- [Features](#features) -- [Sponsors](#sponsors) -- [Getting Started](#getting-started) -- [FAQ](#faq) -- [Contributors](#contributors) -- [License](#license) - -
- -## Introduction - -The traditional method of providing web interfaces to Go programs is via a built-in web server. Wails offers a different -approach: it provides the ability to wrap both Go code and a web frontend into a single binary. Tools are provided to -make this easy for you by handling project creation, compilation and bundling. All you have to do is get creative! - -## Features - -- Use standard Go for the backend -- Use any frontend technology you are already familiar with to build your UI -- Quickly create rich frontends for your Go programs using pre-built templates -- Easily call Go methods from Javascript -- Auto-generated Typescript definitions for your Go structs and methods -- Native Dialogs & Menus -- Native Dark / Light mode support -- Supports modern translucency and "frosted window" effects -- Unified eventing system between Go and Javascript -- Powerful cli tool to quickly generate and build your projects -- Multiplatform -- Uses native rendering engines - _no embedded browser_! - -### Roadmap - -The project roadmap may be found [here](https://github.com/wailsapp/wails/discussions/1484). Please consult -this before open up an enhancement request. - -## Sponsors - -This project is supported by these kind people / companies: - - - - - - - -
-
- - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -## Getting Started - -The installation instructions are on the [official website](https://wails.io/docs/gettingstarted/installation). - -## FAQ - -- Is this an alternative to Electron? - - Depends on your requirements. It's designed to make it easy for Go programmers to make lightweight desktop - applications or add a frontend to their existing applications. Wails does offer native elements such as menus - and dialogs, so it could be considered a lightweight electron alternative. - -- Who is this project aimed at? - - Go programmers who want to bundle an HTML/JS/CSS frontend with their applications, without resorting to creating a - server and opening a browser to view it. - -- What's with the name? - - When I saw WebView, I thought "What I really want is tooling around building a WebView app, a bit like Rails is to - Ruby". So initially it was a play on words (Webview on Rails). It just so happened to also be a homophone of the - English name for the [Country](https://en.wikipedia.org/wiki/Wales) I am from. So it stuck. - -## Stargazers over time - -[![Stargazers over time](https://starchart.cc/wailsapp/wails.svg)](https://starchart.cc/wailsapp/wails) - -## Contributors - -The contributors list is getting too big for the readme! All the amazing people who have contributed to this -project have their own page [here](https://wails.io/credits#contributors). - -## License - -[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fwailsapp%2Fwails.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fwailsapp%2Fwails?ref=badge_large) - -## Inspiration - -This project was mainly coded to the following albums: - -- [Manic Street Preachers - Resistance Is Futile](https://open.spotify.com/album/1R2rsEUqXjIvAbzM0yHrxA) -- [Manic Street Preachers - This Is My Truth, Tell Me Yours](https://open.spotify.com/album/4VzCL9kjhgGQeKCiojK1YN) -- [The Midnight - Endless Summer](https://open.spotify.com/album/4Krg8zvprquh7TVn9OxZn8) -- [Gary Newman - Savage (Songs from a Broken World)](https://open.spotify.com/album/3kMfsD07Q32HRWKRrpcexr) -- [Steve Vai - Passion & Warfare](https://open.spotify.com/album/0oL0OhrE2rYVns4IGj8h2m) -- [Ben Howard - Every Kingdom](https://open.spotify.com/album/1nJsbWm3Yy2DW1KIc1OKle) -- [Ben Howard - Noonday Dream](https://open.spotify.com/album/6astw05cTiXEc2OvyByaPs) -- [Adwaith - Melyn](https://open.spotify.com/album/2vBE40Rp60tl7rNqIZjaXM) -- [Gwidaith Hen Fran - Cedors Hen Wrach](https://open.spotify.com/album/3v2hrfNGINPLuDP0YDTOjm) -- [Metallica - Metallica](https://open.spotify.com/album/2Kh43m04B1UkVcpcRa1Zug) -- [Bloc Party - Silent Alarm](https://open.spotify.com/album/6SsIdN05HQg2GwYLfXuzLB) -- [Maxthor - Another World](https://open.spotify.com/album/3tklE2Fgw1hCIUstIwPBJF) -- [Alun Tan Lan - Y Distawrwydd](https://open.spotify.com/album/0c32OywcLpdJCWWMC6vB8v) diff --git a/v2/Taskfile.yaml b/v2/Taskfile.yaml deleted file mode 100644 index d1893732b..000000000 --- a/v2/Taskfile.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# https://taskfile.dev - -version: "3" - -tasks: - download: - summary: Run go mod tidy - cmds: - - go mod tidy - - lint: - summary: Run golangci-lint - cmds: - - golangci-lint run ./... --timeout=3m -v - - release: - summary: Release a new version of Task. Call with `task v2:release -- ` - dir: tools/release - cmds: - - go run release.go {{.CLI_ARGS}} - - format:md: - cmds: - - npx prettier --write "**/*.md" - - format: - cmds: - - task: format:md diff --git a/v2/cmd/wails/build.go b/v2/cmd/wails/build.go deleted file mode 100644 index 39ad00d2f..000000000 --- a/v2/cmd/wails/build.go +++ /dev/null @@ -1,276 +0,0 @@ -package main - -import ( - "fmt" - "github.com/wailsapp/wails/v2/pkg/commands/buildtags" - "os" - "runtime" - "strings" - "time" - - "github.com/leaanthony/slicer" - "github.com/pterm/pterm" - "github.com/wailsapp/wails/v2/cmd/wails/flags" - "github.com/wailsapp/wails/v2/cmd/wails/internal/gomod" - "github.com/wailsapp/wails/v2/internal/colour" - "github.com/wailsapp/wails/v2/internal/project" - "github.com/wailsapp/wails/v2/pkg/clilogger" - "github.com/wailsapp/wails/v2/pkg/commands/build" -) - -func buildApplication(f *flags.Build) error { - if f.NoColour { - pterm.DisableColor() - colour.ColourEnabled = false - } - - quiet := f.Verbosity == flags.Quiet - - // Create logger - logger := clilogger.New(os.Stdout) - logger.Mute(quiet) - - if quiet { - pterm.DisableOutput() - } else { - app.PrintBanner() - } - - err := f.Process() - if err != nil { - return err - } - - cwd, err := os.Getwd() - if err != nil { - return err - } - projectOptions, err := project.Load(cwd) - if err != nil { - return err - } - - // Set obfuscation from project file - if projectOptions.Obfuscated { - f.Obfuscated = projectOptions.Obfuscated - } - - // Set garble args from project file - if projectOptions.GarbleArgs != "" { - f.GarbleArgs = projectOptions.GarbleArgs - } - - projectTags, err := buildtags.Parse(projectOptions.BuildTags) - if err != nil { - return err - } - userTags := f.GetTags() - compiledTags := append(projectTags, userTags...) - - // Create BuildOptions - buildOptions := &build.Options{ - Logger: logger, - OutputType: "desktop", - OutputFile: f.OutputFilename, - CleanBinDirectory: f.Clean, - Mode: f.GetBuildMode(), - Devtools: f.Debug || f.Devtools, - Pack: !f.NoPackage, - LDFlags: f.LdFlags, - Compiler: f.Compiler, - SkipModTidy: f.SkipModTidy, - Verbosity: f.Verbosity, - ForceBuild: f.ForceBuild, - IgnoreFrontend: f.SkipFrontend, - Compress: f.Upx, - CompressFlags: f.UpxFlags, - UserTags: compiledTags, - WebView2Strategy: f.GetWebView2Strategy(), - TrimPath: f.TrimPath, - RaceDetector: f.RaceDetector, - WindowsConsole: f.WindowsConsole, - Obfuscated: f.Obfuscated, - GarbleArgs: f.GarbleArgs, - SkipBindings: f.SkipBindings, - ProjectData: projectOptions, - SkipEmbedCreate: f.SkipEmbedCreate, - } - - tableData := pterm.TableData{ - {"Platform(s)", f.Platform}, - {"Compiler", f.GetCompilerPath()}, - {"Skip Bindings", bool2Str(f.SkipBindings)}, - {"Build Mode", f.GetBuildModeAsString()}, - {"Devtools", bool2Str(buildOptions.Devtools)}, - {"Frontend Directory", projectOptions.GetFrontendDir()}, - {"Obfuscated", bool2Str(f.Obfuscated)}, - } - if f.Obfuscated { - tableData = append(tableData, []string{"Garble Args", f.GarbleArgs}) - } - tableData = append(tableData, pterm.TableData{ - {"Skip Frontend", bool2Str(f.SkipFrontend)}, - {"Compress", bool2Str(f.Upx)}, - {"Package", bool2Str(!f.NoPackage)}, - {"Clean Bin Dir", bool2Str(f.Clean)}, - {"LDFlags", f.LdFlags}, - {"Tags", "[" + strings.Join(compiledTags, ",") + "]"}, - {"Race Detector", bool2Str(f.RaceDetector)}, - }...) - if len(buildOptions.OutputFile) > 0 && f.GetTargets().Length() == 1 { - tableData = append(tableData, []string{"Output File", f.OutputFilename}) - } - pterm.DefaultSection.Println("Build Options") - - err = pterm.DefaultTable.WithData(tableData).Render() - if err != nil { - return err - } - - if !f.NoSyncGoMod { - err = gomod.SyncGoMod(logger, f.UpdateWailsVersionGoMod) - if err != nil { - return err - } - } - - // Check platform - validPlatformArch := slicer.String([]string{ - "darwin", - "darwin/amd64", - "darwin/arm64", - "darwin/universal", - "linux", - "linux/amd64", - "linux/arm64", - "linux/arm", - "windows", - "windows/amd64", - "windows/arm64", - "windows/386", - }) - - outputBinaries := map[string]string{} - - // Allows cancelling the build after the first error. It would be nice if targets.Each would support funcs - // returning an error. - var targetErr error - targets := f.GetTargets() - targets.Each(func(platform string) { - if targetErr != nil { - return - } - - if !validPlatformArch.Contains(platform) { - buildOptions.Logger.Println("platform '%s' is not supported - skipping. Supported platforms: %s", platform, validPlatformArch.Join(",")) - return - } - - desiredFilename := projectOptions.OutputFilename - if desiredFilename == "" { - desiredFilename = projectOptions.Name - } - desiredFilename = strings.TrimSuffix(desiredFilename, ".exe") - - // Calculate platform and arch - platformSplit := strings.Split(platform, "/") - buildOptions.Platform = platformSplit[0] - buildOptions.Arch = f.GetDefaultArch() - if len(platformSplit) > 1 { - buildOptions.Arch = platformSplit[1] - } - banner := "Building target: " + buildOptions.Platform + "/" + buildOptions.Arch - pterm.DefaultSection.Println(banner) - - if f.Upx && platform == "darwin/universal" { - pterm.Warning.Println("Warning: compress flag unsupported for universal binaries. Ignoring.") - f.Upx = false - } - - switch buildOptions.Platform { - case "linux": - if runtime.GOOS != "linux" { - pterm.Warning.Println("Crosscompiling to Linux not currently supported.") - return - } - case "darwin": - if runtime.GOOS != "darwin" { - pterm.Warning.Println("Crosscompiling to Mac not currently supported.") - return - } - macTargets := targets.Filter(func(platform string) bool { - return strings.HasPrefix(platform, "darwin") - }) - if macTargets.Length() == 2 { - buildOptions.BundleName = fmt.Sprintf("%s-%s.app", desiredFilename, buildOptions.Arch) - } - } - - if targets.Length() > 1 { - // target filename - switch buildOptions.Platform { - case "windows": - desiredFilename = fmt.Sprintf("%s-%s", desiredFilename, buildOptions.Arch) - case "linux", "darwin": - desiredFilename = fmt.Sprintf("%s-%s-%s", desiredFilename, buildOptions.Platform, buildOptions.Arch) - } - } - if buildOptions.Platform == "windows" { - desiredFilename += ".exe" - } - buildOptions.OutputFile = desiredFilename - - if f.OutputFilename != "" { - buildOptions.OutputFile = f.OutputFilename - } - - if f.Obfuscated && f.SkipBindings { - pterm.Warning.Println("obfuscated flag overrides skipbindings flag.") - buildOptions.SkipBindings = false - } - - if !f.DryRun { - // Start Time - start := time.Now() - - compiledBinary, err := build.Build(buildOptions) - if err != nil { - pterm.Error.Println(err.Error()) - targetErr = err - return - } - - buildOptions.IgnoreFrontend = true - buildOptions.CleanBinDirectory = false - - // Output stats - buildOptions.Logger.Println(fmt.Sprintf("Built '%s' in %s.\n", compiledBinary, time.Since(start).Round(time.Millisecond).String())) - - outputBinaries[buildOptions.Platform+"/"+buildOptions.Arch] = compiledBinary - } else { - pterm.Info.Println("Dry run: skipped build.") - } - }) - - if targetErr != nil { - return targetErr - } - - if f.DryRun { - return nil - } - - if f.NSIS { - amd64Binary := outputBinaries["windows/amd64"] - arm64Binary := outputBinaries["windows/arm64"] - if amd64Binary == "" && arm64Binary == "" { - return fmt.Errorf("cannot build nsis installer - no windows targets") - } - - if err := build.GenerateNSISInstaller(buildOptions, amd64Binary, arm64Binary); err != nil { - return err - } - } - - return nil -} diff --git a/v2/cmd/wails/dev.go b/v2/cmd/wails/dev.go deleted file mode 100644 index 30213a68e..000000000 --- a/v2/cmd/wails/dev.go +++ /dev/null @@ -1,37 +0,0 @@ -package main - -import ( - "os" - - "github.com/pterm/pterm" - "github.com/wailsapp/wails/v2/cmd/wails/flags" - "github.com/wailsapp/wails/v2/cmd/wails/internal/dev" - "github.com/wailsapp/wails/v2/internal/colour" - "github.com/wailsapp/wails/v2/pkg/clilogger" -) - -func devApplication(f *flags.Dev) error { - if f.NoColour { - pterm.DisableColor() - colour.ColourEnabled = false - } - - quiet := f.Verbosity == flags.Quiet - - // Create logger - logger := clilogger.New(os.Stdout) - logger.Mute(quiet) - - if quiet { - pterm.DisableOutput() - } else { - app.PrintBanner() - } - - err := f.Process() - if err != nil { - return err - } - - return dev.Application(f, logger) -} diff --git a/v2/cmd/wails/doctor.go b/v2/cmd/wails/doctor.go deleted file mode 100644 index 7f453133d..000000000 --- a/v2/cmd/wails/doctor.go +++ /dev/null @@ -1,262 +0,0 @@ -package main - -import ( - "fmt" - "runtime" - "runtime/debug" - "strconv" - "strings" - - "github.com/wailsapp/wails/v2/internal/shell" - - "github.com/pterm/pterm" - - "github.com/jaypipes/ghw" - "github.com/wailsapp/wails/v2/cmd/wails/flags" - "github.com/wailsapp/wails/v2/internal/colour" - "github.com/wailsapp/wails/v2/internal/system" - "github.com/wailsapp/wails/v2/internal/system/packagemanager" -) - -func diagnoseEnvironment(f *flags.Doctor) error { - if f.NoColour { - pterm.DisableColor() - colour.ColourEnabled = false - } - - pterm.DefaultSection = *pterm.DefaultSection. - WithBottomPadding(0). - WithStyle(pterm.NewStyle(pterm.FgBlue, pterm.Bold)) - - pterm.Println() // Spacer - pterm.DefaultHeader.WithBackgroundStyle(pterm.NewStyle(pterm.BgLightBlue)).WithMargin(10).Println("Wails Doctor") - pterm.Println() // Spacer - - spinner, _ := pterm.DefaultSpinner.WithRemoveWhenDone().Start("Scanning system - Please wait (this may take a long time)...") - - // Get system info - info, err := system.GetInfo() - if err != nil { - spinner.Fail() - pterm.Error.Println("Failed to get system information") - return err - } - spinner.Success() - - pterm.DefaultSection.Println("Wails") - - wailsTableData := pterm.TableData{ - {"Version", app.Version()}, - } - - if buildInfo, _ := debug.ReadBuildInfo(); buildInfo != nil { - buildSettingToName := map[string]string{ - "vcs.revision": "Revision", - "vcs.modified": "Modified", - } - for _, buildSetting := range buildInfo.Settings { - name := buildSettingToName[buildSetting.Key] - if name == "" { - continue - } - wailsTableData = append(wailsTableData, []string{name, buildSetting.Value}) - } - } - - // Exit early if PM not found - if info.PM != nil { - wailsTableData = append(wailsTableData, []string{"Package Manager", info.PM.Name()}) - } - - err = pterm.DefaultTable.WithData(wailsTableData).Render() - if err != nil { - return err - } - - pterm.DefaultSection.Println("System") - - systemTabledata := pterm.TableData{ - {pterm.Bold.Sprint("OS"), info.OS.Name}, - {pterm.Bold.Sprint("Version"), info.OS.Version}, - {pterm.Bold.Sprint("ID"), info.OS.ID}, - {pterm.Bold.Sprint("Branding"), info.OS.Branding}, - {pterm.Bold.Sprint("Go Version"), runtime.Version()}, - {pterm.Bold.Sprint("Platform"), runtime.GOOS}, - {pterm.Bold.Sprint("Architecture"), runtime.GOARCH}, - } - - // Probe CPU - cpus, _ := ghw.CPU() - if cpus != nil { - prefix := "CPU" - for idx, cpu := range cpus.Processors { - if len(cpus.Processors) > 1 { - prefix = "CPU " + strconv.Itoa(idx+1) - } - systemTabledata = append(systemTabledata, []string{prefix, cpu.Model}) - } - } else { - cpuInfo := "Unknown" - if runtime.GOOS == "darwin" { - // Try to get CPU info from sysctl - if stdout, _, err := shell.RunCommand("", "sysctl", "-n", "machdep.cpu.brand_string"); err == nil { - cpuInfo = strings.TrimSpace(stdout) - } - } - systemTabledata = append(systemTabledata, []string{"CPU", cpuInfo}) - } - - // Probe GPU - gpu, _ := ghw.GPU(ghw.WithDisableWarnings()) - if gpu != nil { - prefix := "GPU" - for idx, card := range gpu.GraphicsCards { - if len(gpu.GraphicsCards) > 1 { - prefix = "GPU " + strconv.Itoa(idx+1) + " " - } - if card.DeviceInfo == nil { - systemTabledata = append(systemTabledata, []string{prefix, "Unknown"}) - continue - } - details := fmt.Sprintf("%s (%s) - Driver: %s", card.DeviceInfo.Product.Name, card.DeviceInfo.Vendor.Name, card.DeviceInfo.Driver) - systemTabledata = append(systemTabledata, []string{prefix, details}) - } - } else { - gpuInfo := "Unknown" - if runtime.GOOS == "darwin" { - // Try to get GPU info from system_profiler - if stdout, _, err := shell.RunCommand("", "system_profiler", "SPDisplaysDataType"); err == nil { - var ( - startCapturing bool - gpuInfoDetails []string - ) - for _, line := range strings.Split(stdout, "\n") { - if strings.Contains(line, "Chipset Model") { - startCapturing = true - } - if startCapturing { - gpuInfoDetails = append(gpuInfoDetails, strings.TrimSpace(line)) - } - if strings.Contains(line, "Metal Support") { - break - } - } - if len(gpuInfoDetails) > 0 { - gpuInfo = strings.Join(gpuInfoDetails, " ") - } - } - } - systemTabledata = append(systemTabledata, []string{"GPU", gpuInfo}) - } - - memory, _ := ghw.Memory() - if memory != nil { - systemTabledata = append(systemTabledata, []string{"Memory", strconv.Itoa(int(memory.TotalPhysicalBytes/1024/1024/1024)) + "GB"}) - } else { - memInfo := "Unknown" - if runtime.GOOS == "darwin" { - // Try to get Memory info from sysctl - if stdout, _, err := shell.RunCommand("", "sysctl", "-n", "hw.memsize"); err == nil { - if memSize, err := strconv.Atoi(strings.TrimSpace(stdout)); err == nil { - memInfo = strconv.Itoa(memSize/1024/1024/1024) + "GB" - } - } - } - systemTabledata = append(systemTabledata, []string{"Memory", memInfo}) - } - - err = pterm.DefaultTable.WithBoxed().WithData(systemTabledata).Render() - if err != nil { - return err - } - - pterm.DefaultSection.Println("Dependencies") - - // Output Dependencies Status - var dependenciesMissing []string - var externalPackages []*packagemanager.Dependency - dependenciesAvailableRequired := 0 - dependenciesAvailableOptional := 0 - - dependenciesTableData := pterm.TableData{ - {"Dependency", "Package Name", "Status", "Version"}, - } - - hasOptionalDependencies := false - // Loop over dependencies - for _, dependency := range info.Dependencies { - name := dependency.Name - - if dependency.Optional { - name = pterm.Gray("*") + name - hasOptionalDependencies = true - } - - packageName := "Unknown" - status := pterm.LightRed("Not Found") - - // If we found the package - if dependency.PackageName != "" { - packageName = dependency.PackageName - - // If it's installed, update the status - if dependency.Installed { - status = pterm.LightGreen("Installed") - } else { - // Generate meaningful status text - status = pterm.LightMagenta("Available") - - if dependency.Optional { - dependenciesAvailableOptional++ - } else { - dependenciesAvailableRequired++ - } - } - } else { - if !dependency.Optional { - dependenciesMissing = append(dependenciesMissing, dependency.Name) - } - - if dependency.External { - externalPackages = append(externalPackages, dependency) - } - } - - dependenciesTableData = append(dependenciesTableData, []string{name, packageName, status, dependency.Version}) - } - - dependenciesTableString, _ := pterm.DefaultTable.WithHasHeader(true).WithData(dependenciesTableData).Srender() - dependenciesBox := pterm.DefaultBox.WithTitleBottomCenter() - - if hasOptionalDependencies { - dependenciesBox = dependenciesBox.WithTitle(pterm.Gray("*") + " - Optional Dependency") - } - - dependenciesBox.Println(dependenciesTableString) - - pterm.DefaultSection.Println("Diagnosis") - - // Generate an appropriate diagnosis - - if dependenciesAvailableRequired != 0 { - pterm.Println("Required package(s) installation details: \n" + info.Dependencies.InstallAllRequiredCommand()) - } - - if dependenciesAvailableOptional != 0 { - pterm.Println("Optional package(s) installation details: \n" + info.Dependencies.InstallAllOptionalCommand()) - } - - if len(dependenciesMissing) == 0 && dependenciesAvailableRequired == 0 { - pterm.Success.Println("Your system is ready for Wails development!") - } else { - pterm.Warning.Println("Your system has missing dependencies!") - } - - if len(dependenciesMissing) != 0 { - pterm.Println("Fatal:") - pterm.Println("Required dependencies missing: " + strings.Join(dependenciesMissing, " ")) - } - - pterm.Println() // Spacer for sponsor message - return nil -} diff --git a/v2/cmd/wails/flags/build.go b/v2/cmd/wails/flags/build.go deleted file mode 100644 index db05c9035..000000000 --- a/v2/cmd/wails/flags/build.go +++ /dev/null @@ -1,166 +0,0 @@ -package flags - -import ( - "fmt" - "os" - "os/exec" - "runtime" - "strings" - - "github.com/leaanthony/slicer" - "github.com/wailsapp/wails/v2/internal/system" - "github.com/wailsapp/wails/v2/pkg/commands/build" - "github.com/wailsapp/wails/v2/pkg/commands/buildtags" -) - -const ( - Quiet int = 0 - Normal int = 1 - Verbose int = 2 -) - -// TODO: unify this and `build.Options` -type Build struct { - Common - BuildCommon - - NoPackage bool `description:"Skips platform specific packaging"` - Upx bool `description:"Compress final binary with UPX (if installed)"` - UpxFlags string `description:"Flags to pass to upx"` - Platform string `description:"Platform to target. Comma separate multiple platforms"` - OutputFilename string `name:"o" description:"Output filename"` - Clean bool `description:"Clean the bin directory before building"` - WebView2 string `description:"WebView2 installer strategy: download,embed,browser,error"` - ForceBuild bool `name:"f" description:"Force build of application"` - UpdateWailsVersionGoMod bool `name:"u" description:"Updates go.mod to use the same Wails version as the CLI"` - Debug bool `description:"Builds the application in debug mode"` - Devtools bool `description:"Enable Devtools in productions, Already enabled in debug mode (-debug)"` - NSIS bool `description:"Generate NSIS installer for Windows"` - TrimPath bool `description:"Remove all file system paths from the resulting executable"` - WindowsConsole bool `description:"Keep the console when building for Windows"` - Obfuscated bool `description:"Code obfuscation of bound Wails methods"` - GarbleArgs string `description:"Arguments to pass to garble"` - DryRun bool `description:"Prints the build command without executing it"` - - // Build Specific - - // Internal state - compilerPath string - userTags []string - wv2rtstrategy string // WebView2 runtime strategy - defaultArch string // Default architecture -} - -func (b *Build) Default() *Build { - defaultPlatform := os.Getenv("GOOS") - if defaultPlatform == "" { - defaultPlatform = runtime.GOOS - } - defaultArch := os.Getenv("GOARCH") - if defaultArch == "" { - if system.IsAppleSilicon { - defaultArch = "arm64" - } else { - defaultArch = runtime.GOARCH - } - } - - result := &Build{ - Platform: defaultPlatform + "/" + defaultArch, - WebView2: "download", - GarbleArgs: "-literals -tiny -seed=random", - - defaultArch: defaultArch, - } - result.BuildCommon = result.BuildCommon.Default() - return result -} - -func (b *Build) GetBuildMode() build.Mode { - if b.Debug { - return build.Debug - } - return build.Production -} - -func (b *Build) GetWebView2Strategy() string { - return b.wv2rtstrategy -} - -func (b *Build) GetTargets() *slicer.StringSlicer { - var targets slicer.StringSlicer - targets.AddSlice(strings.Split(b.Platform, ",")) - targets.Deduplicate() - return &targets -} - -func (b *Build) GetCompilerPath() string { - return b.compilerPath -} - -func (b *Build) GetTags() []string { - return b.userTags -} - -func (b *Build) Process() error { - // Lookup compiler path - var err error - b.compilerPath, err = exec.LookPath(b.Compiler) - if err != nil { - return fmt.Errorf("unable to find compiler: %s", b.Compiler) - } - - // Process User Tags - b.userTags, err = buildtags.Parse(b.Tags) - if err != nil { - return err - } - - // WebView2 installer strategy (download by default) - b.WebView2 = strings.ToLower(b.WebView2) - if b.WebView2 != "" { - validWV2Runtime := slicer.String([]string{"download", "embed", "browser", "error"}) - if !validWV2Runtime.Contains(b.WebView2) { - return fmt.Errorf("invalid option for flag 'webview2': %s", b.WebView2) - } - b.wv2rtstrategy = "wv2runtime." + b.WebView2 - } - - return nil -} - -func bool2Str(b bool) string { - if b { - return "true" - } - return "false" -} - -func (b *Build) GetBuildModeAsString() string { - if b.Debug { - return "debug" - } - return "production" -} - -func (b *Build) GetDefaultArch() string { - return b.defaultArch -} - -/* - _, _ = fmt.Fprintf(w, "Frontend Directory: \t%s\n", projectOptions.GetFrontendDir()) - _, _ = fmt.Fprintf(w, "Obfuscated: \t%t\n", buildOptions.Obfuscated) - if buildOptions.Obfuscated { - _, _ = fmt.Fprintf(w, "Garble Args: \t%s\n", buildOptions.GarbleArgs) - } - _, _ = fmt.Fprintf(w, "Skip Frontend: \t%t\n", skipFrontend) - _, _ = fmt.Fprintf(w, "Compress: \t%t\n", buildOptions.Compress) - _, _ = fmt.Fprintf(w, "Package: \t%t\n", buildOptions.Pack) - _, _ = fmt.Fprintf(w, "Clean Bin Dir: \t%t\n", buildOptions.CleanBinDirectory) - _, _ = fmt.Fprintf(w, "LDFlags: \t\"%s\"\n", buildOptions.LDFlags) - _, _ = fmt.Fprintf(w, "Tags: \t[%s]\n", strings.Join(buildOptions.UserTags, ",")) - _, _ = fmt.Fprintf(w, "Race Detector: \t%t\n", buildOptions.RaceDetector) - if len(buildOptions.OutputFile) > 0 && targets.Length() == 1 { - _, _ = fmt.Fprintf(w, "Output File: \t%s\n", buildOptions.OutputFile) - } -*/ diff --git a/v2/cmd/wails/flags/buildcommon.go b/v2/cmd/wails/flags/buildcommon.go deleted file mode 100644 index a22f7a502..000000000 --- a/v2/cmd/wails/flags/buildcommon.go +++ /dev/null @@ -1,21 +0,0 @@ -package flags - -type BuildCommon struct { - LdFlags string `description:"Additional ldflags to pass to the compiler"` - Compiler string `description:"Use a different go compiler to build, eg go1.15beta1"` - SkipBindings bool `description:"Skips generation of bindings"` - RaceDetector bool `name:"race" description:"Build with Go's race detector"` - SkipFrontend bool `name:"s" description:"Skips building the frontend"` - Verbosity int `name:"v" description:"Verbosity level (0 = quiet, 1 = normal, 2 = verbose)"` - Tags string `description:"Build tags to pass to Go compiler. Must be quoted. Space or comma (but not both) separated"` - NoSyncGoMod bool `description:"Don't sync go.mod"` - SkipModTidy bool `name:"m" description:"Skip mod tidy before compile"` - SkipEmbedCreate bool `description:"Skips creation of embed files"` -} - -func (c BuildCommon) Default() BuildCommon { - return BuildCommon{ - Compiler: "go", - Verbosity: 1, - } -} diff --git a/v2/cmd/wails/flags/common.go b/v2/cmd/wails/flags/common.go deleted file mode 100644 index e58eff411..000000000 --- a/v2/cmd/wails/flags/common.go +++ /dev/null @@ -1,5 +0,0 @@ -package flags - -type Common struct { - NoColour bool `description:"Disable colour in output"` -} diff --git a/v2/cmd/wails/flags/dev.go b/v2/cmd/wails/flags/dev.go deleted file mode 100644 index d31d8bc87..000000000 --- a/v2/cmd/wails/flags/dev.go +++ /dev/null @@ -1,157 +0,0 @@ -package flags - -import ( - "fmt" - "net" - "net/url" - "os" - "path/filepath" - "runtime" - - "github.com/samber/lo" - "github.com/wailsapp/wails/v2/internal/project" - "github.com/wailsapp/wails/v2/pkg/commands/build" -) - -type Dev struct { - BuildCommon - - AssetDir string `flag:"assetdir" description:"Serve assets from the given directory instead of using the provided asset FS"` - Extensions string `flag:"e" description:"Extensions to trigger rebuilds (comma separated) eg go"` - ReloadDirs string `flag:"reloaddirs" description:"Additional directories to trigger reloads (comma separated)"` - Browser bool `flag:"browser" description:"Open the application in a browser"` - NoReload bool `flag:"noreload" description:"Disable reload on asset change"` - NoColour bool `flag:"nocolor" description:"Disable colour in output"` - NoGoRebuild bool `flag:"nogorebuild" description:"Disable automatic rebuilding on backend file changes/additions"` - WailsJSDir string `flag:"wailsjsdir" description:"Directory to generate the Wails JS modules"` - LogLevel string `flag:"loglevel" description:"LogLevel to use - Trace, Debug, Info, Warning, Error)"` - ForceBuild bool `flag:"f" description:"Force build of application"` - Debounce int `flag:"debounce" description:"The amount of time to wait to trigger a reload on change"` - DevServer string `flag:"devserver" description:"The address of the wails dev server"` - AppArgs string `flag:"appargs" description:"arguments to pass to the underlying app (quoted and space separated)"` - Save bool `flag:"save" description:"Save the given flags as defaults"` - FrontendDevServerURL string `flag:"frontenddevserverurl" description:"The url of the external frontend dev server to use"` - ViteServerTimeout int `flag:"viteservertimeout" description:"The timeout in seconds for Vite server detection (default: 10)"` - - // Internal state - devServerURL *url.URL - projectConfig *project.Project -} - -func (*Dev) Default() *Dev { - result := &Dev{ - Extensions: "go", - Debounce: 100, - LogLevel: "Info", - } - result.BuildCommon = result.BuildCommon.Default() - return result -} - -func (d *Dev) Process() error { - var err error - err = d.loadAndMergeProjectConfig() - if err != nil { - return err - } - - if _, _, err := net.SplitHostPort(d.DevServer); err != nil { - return fmt.Errorf("DevServer is not of the form 'host:port', please check your wails.json") - } - - d.devServerURL, err = url.Parse("http://" + d.DevServer) - if err != nil { - return err - } - - return nil -} - -func (d *Dev) loadAndMergeProjectConfig() error { - var err error - cwd, err := os.Getwd() - if err != nil { - return err - } - d.projectConfig, err = project.Load(cwd) - if err != nil { - return err - } - - d.AssetDir, _ = lo.Coalesce(d.AssetDir, d.projectConfig.AssetDirectory) - d.projectConfig.AssetDirectory = filepath.ToSlash(d.AssetDir) - if d.AssetDir != "" { - d.AssetDir, err = filepath.Abs(d.AssetDir) - if err != nil { - return err - } - } - - d.ReloadDirs, _ = lo.Coalesce(d.ReloadDirs, d.projectConfig.ReloadDirectories) - d.projectConfig.ReloadDirectories = filepath.ToSlash(d.ReloadDirs) - d.DevServer, _ = lo.Coalesce(d.DevServer, d.projectConfig.DevServer) - d.projectConfig.DevServer = d.DevServer - d.FrontendDevServerURL, _ = lo.Coalesce(d.FrontendDevServerURL, d.projectConfig.FrontendDevServerURL) - d.projectConfig.FrontendDevServerURL = d.FrontendDevServerURL - d.WailsJSDir, _ = lo.Coalesce(d.WailsJSDir, d.projectConfig.GetWailsJSDir(), d.projectConfig.GetFrontendDir()) - d.projectConfig.WailsJSDir = filepath.ToSlash(d.WailsJSDir) - - if d.Debounce == 100 && d.projectConfig.DebounceMS != 100 { - if d.projectConfig.DebounceMS == 0 { - d.projectConfig.DebounceMS = 100 - } - d.Debounce = d.projectConfig.DebounceMS - } - d.projectConfig.DebounceMS = d.Debounce - - d.AppArgs, _ = lo.Coalesce(d.AppArgs, d.projectConfig.AppArgs) - - if d.ViteServerTimeout == 0 && d.projectConfig.ViteServerTimeout != 0 { - d.ViteServerTimeout = d.projectConfig.ViteServerTimeout - } else if d.ViteServerTimeout == 0 { - d.ViteServerTimeout = 10 // Default timeout - } - d.projectConfig.ViteServerTimeout = d.ViteServerTimeout - - if d.Save { - err = d.projectConfig.Save() - if err != nil { - return err - } - } - - return nil -} - -// GenerateBuildOptions creates a build.Options using the flags -func (d *Dev) GenerateBuildOptions() *build.Options { - result := &build.Options{ - OutputType: "dev", - Mode: build.Dev, - Devtools: true, - Arch: runtime.GOARCH, - Pack: true, - Platform: runtime.GOOS, - LDFlags: d.LdFlags, - Compiler: d.Compiler, - ForceBuild: d.ForceBuild, - IgnoreFrontend: d.SkipFrontend, - SkipBindings: d.SkipBindings, - SkipModTidy: d.SkipModTidy, - Verbosity: d.Verbosity, - WailsJSDir: d.WailsJSDir, - RaceDetector: d.RaceDetector, - ProjectData: d.projectConfig, - SkipEmbedCreate: d.SkipEmbedCreate, - } - - return result -} - -func (d *Dev) ProjectConfig() *project.Project { - return d.projectConfig -} - -func (d *Dev) DevServerURL() *url.URL { - return d.devServerURL -} diff --git a/v2/cmd/wails/flags/doctor.go b/v2/cmd/wails/flags/doctor.go deleted file mode 100644 index e4816b969..000000000 --- a/v2/cmd/wails/flags/doctor.go +++ /dev/null @@ -1,9 +0,0 @@ -package flags - -type Doctor struct { - Common -} - -func (b *Doctor) Default() *Doctor { - return &Doctor{} -} diff --git a/v2/cmd/wails/flags/generate.go b/v2/cmd/wails/flags/generate.go deleted file mode 100644 index b14d67017..000000000 --- a/v2/cmd/wails/flags/generate.go +++ /dev/null @@ -1,21 +0,0 @@ -package flags - -type GenerateModule struct { - Common - Compiler string `description:"Use a different go compiler to build, eg go1.15beta1"` - Tags string `description:"Build tags to pass to Go compiler. Must be quoted. Space or comma (but not both) separated"` - Verbosity int `name:"v" description:"Verbosity level (0 = quiet, 1 = normal, 2 = verbose)"` -} - -type GenerateTemplate struct { - Common - Name string `description:"Name of the template to generate"` - Frontend string `description:"Frontend to use for the template"` - Quiet bool `description:"Suppress output"` -} - -func (c *GenerateModule) Default() *GenerateModule { - return &GenerateModule{ - Compiler: "go", - } -} diff --git a/v2/cmd/wails/flags/init.go b/v2/cmd/wails/flags/init.go deleted file mode 100644 index 16d56a207..000000000 --- a/v2/cmd/wails/flags/init.go +++ /dev/null @@ -1,21 +0,0 @@ -package flags - -type Init struct { - Common - - TemplateName string `name:"t" description:"Name of built-in template to use, path to template or template url"` - ProjectName string `name:"n" description:"Name of project"` - CIMode bool `name:"ci" description:"CI Mode"` - ProjectDir string `name:"d" description:"Project directory"` - Quiet bool `name:"q" description:"Suppress output to console"` - InitGit bool `name:"g" description:"Initialise git repository"` - IDE string `name:"ide" description:"Generate IDE project files"` - List bool `name:"l" description:"List templates"` -} - -func (i *Init) Default() *Init { - result := &Init{ - TemplateName: "vanilla", - } - return result -} diff --git a/v2/cmd/wails/flags/show.go b/v2/cmd/wails/flags/show.go deleted file mode 100644 index a8220f3cc..000000000 --- a/v2/cmd/wails/flags/show.go +++ /dev/null @@ -1,6 +0,0 @@ -package flags - -type ShowReleaseNotes struct { - Common - Version string `description:"The version to show the release notes for"` -} diff --git a/v2/cmd/wails/flags/update.go b/v2/cmd/wails/flags/update.go deleted file mode 100644 index ffd143a9f..000000000 --- a/v2/cmd/wails/flags/update.go +++ /dev/null @@ -1,7 +0,0 @@ -package flags - -type Update struct { - Common - Version string `description:"The version to update to"` - PreRelease bool `name:"pre" description:"Update to latest pre-release"` -} diff --git a/v2/cmd/wails/generate.go b/v2/cmd/wails/generate.go deleted file mode 100644 index 15a6b33d8..000000000 --- a/v2/cmd/wails/generate.go +++ /dev/null @@ -1,250 +0,0 @@ -package main - -import ( - "fmt" - "os" - "path/filepath" - - "github.com/leaanthony/debme" - "github.com/leaanthony/gosod" - "github.com/pterm/pterm" - "github.com/tidwall/sjson" - "github.com/wailsapp/wails/v2/cmd/wails/flags" - "github.com/wailsapp/wails/v2/cmd/wails/internal/template" - "github.com/wailsapp/wails/v2/internal/colour" - "github.com/wailsapp/wails/v2/internal/fs" - "github.com/wailsapp/wails/v2/internal/project" - "github.com/wailsapp/wails/v2/pkg/clilogger" - "github.com/wailsapp/wails/v2/pkg/commands/bindings" - "github.com/wailsapp/wails/v2/pkg/commands/buildtags" -) - -func generateModule(f *flags.GenerateModule) error { - if f.NoColour { - pterm.DisableColor() - colour.ColourEnabled = false - } - - quiet := f.Verbosity == flags.Quiet - logger := clilogger.New(os.Stdout) - logger.Mute(quiet) - - buildTags, err := buildtags.Parse(f.Tags) - if err != nil { - return err - } - - cwd, err := os.Getwd() - if err != nil { - return err - } - projectConfig, err := project.Load(cwd) - if err != nil { - return err - } - - if projectConfig.Bindings.TsGeneration.OutputType == "" { - projectConfig.Bindings.TsGeneration.OutputType = "classes" - } - - _, err = bindings.GenerateBindings(bindings.Options{ - Compiler: f.Compiler, - Tags: buildTags, - TsPrefix: projectConfig.Bindings.TsGeneration.Prefix, - TsSuffix: projectConfig.Bindings.TsGeneration.Suffix, - TsOutputType: projectConfig.Bindings.TsGeneration.OutputType, - }) - if err != nil { - return err - } - return nil -} - -func generateTemplate(f *flags.GenerateTemplate) error { - if f.NoColour { - pterm.DisableColor() - colour.ColourEnabled = false - } - - quiet := f.Quiet - logger := clilogger.New(os.Stdout) - logger.Mute(quiet) - - // name is mandatory - if f.Name == "" { - return fmt.Errorf("please provide a template name using the -name flag") - } - - // If the current directory is not empty, we create a new directory - cwd, err := os.Getwd() - if err != nil { - return err - } - templateDir := filepath.Join(cwd, f.Name) - if !fs.DirExists(templateDir) { - err := os.MkdirAll(templateDir, 0o755) - if err != nil { - return err - } - } - empty, err := fs.DirIsEmpty(templateDir) - if err != nil { - return err - } - - pterm.DefaultSection.Println("Generating template") - - if !empty { - templateDir = filepath.Join(cwd, f.Name) - printBulletPoint("Creating new template directory:", f.Name) - err = fs.Mkdir(templateDir) - if err != nil { - return err - } - } - - // Create base template - baseTemplate, err := debme.FS(template.Base, "base") - if err != nil { - return err - } - g := gosod.New(baseTemplate) - g.SetTemplateFilters([]string{".template"}) - - err = os.Chdir(templateDir) - if err != nil { - return err - } - - type templateData struct { - Name string - Description string - TemplateDir string - WailsVersion string - } - - printBulletPoint("Extracting base template files...") - - err = g.Extract(templateDir, &templateData{ - Name: f.Name, - TemplateDir: templateDir, - WailsVersion: app.Version(), - }) - if err != nil { - return err - } - - err = os.Chdir(cwd) - if err != nil { - return err - } - - // If we aren't migrating the files, just exit - if f.Frontend == "" { - pterm.Println() - pterm.Println() - pterm.Info.Println("No frontend specified to migrate. Template created.") - pterm.Println() - return nil - } - - // Remove frontend directory - frontendDir := filepath.Join(templateDir, "frontend") - err = os.RemoveAll(frontendDir) - if err != nil { - return err - } - - // Copy the files into a new frontend directory - printBulletPoint("Migrating existing project files to frontend directory...") - - sourceDir, err := filepath.Abs(f.Frontend) - if err != nil { - return err - } - - newFrontendDir := filepath.Join(templateDir, "frontend") - err = fs.CopyDirExtended(sourceDir, newFrontendDir, []string{f.Name, "node_modules"}) - if err != nil { - return err - } - - // Process package.json - err = processPackageJSON(frontendDir) - if err != nil { - return err - } - - // Process package-lock.json - err = processPackageLockJSON(frontendDir) - if err != nil { - return err - } - - // Remove node_modules - ignore error, eg it doesn't exist - _ = os.RemoveAll(filepath.Join(frontendDir, "node_modules")) - - return nil -} - -func processPackageJSON(frontendDir string) error { - var err error - - packageJSON := filepath.Join(frontendDir, "package.json") - if !fs.FileExists(packageJSON) { - return fmt.Errorf("no package.json found - cannot process") - } - - json, err := os.ReadFile(packageJSON) - if err != nil { - return err - } - - // We will ignore these errors - it's not critical - printBulletPoint("Updating package.json data...") - json, _ = sjson.SetBytes(json, "name", "{{.ProjectName}}") - json, _ = sjson.SetBytes(json, "author", "{{.AuthorName}}") - - err = os.WriteFile(packageJSON, json, 0o644) - if err != nil { - return err - } - baseDir := filepath.Dir(packageJSON) - printBulletPoint("Renaming package.json -> package.tmpl.json...") - err = os.Rename(packageJSON, filepath.Join(baseDir, "package.tmpl.json")) - if err != nil { - return err - } - return nil -} - -func processPackageLockJSON(frontendDir string) error { - var err error - - filename := filepath.Join(frontendDir, "package-lock.json") - if !fs.FileExists(filename) { - return fmt.Errorf("no package-lock.json found - cannot process") - } - - data, err := os.ReadFile(filename) - if err != nil { - return err - } - json := string(data) - - // We will ignore these errors - it's not critical - printBulletPoint("Updating package-lock.json data...") - json, _ = sjson.Set(json, "name", "{{.ProjectName}}") - - err = os.WriteFile(filename, []byte(json), 0o644) - if err != nil { - return err - } - baseDir := filepath.Dir(filename) - printBulletPoint("Renaming package-lock.json -> package-lock.tmpl.json...") - err = os.Rename(filename, filepath.Join(baseDir, "package-lock.tmpl.json")) - if err != nil { - return err - } - return nil -} diff --git a/v2/cmd/wails/init.go b/v2/cmd/wails/init.go deleted file mode 100644 index f79e37ffc..000000000 --- a/v2/cmd/wails/init.go +++ /dev/null @@ -1,295 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "os" - "os/exec" - "path/filepath" - "strings" - "time" - - "github.com/flytam/filenamify" - "github.com/leaanthony/slicer" - "github.com/pkg/errors" - "github.com/pterm/pterm" - "github.com/wailsapp/wails/v2/cmd/wails/flags" - "github.com/wailsapp/wails/v2/internal/colour" - "github.com/wailsapp/wails/v2/pkg/buildassets" - "github.com/wailsapp/wails/v2/pkg/clilogger" - "github.com/wailsapp/wails/v2/pkg/git" - "github.com/wailsapp/wails/v2/pkg/templates" -) - -func initProject(f *flags.Init) error { - if f.NoColour { - pterm.DisableColor() - colour.ColourEnabled = false - } - - quiet := f.Quiet - - // Create logger - logger := clilogger.New(os.Stdout) - logger.Mute(quiet) - - // Are we listing templates? - if f.List { - app.PrintBanner() - templateList, err := templates.List() - if err != nil { - return err - } - - pterm.DefaultSection.Println("Available templates") - - table := pterm.TableData{{"Template", "Short Name", "Description"}} - for _, template := range templateList { - table = append(table, []string{template.Name, template.ShortName, template.Description}) - } - err = pterm.DefaultTable.WithHasHeader(true).WithBoxed(true).WithData(table).Render() - pterm.Println() - return err - } - - // Validate name - if len(f.ProjectName) == 0 { - return fmt.Errorf("please provide a project name using the -n flag") - } - - // Validate IDE option - supportedIDEs := slicer.String([]string{"vscode", "goland"}) - ide := strings.ToLower(f.IDE) - if ide != "" { - if !supportedIDEs.Contains(ide) { - return fmt.Errorf("ide '%s' not supported. Valid values: %s", ide, supportedIDEs.Join(" ")) - } - } - - if !quiet { - app.PrintBanner() - } - - pterm.DefaultSection.Printf("Initialising Project '%s'", f.ProjectName) - - projectFilename, err := filenamify.Filenamify(f.ProjectName, filenamify.Options{ - Replacement: "_", - MaxLength: 255, - }) - if err != nil { - return err - } - goBinary, err := exec.LookPath("go") - if err != nil { - return fmt.Errorf("unable to find Go compiler. Please download and install Go: https://golang.org/dl/") - } - - // Get base path and convert to forward slashes - goPath := filepath.ToSlash(filepath.Dir(goBinary)) - // Trim bin directory - goSDKPath := strings.TrimSuffix(goPath, "/bin") - - // Create Template Options - options := &templates.Options{ - ProjectName: f.ProjectName, - TargetDir: f.ProjectDir, - TemplateName: f.TemplateName, - Logger: logger, - IDE: ide, - InitGit: f.InitGit, - ProjectNameFilename: projectFilename, - WailsVersion: app.Version(), - GoSDKPath: goSDKPath, - } - - // Try to discover author details from git config - findAuthorDetails(options) - - // Start Time - start := time.Now() - - // Install the template - remote, template, err := templates.Install(options) - if err != nil { - return err - } - - // Install the default assets - err = buildassets.Install(options.TargetDir) - if err != nil { - return err - } - - err = os.Chdir(options.TargetDir) - if err != nil { - return err - } - - // Change the module name to project name - err = updateModuleNameToProjectName(options, quiet) - if err != nil { - return err - } - - if !f.CIMode { - // Run `go mod tidy` to ensure `go.sum` is up to date - cmd := exec.Command("go", "mod", "tidy") - cmd.Dir = options.TargetDir - cmd.Stderr = os.Stderr - if !quiet { - cmd.Stdout = os.Stdout - } - err = cmd.Run() - if err != nil { - return err - } - } else { - // Update go mod - workspace := os.Getenv("GITHUB_WORKSPACE") - pterm.Println("GitHub workspace:", workspace) - if workspace == "" { - os.Exit(1) - } - updateReplaceLine(workspace) - } - - // Remove the `.git`` directory in the template project - err = os.RemoveAll(".git") - if err != nil { - return err - } - - if options.InitGit { - err = initGit(options) - if err != nil { - return err - } - } - - if quiet { - return nil - } - - // Output stats - elapsed := time.Since(start) - - // Create pterm table - table := pterm.TableData{ - {"Project Name", options.ProjectName}, - {"Project Directory", options.TargetDir}, - {"Template", template.Name}, - {"Template Source", template.HelpURL}, - } - err = pterm.DefaultTable.WithData(table).Render() - if err != nil { - return err - } - - // IDE message - switch options.IDE { - case "vscode": - pterm.Println() - pterm.Info.Println("VSCode config files generated.") - case "goland": - pterm.Println() - pterm.Info.Println("Goland config files generated.") - } - - if options.InitGit { - pterm.Info.Println("Git repository initialised.") - } - - if remote { - pterm.Warning.Println("NOTE: You have created a project using a remote template. The Wails project takes no responsibility for 3rd party templates. Only use remote templates that you trust.") - } - - pterm.Println("") - pterm.Printf("Initialised project '%s' in %s.\n", options.ProjectName, elapsed.Round(time.Millisecond).String()) - pterm.Println("") - - return nil -} - -func initGit(options *templates.Options) error { - err := git.InitRepo(options.TargetDir) - if err != nil { - return errors.Wrap(err, "Unable to initialise git repository:") - } - - ignore := []string{ - "build/bin", - "frontend/dist", - "frontend/node_modules", - } - err = os.WriteFile(filepath.Join(options.TargetDir, ".gitignore"), []byte(strings.Join(ignore, "\n")), 0o644) - if err != nil { - return errors.Wrap(err, "Unable to create gitignore") - } - - return nil -} - -// findAuthorDetails tries to find the user's name and email -// from gitconfig. If it finds them, it stores them in the project options -func findAuthorDetails(options *templates.Options) { - if git.IsInstalled() { - name, err := git.Name() - if err == nil { - options.AuthorName = strings.TrimSpace(name) - } - - email, err := git.Email() - if err == nil { - options.AuthorEmail = strings.TrimSpace(email) - } - } -} - -func updateReplaceLine(targetPath string) { - file, err := os.Open("go.mod") - if err != nil { - fatal(err.Error()) - } - - var lines []string - scanner := bufio.NewScanner(file) - for scanner.Scan() { - lines = append(lines, scanner.Text()) - } - - err = file.Close() - if err != nil { - fatal(err.Error()) - } - - if err := scanner.Err(); err != nil { - fatal(err.Error()) - } - - for i, line := range lines { - println(line) - if strings.HasPrefix(line, "// replace") { - pterm.Println("Found replace line") - splitLine := strings.Split(line, " ") - splitLine[5] = targetPath + "/v2" - lines[i] = strings.Join(splitLine[1:], " ") - continue - } - } - - err = os.WriteFile("go.mod", []byte(strings.Join(lines, "\n")), 0o644) - if err != nil { - fatal(err.Error()) - } -} - -func updateModuleNameToProjectName(options *templates.Options, quiet bool) error { - cmd := exec.Command("go", "mod", "edit", "-module", options.ProjectName) - cmd.Dir = options.TargetDir - cmd.Stderr = os.Stderr - if !quiet { - cmd.Stdout = os.Stdout - } - - return cmd.Run() -} diff --git a/v2/cmd/wails/internal/commands/build/README.md b/v2/cmd/wails/internal/commands/build/README.md new file mode 100644 index 000000000..321445073 --- /dev/null +++ b/v2/cmd/wails/internal/commands/build/README.md @@ -0,0 +1,48 @@ +# Build + +The build command processes the Wails project and generates an application binary. + +## Usage + +`wails build ` + +### Flags + +| Flag | Details | Default | +| :------------- | :----------- | :------ | +| -clean | Clean the bin directory before building | | +| -compiler path/to/compiler | Use a different go compiler, eg go1.15beta1 | go | +| -ldflags "custom ld flags" | Use given ldflags | | +| -o path/to/binary | Compile to given path/filename | | +| -k | Keep generated assets | | +| -package | Create a platform specific package | | +| -production | Compile in production mode: -ldflags="-w -s" + "-h windows" on Windows | | +| -tags | Build tags to pass to Go compiler (quoted and space separated) | | +| -upx | Compress final binary with UPX (if installed) | | +| -upxflags "custom flags" | Flags to pass to upx | | +| -v int | Verbosity level (0 - silent, 1 - default, 2 - verbose) | 1 | +| -delve | If true, runs delve on the compiled binary | false | + +## The Build Process + +The build process is as follows: + + - The flags are processed, and an Options struct built containing the build context. + - The type of target is determined, and a custom build process is followed for target. + +### Desktop Target + + - The frontend dependencies are installed. The command is read from the project file `wails.json` under the key `frontend:install` and executed in the `frontend` directory. If this is not defined, it is ignored. + - The frontend is then built. This command is read from the project file `wails.json` under the key `frontend:install` and executed in the `frontend` directory. If this is not defined, it is ignored. + - The project directory is checked to see if the `build` directory exists. If not, it is created and default project assets are copied to it. + - An asset bundle is then created by reading the `html` key from `wails.json` and loading the referenced file. This is then parsed, looking for local Javascript and CSS references. Those files are in turn loaded into memory, converted to C data and saved into the asset bundle located at `build/assets.h`, which also includes the original HTML. + - The application icon is then processed: if there is no `build/appicon.png`, a default icon is copied. On Windows, an `app.ico` file is generated from this png. On Mac, `icons.icns` is generated. + - If there are icons in the `build/tray` directory, these are processed, converted to C data and saved as `build/trayicons.h`, ready for the compilation step. + - If there are icons in the `build/dialog` directory, these are processed, converted to C data and saved as `build/userdialogicons.h`, ready for the compilation step. + - If the `-package` flag is given for a Windows target, the Windows assets in the `build/windows` directory are processed: manifest + icons compiled to a `.syso` file (deleted after compilation). + - If we are building a universal binary for Mac, the application is compiled for both `arm64` and `amd64`. The `lipo` tool is then executed to create the universal binary. + - If we are not building a universal binary for Mac, the application is built using `go build`, using build tags to indicate type of application and build mode (debug/production). + - If the `-upx` flag was provided, `upx` is invoked to compress the binary. Custom flags may be provided using the `-upxflags` flag. + - If the `package` flag is given for a non Windows target, the application is bundled for the platform. On Mac, this creates a `.app` with the processed icons, the `Info.plist` in `build/darwin` and the compiled binary. + + diff --git a/v2/cmd/wails/internal/commands/build/build.go b/v2/cmd/wails/internal/commands/build/build.go new file mode 100644 index 000000000..a74ac497b --- /dev/null +++ b/v2/cmd/wails/internal/commands/build/build.go @@ -0,0 +1,230 @@ +package build + +import ( + "fmt" + "io" + "os" + "os/exec" + "runtime" + "strings" + "text/tabwriter" + "time" + + "github.com/wailsapp/wails/v2/internal/system" + + "github.com/leaanthony/clir" + "github.com/leaanthony/slicer" + "github.com/wailsapp/wails/v2/pkg/clilogger" + "github.com/wailsapp/wails/v2/pkg/commands/build" +) + +// AddBuildSubcommand adds the `build` command for the Wails application +func AddBuildSubcommand(app *clir.Cli, w io.Writer) { + + outputType := "desktop" + + validTargetTypes := slicer.String([]string{"desktop", "hybrid", "server"}) + + command := app.NewSubCommand("build", "Builds the application") + + // Setup noPackage flag + noPackage := false + command.BoolFlag("noPackage", "Skips platform specific packaging", &noPackage) + + compilerCommand := "go" + command.StringFlag("compiler", "Use a different go compiler to build, eg go1.15beta1", &compilerCommand) + + compress := false + command.BoolFlag("upx", "Compress final binary with UPX (if installed)", &compress) + + compressFlags := "" + command.StringFlag("upxflags", "Flags to pass to upx", &compressFlags) + + // Setup Platform flag + platform := runtime.GOOS + //command.StringFlag("platform", "Platform to target", &platform) + + // Verbosity + verbosity := 1 + command.IntFlag("v", "Verbosity level (0 - silent, 1 - default, 2 - verbose)", &verbosity) + + // ldflags to pass to `go` + ldflags := "" + command.StringFlag("ldflags", "optional ldflags", &ldflags) + + // tags to pass to `go` + tags := "" + command.StringFlag("tags", "tags to pass to Go compiler (quoted and space separated)", &tags) + + outputFilename := "" + command.StringFlag("o", "Output filename", &outputFilename) + + // Clean build directory + cleanBuildDirectory := false + command.BoolFlag("clean", "Clean the build directory before building", &cleanBuildDirectory) + + webview2 := "download" + command.StringFlag("webview2", "WebView2 installer strategy: download,embed,browser,error.", &webview2) + + skipFrontend := false + command.BoolFlag("s", "Skips building the frontend", &skipFrontend) + + forceBuild := false + command.BoolFlag("f", "Force build application", &forceBuild) + + command.Action(func() error { + + quiet := verbosity == 0 + + // Create logger + logger := clilogger.New(w) + logger.Mute(quiet) + + // Validate output type + if !validTargetTypes.Contains(outputType) { + return fmt.Errorf("output type '%s' is not valid", outputType) + } + + if !quiet { + app.PrintBanner() + } + + // Check platform + validPlatformArch := slicer.String([]string{ + "darwin", + "darwin/amd64", + "darwin/arm64", + "darwin/universal", + "linux", + //"linux/amd64", + //"linux/arm-7", + "windows", + "windows/amd64", + }) + if !validPlatformArch.Contains(platform) { + return fmt.Errorf("platform %s is not supported", platform) + } + + if compress && platform == "darwin/universal" { + logger.Println("Warning: compress flag unsupported for universal binaries. Ignoring.") + compress = false + } + + // Lookup compiler path + compilerPath, err := exec.LookPath(compilerCommand) + if err != nil { + return fmt.Errorf("unable to find compiler: %s", compilerCommand) + } + + // Tags + experimental := false + userTags := []string{} + for _, tag := range strings.Split(tags, " ") { + thisTag := strings.TrimSpace(tag) + if thisTag != "" { + userTags = append(userTags, thisTag) + } + if thisTag == "exp" { + experimental = true + } + } + + if runtime.GOOS == "darwin" && !experimental { + return fmt.Errorf("MacOS version coming soon!") + } + + // Webview2 installer strategy (download by default) + wv2rtstrategy := "" + webview2 = strings.ToLower(webview2) + if webview2 != "" { + validWV2Runtime := slicer.String([]string{"download", "embed", "browser", "error"}) + if !validWV2Runtime.Contains(webview2) { + return fmt.Errorf("invalid option for flag 'webview2': %s", webview2) + } + // These are the build tags associated with the strategies + switch webview2 { + case "embed": + wv2rtstrategy = "wv2runtime.embed" + case "error": + wv2rtstrategy = "wv2runtime.error" + case "browser": + wv2rtstrategy = "wv2runtime.browser" + } + } + + // Create BuildOptions + buildOptions := &build.Options{ + Logger: logger, + OutputType: outputType, + OutputFile: outputFilename, + CleanBuildDirectory: cleanBuildDirectory, + Mode: build.Production, + Pack: !noPackage, + LDFlags: ldflags, + Compiler: compilerCommand, + Verbosity: verbosity, + ForceBuild: forceBuild, + IgnoreFrontend: skipFrontend, + Compress: compress, + CompressFlags: compressFlags, + UserTags: userTags, + WebView2Strategy: wv2rtstrategy, + } + + // Calculate platform and arch + platformSplit := strings.Split(platform, "/") + buildOptions.Platform = platformSplit[0] + if system.IsAppleSilicon { + buildOptions.Arch = "arm64" + } else { + buildOptions.Arch = runtime.GOARCH + } + if len(platformSplit) == 2 { + buildOptions.Arch = platformSplit[1] + } + + // Start a new tabwriter + w := new(tabwriter.Writer) + w.Init(os.Stdout, 8, 8, 0, '\t', 0) + + // Write out the system information + fmt.Fprintf(w, "\n") + fmt.Fprintf(w, "App Type: \t%s\n", buildOptions.OutputType) + fmt.Fprintf(w, "Platform: \t%s\n", buildOptions.Platform) + fmt.Fprintf(w, "Arch: \t%s\n", buildOptions.Arch) + fmt.Fprintf(w, "Compiler: \t%s\n", compilerPath) + fmt.Fprintf(w, "Skip Frontend: \t%t\n", skipFrontend) + fmt.Fprintf(w, "Compress: \t%t\n", buildOptions.Compress) + fmt.Fprintf(w, "Package: \t%t\n", buildOptions.Pack) + fmt.Fprintf(w, "Clean Build Dir: \t%t\n", buildOptions.CleanBuildDirectory) + fmt.Fprintf(w, "LDFlags: \t\"%s\"\n", buildOptions.LDFlags) + fmt.Fprintf(w, "Tags: \t[%s]\n", strings.Join(buildOptions.UserTags, ",")) + if len(buildOptions.OutputFile) > 0 { + fmt.Fprintf(w, "Output File: \t%s\n", buildOptions.OutputFile) + } + fmt.Fprintf(w, "\n") + w.Flush() + + return doBuild(buildOptions) + }) +} + +// doBuild is our main build command +func doBuild(buildOptions *build.Options) error { + + // Start Time + start := time.Now() + + outputFilename, err := build.Build(buildOptions) + if err != nil { + return err + } + + // Output stats + elapsed := time.Since(start) + buildOptions.Logger.Println("") + buildOptions.Logger.Println(fmt.Sprintf("Built '%s' in %s.", outputFilename, elapsed.Round(time.Millisecond).String())) + buildOptions.Logger.Println("") + + return nil +} diff --git a/v2/cmd/wails/internal/commands/dev/README.md b/v2/cmd/wails/internal/commands/dev/README.md new file mode 100644 index 000000000..96eb3d2a2 --- /dev/null +++ b/v2/cmd/wails/internal/commands/dev/README.md @@ -0,0 +1,22 @@ +# Dev + +The dev command allows you to develop your application through a standard browser. + +## Usage + +`wails dev ` + +### Flags + +| Flag | Details | Default | +| :------------- | :----------- | :------ | +| -compiler path/to/compiler | Use a different go compiler, eg go1.15beta1 | go | +| -ldflags "custom ld flags" | Use given ldflags | | +| -e list,of,extensions | File extensions to trigger rebuilds | go | +| -w | Show warnings | false | +| -v int | Verbosity level (0 - silent, 1 - default, 2 - verbose) | 1 | +| -loglevel | Loglevel to pass to the application - Trace, Debug, Info, Warning, Error | Debug | + +## How it works + +The project is built using a special mode that starts a webserver and starts listening to port 34115. When the frontend project is run independently, so long as the JS is wrapped with the runtime method `ready`, then the frontend will connect to the backend code via websockets. The interface should be present in your browser, and you should be able to interact with the backend as you would in a desktop app. \ No newline at end of file diff --git a/v2/cmd/wails/internal/commands/dev/dev.go b/v2/cmd/wails/internal/commands/dev/dev.go new file mode 100644 index 000000000..e9344ea4a --- /dev/null +++ b/v2/cmd/wails/internal/commands/dev/dev.go @@ -0,0 +1,576 @@ +package dev + +import ( + "context" + "fmt" + "io" + "net/http" + "os" + "os/exec" + "os/signal" + "path/filepath" + "runtime" + "strconv" + "strings" + "sync" + "syscall" + "time" + + "github.com/wailsapp/wails/v2/cmd/wails/internal" + "github.com/wailsapp/wails/v2/internal/gomod" + + "github.com/leaanthony/slicer" + "github.com/wailsapp/wails/v2/internal/project" + + "github.com/pkg/browser" + "github.com/wailsapp/wails/v2/internal/colour" + + "github.com/fsnotify/fsnotify" + "github.com/leaanthony/clir" + "github.com/wailsapp/wails/v2/internal/fs" + "github.com/wailsapp/wails/v2/internal/process" + "github.com/wailsapp/wails/v2/pkg/clilogger" + "github.com/wailsapp/wails/v2/pkg/commands/build" +) + +const defaultDevServerURL = "http://localhost:34115" + +func LogGreen(message string, args ...interface{}) { + text := fmt.Sprintf(message, args...) + println(colour.Green(text)) +} + +func LogRed(message string, args ...interface{}) { + text := fmt.Sprintf(message, args...) + println(colour.Red(text)) +} + +func LogDarkYellow(message string, args ...interface{}) { + text := fmt.Sprintf(message, args...) + println(colour.DarkYellow(text)) +} + +func sliceToMap(input []string) map[string]struct{} { + result := map[string]struct{}{} + for _, value := range input { + result[value] = struct{}{} + } + return result +} + +type devFlags struct { + ldflags string + compilerCommand string + assetDir string + extensions string + openBrowser bool + noReload bool + wailsjsdir string + tags string + verbosity int + loglevel string + forceBuild bool + debounceMS int + devServerURL string +} + +// AddSubcommand adds the `dev` command for the Wails application +func AddSubcommand(app *clir.Cli, w io.Writer) error { + + command := app.NewSubCommand("dev", "Development mode") + + flags := defaultDevFlags() + command.StringFlag("ldflags", "optional ldflags", &flags.ldflags) + command.StringFlag("compiler", "Use a different go compiler to build, eg go1.15beta1", &flags.compilerCommand) + command.StringFlag("assetdir", "Serve assets from the given directory", &flags.assetDir) + command.StringFlag("e", "Extensions to trigger rebuilds (comma separated) eg go", &flags.extensions) + command.BoolFlag("browser", "Open application in browser", &flags.openBrowser) + command.BoolFlag("noreload", "Disable reload on asset change", &flags.noReload) + command.StringFlag("wailsjsdir", "Directory to generate the Wails JS modules", &flags.wailsjsdir) + command.StringFlag("tags", "tags to pass to Go compiler (quoted and space separated)", &flags.tags) + command.IntFlag("v", "Verbosity level (0 - silent, 1 - standard, 2 - verbose)", &flags.verbosity) + command.StringFlag("loglevel", "Loglevel to use - Trace, Debug, Info, Warning, Error", &flags.loglevel) + command.BoolFlag("f", "Force build application", &flags.forceBuild) + command.IntFlag("debounce", "The amount of time to wait to trigger a reload on change", &flags.debounceMS) + command.StringFlag("devserverurl", "The url of the dev server to use", &flags.devServerURL) + + command.Action(func() error { + // Create logger + logger := clilogger.New(w) + app.PrintBanner() + + experimental := false + userTags := []string{} + for _, tag := range strings.Split(flags.tags, " ") { + thisTag := strings.TrimSpace(tag) + if thisTag != "" { + userTags = append(userTags, thisTag) + } + if thisTag == "exp" { + experimental = true + } + } + + if runtime.GOOS == "darwin" && !experimental { + return fmt.Errorf("MacOS version coming soon!") + } + + cwd, err := os.Getwd() + if err != nil { + return err + } + + projectConfig, err := loadAndMergeProjectConfig(cwd, &flags) + if err != nil { + return err + } + + // Update go.mod to use current wails version + err = syncGoModVersion(cwd) + if err != nil { + return err + } + + // Run go mod tidy to ensure we're up to date + err = runCommand(cwd, false, "go", "mod", "tidy") + if err != nil { + return err + } + + if flags.tags != "" { + err = runCommand(cwd, true, "wails", "generate", "module", "-tags", flags.tags) + } else { + err = runCommand(cwd, true, "wails", "generate", "module") + } + if err != nil { + return err + } + + // frontend:dev server command + if projectConfig.DevCommand != "" { + var devCommandWaitGroup sync.WaitGroup + closer := runFrontendDevCommand(cwd, projectConfig.DevCommand, &devCommandWaitGroup) + defer closer(&devCommandWaitGroup) + } + + buildOptions := generateBuildOptions(flags) + buildOptions.Logger = logger + buildOptions.UserTags = internal.ParseUserTags(flags.tags) + + var debugBinaryProcess *process.Process = nil + + // Setup signal handler + quitChannel := make(chan os.Signal, 1) + signal.Notify(quitChannel, os.Interrupt, os.Kill, syscall.SIGTERM) + exitCodeChannel := make(chan int, 1) + + // Do initial build + logger.Println("Building application for development...") + newProcess, appBinary, err := restartApp(buildOptions, debugBinaryProcess, flags, exitCodeChannel) + if err != nil { + return err + } + if newProcess != nil { + debugBinaryProcess = newProcess + } + + // open browser + if flags.openBrowser { + url := defaultDevServerURL + if flags.devServerURL != "" { + url = flags.devServerURL + } + err = browser.OpenURL(url) + if err != nil { + return err + } + } + + // create the project files watcher + watcher, err := initialiseWatcher(cwd, logger.Fatal) + defer func(watcher *fsnotify.Watcher) { + err := watcher.Close() + if err != nil { + logger.Fatal(err.Error()) + } + }(watcher) + + LogGreen("Watching (sub)/directory: %s", cwd) + LogGreen("Using Dev Server URL: %s", flags.devServerURL) + LogGreen("Using reload debounce setting of %d milliseconds", flags.debounceMS) + + // Watch for changes and trigger restartApp() + doWatcherLoop(buildOptions, debugBinaryProcess, flags, watcher, exitCodeChannel, quitChannel) + + // Kill the current program if running + if debugBinaryProcess != nil { + err := debugBinaryProcess.Kill() + if err != nil { + return err + } + } + + // Remove dev binary + err = os.Remove(appBinary) + if err != nil { + return err + } + + LogGreen("Development mode exited") + + return nil + }) + return nil +} + +func syncGoModVersion(cwd string) error { + gomodFilename := filepath.Join(cwd, "go.mod") + gomodData, err := os.ReadFile(gomodFilename) + if err != nil { + return err + } + outOfSync, err := gomod.GoModOutOfSync(gomodData, internal.Version) + if err != nil { + return err + } + if !outOfSync { + return nil + } + LogGreen("Updating go.mod to use Wails '%s'", internal.Version) + newGoData, err := gomod.UpdateGoModVersion(gomodData, internal.Version) + if err != nil { + return err + } + return os.WriteFile(gomodFilename, newGoData, 0755) +} + +func runCommand(dir string, exitOnError bool, command string, args ...string) error { + LogGreen("Executing: " + command + " " + strings.Join(args, " ")) + cmd := exec.Command(command, args...) + cmd.Dir = dir + output, err := cmd.CombinedOutput() + if err != nil { + println(string(output)) + if exitOnError { + os.Exit(1) + } + return err + } + return nil +} + +// defaultDevFlags generates devFlags with default options +func defaultDevFlags() devFlags { + return devFlags{ + devServerURL: defaultDevServerURL, + compilerCommand: "go", + verbosity: 1, + extensions: "go", + debounceMS: 100, + } +} + +// generateBuildOptions creates a build.Options using the flags +func generateBuildOptions(flags devFlags) *build.Options { + result := &build.Options{ + OutputType: "dev", + Mode: build.Dev, + Arch: runtime.GOARCH, + Pack: false, + Platform: runtime.GOOS, + LDFlags: flags.ldflags, + Compiler: flags.compilerCommand, + ForceBuild: flags.forceBuild, + IgnoreFrontend: false, + Verbosity: flags.verbosity, + WailsJSDir: flags.wailsjsdir, + } + switch runtime.GOOS { + case "darwin": + result.Pack = false + } + return result +} + +// loadAndMergeProjectConfig reconciles flags passed to the CLI with project config settings and updates +// the project config if necessary +func loadAndMergeProjectConfig(cwd string, flags *devFlags) (*project.Project, error) { + projectConfig, err := project.Load(cwd) + if err != nil { + return nil, err + } + + var shouldSaveConfig bool + + if projectConfig.AssetDirectory == "" && flags.assetDir == "" { + return nil, fmt.Errorf("No asset directory provided. Please use -assetdir to indicate which directory contains your built assets.") + } + + if flags.assetDir == "" && projectConfig.AssetDirectory != "" { + flags.assetDir = projectConfig.AssetDirectory + } + + if flags.assetDir != projectConfig.AssetDirectory { + projectConfig.AssetDirectory = filepath.ToSlash(flags.assetDir) + } + + flags.assetDir, err = filepath.Abs(flags.assetDir) + if err != nil { + return nil, err + } + + if flags.devServerURL == defaultDevServerURL && projectConfig.DevServerURL != defaultDevServerURL && projectConfig.DevServerURL != "" { + flags.devServerURL = projectConfig.DevServerURL + } + + if flags.devServerURL != projectConfig.DevServerURL { + projectConfig.DevServerURL = flags.devServerURL + shouldSaveConfig = true + } + + if flags.wailsjsdir == "" && projectConfig.WailsJSDir != "" { + flags.wailsjsdir = projectConfig.WailsJSDir + } + + if flags.wailsjsdir == "" { + flags.wailsjsdir = "./frontend" + } + + if flags.wailsjsdir != projectConfig.WailsJSDir { + projectConfig.WailsJSDir = filepath.ToSlash(flags.wailsjsdir) + shouldSaveConfig = true + } + + if flags.debounceMS == 100 && projectConfig.DebounceMS != 100 { + if projectConfig.DebounceMS == 0 { + projectConfig.DebounceMS = 100 + } + flags.debounceMS = projectConfig.DebounceMS + } + + if flags.debounceMS != projectConfig.DebounceMS { + projectConfig.DebounceMS = flags.debounceMS + shouldSaveConfig = true + } + + if shouldSaveConfig { + err = projectConfig.Save() + if err != nil { + return nil, err + } + } + + return projectConfig, nil +} + +// runFrontendDevCommand will run the `frontend:dev` command if it was given, ex- `npm run dev` +func runFrontendDevCommand(cwd string, devCommand string, wg *sync.WaitGroup) func(group *sync.WaitGroup) { + LogGreen("Running frontend dev command: '%s'", devCommand) + ctx, cancel := context.WithCancel(context.Background()) + dir := filepath.Join(cwd, "frontend") + cmdSlice := strings.Split(devCommand, " ") + wg.Add(1) + cmd := exec.CommandContext(ctx, cmdSlice[0], cmdSlice[1:]...) + cmd.Stderr = os.Stderr + cmd.Stdout = os.Stdout + cmd.Dir = dir + go func(ctx context.Context, devCommand string, cwd string, wg *sync.WaitGroup) { + err := cmd.Run() + if err != nil { + if err.Error() != "exit status 1" { + LogRed("Error from '%s': %s", devCommand, err.Error()) + } + } + LogGreen("Dev command exited!") + wg.Done() + }(ctx, devCommand, cwd, wg) + + return func(wg *sync.WaitGroup) { + if runtime.GOOS == "windows" { + // Credit: https://stackoverflow.com/a/44551450 + // For whatever reason, killing an npm script on windows just doesn't exit properly with cancel + if cmd != nil && cmd.Process != nil { + kill := exec.Command("TASKKILL", "/T", "/F", "/PID", strconv.Itoa(cmd.Process.Pid)) + kill.Stderr = os.Stderr + kill.Stdout = os.Stdout + err := kill.Run() + if err != nil { + if err.Error() != "exit status 1" { + LogRed("Error from '%s': %s", devCommand, err.Error()) + } + } + } + } else { + cancel() + } + wg.Wait() + } +} + +// initialiseWatcher creates the project directory watcher that will trigger recompile +func initialiseWatcher(cwd string, logFatal func(string, ...interface{})) (*fsnotify.Watcher, error) { + watcher, err := fsnotify.NewWatcher() + if err != nil { + return nil, err + } + + // Get all subdirectories + dirs, err := fs.GetSubdirectories(cwd) + if err != nil { + return nil, err + } + + // Setup a watcher for non-node_modules directories + dirs.Each(func(dir string) { + if strings.Contains(dir, "node_modules") { + return + } + // Ignore build directory + if strings.HasPrefix(dir, filepath.Join(cwd, "build")) { + return + } + // Ignore dot directories + if strings.HasPrefix(dir, ".") { + return + } + err = watcher.Add(dir) + if err != nil { + logFatal(err.Error()) + } + }) + return watcher, nil +} + +// restartApp does the actual rebuilding of the application when files change +func restartApp(buildOptions *build.Options, debugBinaryProcess *process.Process, flags devFlags, exitCodeChannel chan int) (*process.Process, string, error) { + + appBinary, err := build.Build(buildOptions) + println() + if err != nil { + LogRed("Build error - continuing to run current version") + LogDarkYellow(err.Error()) + return nil, "", nil + } + + // Kill existing binary if need be + if debugBinaryProcess != nil { + killError := debugBinaryProcess.Kill() + + if killError != nil { + buildOptions.Logger.Fatal("Unable to kill debug binary (PID: %d)!", debugBinaryProcess.PID()) + } + + debugBinaryProcess = nil + } + + // Start up new binary with correct args + args := slicer.StringSlicer{} + args.Add("-loglevel", flags.loglevel) + if flags.assetDir != "" { + args.Add("-assetdir", flags.assetDir) + } + if flags.devServerURL != "" { + args.Add("-devserverurl", flags.devServerURL) + } + newProcess := process.NewProcess(appBinary, args.AsSlice()...) + err = newProcess.Start(exitCodeChannel) + if err != nil { + // Remove binary + if fs.FileExists(appBinary) { + deleteError := fs.DeleteFile(appBinary) + if deleteError != nil { + buildOptions.Logger.Fatal("Unable to delete app binary: " + appBinary) + } + } + buildOptions.Logger.Fatal("Unable to start application: %s", err.Error()) + } + + return newProcess, appBinary, nil +} + +// doWatcherLoop is the main watch loop that runs while dev is active +func doWatcherLoop(buildOptions *build.Options, debugBinaryProcess *process.Process, flags devFlags, watcher *fsnotify.Watcher, exitCodeChannel chan int, quitChannel chan os.Signal) { + // Main Loop + var ( + err error + newBinaryProcess *process.Process + ) + var extensionsThatTriggerARebuild = sliceToMap(strings.Split(flags.extensions, ",")) + quit := false + interval := time.Duration(flags.debounceMS) * time.Millisecond + timer := time.NewTimer(interval) + rebuild := false + reload := false + for quit == false { + //reload := false + select { + case exitCode := <-exitCodeChannel: + if exitCode == 0 { + quit = true + } + case item := <-watcher.Events: + // Check for file writes + if item.Op&fsnotify.Write == fsnotify.Write { + // Ignore directories + if fs.DirExists(item.Name) { + continue + } + + // Iterate all file patterns + ext := filepath.Ext(item.Name) + if ext != "" { + ext = ext[1:] + if _, exists := extensionsThatTriggerARebuild[ext]; exists { + rebuild = true + timer.Reset(interval) + continue + } + } + + if strings.HasPrefix(item.Name, flags.assetDir) { + reload = true + } + timer.Reset(interval) + } + // Check for new directories + if item.Op&fsnotify.Create == fsnotify.Create { + // If this is a folder, add it to our watch list + if fs.DirExists(item.Name) { + //node_modules is BANNED! + if !strings.Contains(item.Name, "node_modules") { + err := watcher.Add(item.Name) + if err != nil { + buildOptions.Logger.Fatal("%s", err.Error()) + } + LogGreen("Added new directory to watcher: %s", item.Name) + } + } + } + case <-timer.C: + if rebuild { + rebuild = false + LogGreen("[Rebuild triggered] files updated") + // Try and build the app + newBinaryProcess, _, err = restartApp(buildOptions, debugBinaryProcess, flags, exitCodeChannel) + if err != nil { + LogRed("Error during build: %s", err.Error()) + continue + } + // If we have a new process, save it + if newBinaryProcess != nil { + debugBinaryProcess = newBinaryProcess + } + } + if reload { + reload = false + _, err = http.Get("http://localhost:34115/wails/reload") + if err != nil { + LogRed("Error during refresh: %s", err.Error()) + } + } + case <-quitChannel: + LogGreen("\nCaught quit") + quit = true + } + } +} diff --git a/v2/cmd/wails/internal/commands/doctor/doctor.go b/v2/cmd/wails/internal/commands/doctor/doctor.go new file mode 100644 index 000000000..0075a7efb --- /dev/null +++ b/v2/cmd/wails/internal/commands/doctor/doctor.go @@ -0,0 +1,158 @@ +package doctor + +import ( + "fmt" + "io" + "os" + "runtime" + "strings" + "text/tabwriter" + + "github.com/leaanthony/clir" + "github.com/wailsapp/wails/v2/internal/system" + "github.com/wailsapp/wails/v2/internal/system/packagemanager" + "github.com/wailsapp/wails/v2/pkg/clilogger" +) + +// AddSubcommand adds the `doctor` command for the Wails application +func AddSubcommand(app *clir.Cli, w io.Writer) error { + + command := app.NewSubCommand("doctor", "Diagnose your environment") + + command.Action(func() error { + + logger := clilogger.New(w) + + app.PrintBanner() + + logger.Print("Scanning system - Please wait (this may take a long time)...") + + // Get system info + info, err := system.GetInfo() + if err != nil { + logger.Println("Failed.") + return err + } + logger.Println("Done.") + + logger.Println("") + + // Start a new tabwriter + w := new(tabwriter.Writer) + w.Init(os.Stdout, 8, 8, 0, '\t', 0) + + // Write out the system information + fmt.Fprintf(w, "System\n") + fmt.Fprintf(w, "------\n") + fmt.Fprintf(w, "%s\t%s\n", "OS:", info.OS.Name) + fmt.Fprintf(w, "%s\t%s\n", "Version: ", info.OS.Version) + fmt.Fprintf(w, "%s\t%s\n", "ID:", info.OS.ID) + + // Output Go Information + fmt.Fprintf(w, "%s\t%s\n", "Go Version:", runtime.Version()) + fmt.Fprintf(w, "%s\t%s\n", "Platform:", runtime.GOOS) + fmt.Fprintf(w, "%s\t%s\n", "Architecture:", runtime.GOARCH) + + // Exit early if PM not found + if info.PM != nil { + fmt.Fprintf(w, "%s\t%s\n", "Package Manager: ", info.PM.Name()) + } + + // Output Dependencies Status + var dependenciesMissing = []string{} + var externalPackages = []*packagemanager.Dependancy{} + var dependenciesAvailableRequired = 0 + var dependenciesAvailableOptional = 0 + fmt.Fprintf(w, "\n") + fmt.Fprintf(w, "Dependency\tPackage Name\tStatus\tVersion\n") + fmt.Fprintf(w, "----------\t------------\t------\t-------\n") + + hasOptionalDependencies := false + // Loop over dependencies + for _, dependency := range info.Dependencies { + + name := dependency.Name + if dependency.Optional { + name = "*" + name + hasOptionalDependencies = true + } + packageName := "Unknown" + status := "Not Found" + + // If we found the package + if dependency.PackageName != "" { + + packageName = dependency.PackageName + + // If it's installed, update the status + if dependency.Installed { + status = "Installed" + } else { + // Generate meaningful status text + status = "Available" + + if dependency.Optional { + dependenciesAvailableOptional++ + } else { + dependenciesAvailableRequired++ + } + } + } else { + if !dependency.Optional { + dependenciesMissing = append(dependenciesMissing, dependency.Name) + } + + if dependency.External { + externalPackages = append(externalPackages, dependency) + } + } + + fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", name, packageName, status, dependency.Version) + } + if hasOptionalDependencies { + fmt.Fprintf(w, "\n") + fmt.Fprintf(w, "* - Optional Dependency\n") + } + w.Flush() + logger.Println("") + logger.Println("Diagnosis") + logger.Println("---------") + + // Generate an appropriate diagnosis + + if len(dependenciesMissing) == 0 && dependenciesAvailableRequired == 0 { + logger.Println("Your system is ready for Wails development!") + } else { + logger.Println("Your system has missing dependencies!\n") + } + + if dependenciesAvailableRequired != 0 { + logger.Println("Required package(s) installation details: \n" + info.Dependencies.InstallAllRequiredCommand()) + } + + if dependenciesAvailableOptional != 0 { + logger.Println("Optional package(s) installation details: \n" + info.Dependencies.InstallAllOptionalCommand()) + } + // + //if len(externalPackages) > 0 { + // for _, p := range externalPackages { + // if p.Optional { + // print("[Optional] ") + // } + // logger.Println("Install " + p.Name + ": " + p.InstallCommand) + // } + //} + + if len(dependenciesMissing) != 0 { + // TODO: Check if apps are available locally and if so, adjust the diagnosis + logger.Println("Fatal:") + logger.Println("Required dependencies missing: " + strings.Join(dependenciesMissing, " ")) + logger.Println("Please read this article on how to resolve this: https://wails.app/guides/resolving-missing-packages") + } + + logger.Println("") + return nil + }) + + return nil +} diff --git a/v2/cmd/wails/internal/commands/generate/README.md b/v2/cmd/wails/internal/commands/generate/README.md new file mode 100644 index 000000000..c24eb060a --- /dev/null +++ b/v2/cmd/wails/internal/commands/generate/README.md @@ -0,0 +1,18 @@ +# Generate + +The `generate` command provides the ability to generate various Wails related components. + +## Usage + +`wails generate [subcommand] [options]` + +## Template + +`wails generate template -name [-frontend] [-q]` + +Generate a starter template for you to customise. + +| Flag | Details | +| :------------- | :----------- | +| -frontend | Copies all the files from the current directory into the template's `frontend` directory. Useful for converting frontend projects created by boilerplate generators. | +| -q | Suppress output | diff --git a/v2/cmd/wails/internal/commands/generate/generate.go b/v2/cmd/wails/internal/commands/generate/generate.go new file mode 100644 index 000000000..58f623bf0 --- /dev/null +++ b/v2/cmd/wails/internal/commands/generate/generate.go @@ -0,0 +1,23 @@ +package generate + +import ( + "io" + + "github.com/wailsapp/wails/v2/cmd/wails/internal/commands/generate/template" + + "github.com/leaanthony/clir" +) + +// AddSubcommand adds the `generate` command for the Wails application +func AddSubcommand(app *clir.Cli, w io.Writer) error { + + command := app.NewSubCommand("generate", "Code Generation Tools") + + err := AddModuleCommand(app, command, w) + if err != nil { + return err + } + template.AddSubCommand(app, command, w) + + return nil +} diff --git a/v2/cmd/wails/internal/commands/generate/module.go b/v2/cmd/wails/internal/commands/generate/module.go new file mode 100644 index 000000000..91f9309f9 --- /dev/null +++ b/v2/cmd/wails/internal/commands/generate/module.go @@ -0,0 +1,58 @@ +package generate + +import ( + "fmt" + "github.com/leaanthony/clir" + "github.com/wailsapp/wails/v2/cmd/wails/internal" + "github.com/wailsapp/wails/v2/internal/shell" + "io" + "os" + "path/filepath" + "runtime" + "strings" +) + +// AddModuleCommand adds the `module` subcommand for the `generate` command +func AddModuleCommand(app *clir.Cli, parent *clir.Command, w io.Writer) error { + + command := parent.NewSubCommand("module", "Generate wailsjs modules") + var tags string + command.StringFlag("tags", "tags to pass to Go compiler (quoted and space separated)", &tags) + + command.Action(func() error { + + filename := "wailsbindings" + if runtime.GOOS == "windows" { + filename += ".exe" + } + // go build -tags bindings -o bindings.exe + tempDir := os.TempDir() + filename = filepath.Join(tempDir, filename) + + cwd, err := os.Getwd() + if err != nil { + return err + } + + tagList := internal.ParseUserTags(tags) + tagList = append(tagList, "bindings") + + stdout, stderr, err := shell.RunCommand(cwd, "go", "build", "-tags", strings.Join(tagList, ","), "-o", filename) + if err != nil { + return fmt.Errorf("%s\n%s\n%s", stdout, stderr, err) + } + + stdout, stderr, err = shell.RunCommand(cwd, filename) + if err != nil { + return fmt.Errorf("%s\n%s\n%s", stdout, stderr, err) + } + + err = os.Remove(filename) + if err != nil { + return err + } + + return nil + }) + return nil +} diff --git a/v2/cmd/wails/internal/template/base/NEXTSTEPS.md.template b/v2/cmd/wails/internal/commands/generate/template/base/NEXTSTEPS.md.template similarity index 97% rename from v2/cmd/wails/internal/template/base/NEXTSTEPS.md.template rename to v2/cmd/wails/internal/commands/generate/template/base/NEXTSTEPS.md.template index 5363d10f2..a357acd82 100644 --- a/v2/cmd/wails/internal/template/base/NEXTSTEPS.md.template +++ b/v2/cmd/wails/internal/commands/generate/template/base/NEXTSTEPS.md.template @@ -10,6 +10,7 @@ The next steps to complete the template are: - It is really important to ensure `helpurl` is valid as this is where users of the template will be directed for help. 2. Update `README.md`. 3. Edit `wails.json` and ensure all fields are correct, especially: + - `assetdir` - path to your assets - `wailsjsdir` - path to generate wailsjs modules - `frontend:install` - The command to install your frontend dependencies - `frontend:build` - The command to build your frontend diff --git a/v2/cmd/wails/internal/commands/generate/template/base/README.md b/v2/cmd/wails/internal/commands/generate/template/base/README.md new file mode 100644 index 000000000..fd993210d --- /dev/null +++ b/v2/cmd/wails/internal/commands/generate/template/base/README.md @@ -0,0 +1,16 @@ +# README + +## About + +About your template + +## Building + +To build this project in debug mode, use `wails build`. For production, use `wails build -production`. +To generate a platform native package, add the `-package` flag. + +## Live Development + +To run in live development mode, run `wails dev` in the project directory. In another terminal, go into the `frontend` +directory and run `npm run dev`. The frontend dev server will run on http://localhost:34115. Connect to this +in your browser and connect to your application. diff --git a/v2/cmd/wails/internal/commands/generate/template/base/app.tmpl.go b/v2/cmd/wails/internal/commands/generate/template/base/app.tmpl.go new file mode 100644 index 000000000..dd540dcd2 --- /dev/null +++ b/v2/cmd/wails/internal/commands/generate/template/base/app.tmpl.go @@ -0,0 +1,37 @@ +package main + +import ( + "context" + "fmt" +) + +// App struct +type App struct { + ctx context.Context +} + +// NewApp creates a new App application struct +func NewApp() *App { + return &App{} +} + +// startup is called at application startup +func (a *App) startup(ctx context.Context) { + // Perform your setup here + a.ctx = ctx +} + +// domReady is called after the front-end dom has been loaded +func (a App) domReady(ctx context.Context) { + // Add your action here +} + +// shutdown is called at application termination +func (a *App) shutdown(ctx context.Context) { + // Perform your teardown here +} + +// Greet returns a greeting for the given name +func (a *App) Greet(name string) string { + return fmt.Sprintf("Hello %s!", name) +} diff --git a/v2/cmd/wails/internal/template/base/frontend/dist/assets/fonts/OFL.txt b/v2/cmd/wails/internal/commands/generate/template/base/frontend/dist/assets/fonts/OFL.txt similarity index 100% rename from v2/cmd/wails/internal/template/base/frontend/dist/assets/fonts/OFL.txt rename to v2/cmd/wails/internal/commands/generate/template/base/frontend/dist/assets/fonts/OFL.txt diff --git a/v2/cmd/wails/internal/template/base/frontend/dist/assets/fonts/nunito-v16-latin-regular.woff2 b/v2/cmd/wails/internal/commands/generate/template/base/frontend/dist/assets/fonts/nunito-v16-latin-regular.woff2 similarity index 100% rename from v2/cmd/wails/internal/template/base/frontend/dist/assets/fonts/nunito-v16-latin-regular.woff2 rename to v2/cmd/wails/internal/commands/generate/template/base/frontend/dist/assets/fonts/nunito-v16-latin-regular.woff2 diff --git a/v2/cmd/wails/internal/commands/generate/template/base/frontend/dist/assets/images/logo-dark.svg b/v2/cmd/wails/internal/commands/generate/template/base/frontend/dist/assets/images/logo-dark.svg new file mode 100644 index 000000000..855d7e0ef --- /dev/null +++ b/v2/cmd/wails/internal/commands/generate/template/base/frontend/dist/assets/images/logo-dark.svg @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v2/cmd/wails/internal/commands/generate/template/base/frontend/dist/index.html b/v2/cmd/wails/internal/commands/generate/template/base/frontend/dist/index.html new file mode 100644 index 000000000..7f516f7fa --- /dev/null +++ b/v2/cmd/wails/internal/commands/generate/template/base/frontend/dist/index.html @@ -0,0 +1,18 @@ + + + + + + + + +
Please enter your name below 👇
+
+ + +
+ + + + + \ No newline at end of file diff --git a/v2/cmd/wails/internal/commands/generate/template/base/frontend/dist/main.css b/v2/cmd/wails/internal/commands/generate/template/base/frontend/dist/main.css new file mode 100644 index 000000000..af6412466 --- /dev/null +++ b/v2/cmd/wails/internal/commands/generate/template/base/frontend/dist/main.css @@ -0,0 +1,72 @@ +html { + background-color: rgba(33, 37, 43, 1); + text-align: center; + color: white; +} + +body { + margin: 0; + color: white; + font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", + "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", + sans-serif; +} + +@font-face { + font-family: "Nunito"; + font-style: normal; + font-weight: 400; + src: local(""), + url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2"); +} + +.logo { + display: block; + width: 35%; + height: 35%; + margin: auto; + padding: 15% 0 0; + background-position: center; + background-repeat: no-repeat; + background-image: url("./assets/images/logo-dark.svg"); +} +.result { + height: 20px; + line-height: 20px; + margin: 1.5rem auto; +} +.input-box .btn { + width: 60px; + height: 30px; + line-height: 30px; + border-radius: 3px; + border: none; + margin: 0 0 0 20px; + padding: 0 8px; + cursor: pointer; +} +.input-box .btn:hover { + background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%); + color: #333333; +} + +.input-box .input { + border: none; + border-radius: 3px; + outline: none; + height: 30px; + line-height: 30px; + padding: 0 10px; + background-color: rgba(240, 240, 240, 1); + -webkit-font-smoothing: antialiased; +} + +.input-box .input:hover { + border: none; + background-color: rgba(255, 255, 255, 1); +} + +.input-box .input:focus { + border: none; + background-color: rgba(255, 255, 255, 1); +} diff --git a/v2/cmd/wails/internal/commands/generate/template/base/frontend/dist/main.js b/v2/cmd/wails/internal/commands/generate/template/base/frontend/dist/main.js new file mode 100644 index 000000000..db404e459 --- /dev/null +++ b/v2/cmd/wails/internal/commands/generate/template/base/frontend/dist/main.js @@ -0,0 +1,23 @@ +// Get input + focus +let nameElement = document.getElementById("name"); +nameElement.focus(); + +// Setup the greet function +window.greet = function () { + + // Get name + let name = nameElement.value; + + // Call App.Greet(name) + window.go.main.App.Greet(name).then((result) => { + // Update result with data back from App.Greet() + document.getElementById("result").innerText = result; + }); +}; + +nameElement.onkeydown = function (e) { + console.log(e) + if (e.keyCode == 13) { + window.greet() + } +} \ No newline at end of file diff --git a/v2/cmd/wails/internal/template/base/frontend/package.tmpl.json b/v2/cmd/wails/internal/commands/generate/template/base/frontend/package.tmpl.json similarity index 100% rename from v2/cmd/wails/internal/template/base/frontend/package.tmpl.json rename to v2/cmd/wails/internal/commands/generate/template/base/frontend/package.tmpl.json diff --git a/v2/cmd/wails/internal/commands/generate/template/base/go.mod.tmpl b/v2/cmd/wails/internal/commands/generate/template/base/go.mod.tmpl new file mode 100644 index 000000000..166b9252d --- /dev/null +++ b/v2/cmd/wails/internal/commands/generate/template/base/go.mod.tmpl @@ -0,0 +1,38 @@ +module changeme + +go 1.17 + +require github.com/wailsapp/wails/v2 {{.WailsVersion}} + +require ( +github.com/andybalholm/brotli v1.0.2 // indirect +github.com/davecgh/go-spew v1.1.1 // indirect +github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect +github.com/gabriel-vasile/mimetype v1.3.1 // indirect +github.com/go-ole/go-ole v1.2.5 // indirect +github.com/gofiber/fiber/v2 v2.17.0 // indirect +github.com/gofiber/websocket/v2 v2.0.8 // indirect +github.com/google/uuid v1.1.2 // indirect +github.com/imdario/mergo v0.3.12 // indirect +github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5 // indirect +github.com/klauspost/compress v1.12.2 // indirect +github.com/leaanthony/debme v1.2.1 // indirect +github.com/leaanthony/go-ansi-parser v1.0.1 // indirect +github.com/leaanthony/go-common-file-dialog v1.0.3 // indirect +github.com/leaanthony/go-webview2 v0.0.0-20210914103035-f00aa774a934 // indirect +github.com/leaanthony/slicer v1.5.0 // indirect +github.com/leaanthony/typescriptify-golang-structs v0.1.7 // indirect +github.com/leaanthony/webview2runtime v1.1.0 // indirect +github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 // indirect +github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect +github.com/pkg/errors v0.9.1 // indirect +github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect +github.com/tkrajina/go-reflector v0.5.5 // indirect +github.com/valyala/bytebufferpool v1.0.0 // indirect +github.com/valyala/fasthttp v1.28.0 // indirect +github.com/valyala/tcplisten v1.0.0 // indirect +golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf // indirect +) + +// replace github.com/wailsapp/wails/v2 {{.WailsVersion}} => {{.WailsDirectory}} \ No newline at end of file diff --git a/v2/cmd/wails/internal/commands/generate/template/base/go.sum b/v2/cmd/wails/internal/commands/generate/template/base/go.sum new file mode 100644 index 000000000..8e8bd03fd --- /dev/null +++ b/v2/cmd/wails/internal/commands/generate/template/base/go.sum @@ -0,0 +1,225 @@ +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= +github.com/andybalholm/brotli v1.0.2 h1:JKnhI/XQ75uFBTiuzXpzFrUriDPiZjlOSzh6wXogP0E= +github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab h1:9e2joQGp642wHGFP5m86SDptAavrdGBe8/x9DGEEAaI= +github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab/go.mod h1:smsv/h4PBEBaU0XDTY5UwJTpZv69fQ0FfcLJr21mA6Y= +github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/gabriel-vasile/mimetype v1.3.1 h1:qevA6c2MtE1RorlScnixeG0VA1H4xrXyhyX3oWBynNQ= +github.com/gabriel-vasile/mimetype v1.3.1/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= +github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= +github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-billy/v5 v5.1.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= +github.com/go-git/go-git/v5 v5.3.0/go.mod h1:xdX4bWJ48aOrdhnl2XqHYstHbbp6+LFS4r4X+lNVprw= +github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= +github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY= +github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/gofiber/fiber/v2 v2.17.0 h1:qP3PkGUbBB0i9iQh5E057XI1yO5CZigUxZhyUFYAFoM= +github.com/gofiber/fiber/v2 v2.17.0/go.mod h1:iftruuHGkRYGEXVISmdD7HTYWyfS2Bh+Dkfq4n/1Owg= +github.com/gofiber/websocket/v2 v2.0.8 h1:Hb4y6IxYZVMO0segROODXJiXVgVD3a6i7wnfot8kM6k= +github.com/gofiber/websocket/v2 v2.0.8/go.mod h1:fv8HSGQX09sauNv9g5Xq8GeGAaahLFYQKKb4ZdT0x2w= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/jackmordaunt/icns v1.0.0/go.mod h1:7TTQVEuGzVVfOPPlLNHJIkzA6CoV7aH1Dv9dW351oOo= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5 h1:pdFFlHXY9tZXmJz+tRSm1DzYEH4ebha7cffmm607bMU= +github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs= +github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.12.2 h1:2KCfW3I9M7nSc5wOqXAlW2v2U6v+w6cbjvbfp+OykW8= +github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leaanthony/clir v1.0.4/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0= +github.com/leaanthony/debme v1.1.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA= +github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc= +github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA= +github.com/leaanthony/go-ansi-parser v1.0.1 h1:97v6c5kYppVsbScf4r/VZdXyQ21KQIfeQOk2DgKxGG4= +github.com/leaanthony/go-ansi-parser v1.0.1/go.mod h1:7arTzgVI47srICYhvgUV4CGd063sGEeoSlych5yeSPM= +github.com/leaanthony/go-common-file-dialog v1.0.3 h1:O0uGjKnWtdEADGrkg+TyAAbZylykMwwx/MNEXn9fp+Y= +github.com/leaanthony/go-common-file-dialog v1.0.3/go.mod h1:TGhEc9eSJgRsupZ+iH1ZgAOnEo9zp05cRH2j08RPrF0= +github.com/leaanthony/go-webview2 v0.0.0-20210914103035-f00aa774a934 h1:nK/JTPyJi5QRqYjVZjXgtN4/dhg2qtngoLxLDVn429k= +github.com/leaanthony/go-webview2 v0.0.0-20210914103035-f00aa774a934/go.mod h1:lS5ds4bruPk9d7lzdF/OH31Z0YCerI6MmHNFGsWoUnM= +github.com/leaanthony/gosod v1.0.2/go.mod h1:W8RyeSFBXu7RpIxPGEJfW4moSyGGEjlJMLV25wEbAdU= +github.com/leaanthony/idgen v1.0.0/go.mod h1:4nBZnt8ml/f/ic/EVQuLxuj817RccT2fyrUaZFxrcVA= +github.com/leaanthony/slicer v1.5.0 h1:aHYTN8xbCCLxJmkNKiLB6tgcMARl4eWmH9/F+S/0HtY= +github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY= +github.com/leaanthony/typescriptify-golang-structs v0.1.7 h1:yoznzWzyxkO/iWdlpq+aPcuJ5Y/hpjq/lmgMFmpjwl0= +github.com/leaanthony/typescriptify-golang-structs v0.1.7/go.mod h1:cWtOkiVhMF77e6phAXUcfNwYmMwCJ67Sij24lfvi9Js= +github.com/leaanthony/webview2runtime v1.1.0 h1:N0pv55ift8XtqozIp4PNOtRCJ/Qdd/qzx80lUpalS4c= +github.com/leaanthony/webview2runtime v1.1.0/go.mod h1:hH9GnWCve3DYzNaPOcPbhHQ7fodXR1QJNsnwixid4Tk= +github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 h1:5iOd93PZbpH4Iir8QkC4coFD+zEQEZSIRcjwjTFZkr0= +github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18/go.mod h1:KEbMsKoznsebyGHwLk5LqkFOxL5uXSRdvpP4+avmAMs= +github.com/leaanthony/winicon v1.0.0/go.mod h1:en5xhijl92aphrJdmRPlh4NI1L6wq3gEm0LpXAPghjU= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= +github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= +github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= +github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 h1:acNfDZXmm28D2Yg/c3ALnZStzNaZMSagpbr96vY6Zjc= +github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f h1:PgA+Olipyj258EIEYnpFFONrrCcAIWNUNoFhUfMqAGY= +github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f/go.mod h1:lHhJedqxCoHN+zMtwGNTXWmF0u9Jt363FYRhV6g0CdY= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tc-hib/winres v0.1.5/go.mod h1:pe6dOR40VOrGz8PkzreVKNvEKnlE8t4yR8A8naL+t7A= +github.com/tdewolff/minify v2.3.6+incompatible/go.mod h1:9Ov578KJUmAWpS6NeZwRZyT56Uf6o3Mcz9CEsg8USYs= +github.com/tdewolff/parse v2.3.4+incompatible/go.mod h1:8oBwCsVmUkgHO8M5iCzSIDtpzXOT0WXX9cWhz+bIzJQ= +github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= +github.com/tidwall/gjson v1.8.0/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk= +github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/sjson v1.1.7/go.mod h1:w/yG+ezBeTdUxiKs5NcPicO9diP38nk96QBAbIIGeFs= +github.com/tkrajina/go-reflector v0.5.5 h1:gwoQFNye30Kk7NrExj8zm3zFtrGPqOkzFMLuQZg1DtQ= +github.com/tkrajina/go-reflector v0.5.5/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.9.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= +github.com/valyala/fasthttp v1.26.0/go.mod h1:cmWIqlu99AO/RKcp1HWaViTqc57FswJOfYYdPJBl8BA= +github.com/valyala/fasthttp v1.28.0 h1:ruVmTmZaBR5i67NqnjvvH5gEv0zwHfWtbjoyW98iho4= +github.com/valyala/fasthttp v1.28.0/go.mod h1:cmWIqlu99AO/RKcp1HWaViTqc57FswJOfYYdPJBl8BA= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= +github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +github.com/wzshiming/ctc v1.2.3/go.mod h1:2tVAtIY7SUyraSk0JxvwmONNPFL4ARavPuEsg5+KA28= +github.com/wzshiming/winseq v0.0.0-20200112104235-db357dc107ae/go.mod h1:VTAq37rkGeV+WOybvZwjXiJOicICdpLCN8ifpISjK20= +github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= +github.com/xyproto/xpm v1.2.1/go.mod h1:cMnesLsD0PBXLgjDfTDEaKr8XyTFsnP1QycSqRw7BiY= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/ztrue/tracerr v0.3.0/go.mod h1:qEalzze4VN9O8tnhBXScfCrmoJo10o8TN5ciKjm6Mww= +golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= +golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210510120150-4163338589ed h1:p9UgmWI9wKpfYmgaV/IZKGdXc5qEK45tDwwwDyjS26I= +golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210611083646-a4fc73990273/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= diff --git a/v2/cmd/wails/internal/commands/generate/template/base/main.tmpl.go b/v2/cmd/wails/internal/commands/generate/template/base/main.tmpl.go new file mode 100644 index 000000000..4bec207bd --- /dev/null +++ b/v2/cmd/wails/internal/commands/generate/template/base/main.tmpl.go @@ -0,0 +1,54 @@ +package main + +import ( + "embed" + "log" + + "github.com/wailsapp/wails/v2" + "github.com/wailsapp/wails/v2/pkg/logger" + "github.com/wailsapp/wails/v2/pkg/options" + "github.com/wailsapp/wails/v2/pkg/options/windows" +) + +//go:embed frontend/dist +var assets embed.FS + +func main() { + // Create an instance of the app structure + app := NewApp() + + // Create application with options + err := wails.Run(&options.App{ + Title: "{{.ProjectName}}", + Width: 1024, + Height: 768, + // MinWidth: 720, + // MinHeight: 570, + // MaxWidth: 1280, + // MaxHeight: 740, + DisableResize: false, + Fullscreen: false, + Frameless: false, + StartHidden: false, + HideWindowOnClose: false, + RGBA: &options.RGBA{255, 255, 255, 255}, + Assets: assets, + LogLevel: logger.DEBUG, + OnStartup: app.startup, + OnDomReady: app.domReady, + OnShutdown: app.shutdown, + Bind: []interface{}{ + app, + }, + // Windows platform specific options + Windows: &windows.Options{ + WebviewIsTransparent: false, + WindowIsTranslucent: false, + DisableWindowIcon: false, + }, + }) + + if err != nil { + log.Fatal(err) + } +} diff --git a/v2/cmd/wails/internal/template/base/template.json.template b/v2/cmd/wails/internal/commands/generate/template/base/template.template.json similarity index 100% rename from v2/cmd/wails/internal/template/base/template.json.template rename to v2/cmd/wails/internal/commands/generate/template/base/template.template.json diff --git a/v2/cmd/wails/internal/commands/generate/template/base/wails.tmpl.json b/v2/cmd/wails/internal/commands/generate/template/base/wails.tmpl.json new file mode 100644 index 000000000..b8d08108d --- /dev/null +++ b/v2/cmd/wails/internal/commands/generate/template/base/wails.tmpl.json @@ -0,0 +1,11 @@ +{ + "name": "{{.ProjectName}}", + "outputfilename": "{{.BinaryName}}", + "assetdir": "frontend/dist", + "frontend:install": "npm install", + "frontend:build": "npm run build", + "author": { + "name": "{{.AuthorName}}", + "email": "{{.AuthorEmail}}" + } +} diff --git a/v2/cmd/wails/internal/commands/generate/template/template.go b/v2/cmd/wails/internal/commands/generate/template/template.go new file mode 100644 index 000000000..6464ff7c4 --- /dev/null +++ b/v2/cmd/wails/internal/commands/generate/template/template.go @@ -0,0 +1,215 @@ +package template + +import ( + "embed" + "fmt" + "io" + "os" + "path/filepath" + + "github.com/leaanthony/debme" + + "github.com/leaanthony/gosod" + "github.com/wailsapp/wails/v2/internal/fs" + + "github.com/leaanthony/clir" + "github.com/tidwall/sjson" +) + +//go:embed base +var base embed.FS + +func AddSubCommand(app *clir.Cli, parent *clir.Command, w io.Writer) { + + // command + command := parent.NewSubCommand("template", "Generates a wails template") + + name := "" + command.StringFlag("name", "The name of the template", &name) + + existingProjectDir := "" + command.StringFlag("frontend", "A path to an existing frontend project to include in the template", &existingProjectDir) + + // Quiet Init + quiet := false + command.BoolFlag("q", "Suppress output to console", &quiet) + + command.Action(func() error { + + // name is mandatory + if name == "" { + command.PrintHelp() + return fmt.Errorf("no template name given") + } + + // If the current directory is not empty, we create a new directory + cwd, err := os.Getwd() + if err != nil { + return err + } + templateDir := filepath.Join(cwd, name) + if !fs.DirExists(templateDir) { + err := os.MkdirAll(templateDir, 0755) + if err != nil { + return err + } + } + empty, err := fs.DirIsEmpty(templateDir) + if err != nil { + return err + } + if !empty { + templateDir = filepath.Join(cwd, name) + println("Creating new template directory:", name) + err = fs.Mkdir(templateDir) + if err != nil { + return err + } + } + + // Create base template + baseTemplate, err := debme.FS(base, "base") + if err != nil { + return err + } + g := gosod.New(baseTemplate) + g.SetTemplateFilters([]string{".template"}) + + err = os.Chdir(templateDir) + if err != nil { + return err + } + + type templateData struct { + Name string + Description string + TemplateDir string + WailsVersion string + } + + println("Extracting base template files...") + + err = g.Extract(templateDir, &templateData{ + Name: name, + TemplateDir: templateDir, + WailsVersion: app.Version(), + }) + if err != nil { + return err + } + + err = os.Chdir(cwd) + if err != nil { + return err + } + + // If we aren't migrating the files, just exit + if existingProjectDir == "" { + return nil + } + + // Remove frontend directory + frontendDir := filepath.Join(templateDir, "frontend") + err = os.RemoveAll(frontendDir) + if err != nil { + return err + } + + // Copy the files into a new frontend directory + println("Migrating existing project files to frontend directory...") + + sourceDir, err := filepath.Abs(existingProjectDir) + if err != nil { + return err + } + + newFrontendDir := filepath.Join(templateDir, "frontend") + err = fs.CopyDirExtended(sourceDir, newFrontendDir, []string{name, "node_modules"}) + if err != nil { + return err + } + + // Process package.json + err = processPackageJSON(frontendDir) + if err != nil { + return err + } + + // Process package-lock.json + err = processPackageLockJSON(frontendDir) + if err != nil { + return err + } + + // Remove node_modules - ignore error, eg it doesn't exist + _ = os.RemoveAll(filepath.Join(frontendDir, "node_modules")) + + return nil + + }) +} + +func processPackageJSON(frontendDir string) error { + var err error + + packageJSON := filepath.Join(frontendDir, "package.json") + if !fs.FileExists(packageJSON) { + println("No package.json found - cannot process.") + return nil + } + + data, err := os.ReadFile(packageJSON) + if err != nil { + return err + } + json := string(data) + + // We will ignore these errors - it's not critical + println("Updating package.json data...") + json, _ = sjson.Set(json, "name", "{{.ProjectName}}") + json, _ = sjson.Set(json, "author", "{{.AuthorName}}") + + err = os.WriteFile(packageJSON, []byte(json), 0644) + if err != nil { + return err + } + baseDir := filepath.Dir(packageJSON) + println("Renaming package.json -> package.tmpl.json...") + err = os.Rename(packageJSON, filepath.Join(baseDir, "package.tmpl.json")) + if err != nil { + return err + } + return nil +} + +func processPackageLockJSON(frontendDir string) error { + var err error + + filename := filepath.Join(frontendDir, "package-lock.json") + if !fs.FileExists(filename) { + println("No package-lock.json found - cannot process.") + return nil + } + + data, err := os.ReadFile(filename) + if err != nil { + return err + } + json := string(data) + + // We will ignore these errors - it's not critical + println("Updating package-lock.json data...") + json, _ = sjson.Set(json, "name", "{{.ProjectName}}") + + err = os.WriteFile(filename, []byte(json), 0644) + if err != nil { + return err + } + baseDir := filepath.Dir(filename) + println("Renaming package-lock.json -> package-lock.tmpl.json...") + err = os.Rename(filename, filepath.Join(baseDir, "package-lock.tmpl.json")) + if err != nil { + return err + } + return nil +} diff --git a/v2/cmd/wails/internal/commands/initialise/initialise.go b/v2/cmd/wails/internal/commands/initialise/initialise.go new file mode 100644 index 000000000..f87e6b7a3 --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/initialise.go @@ -0,0 +1,235 @@ +package initialise + +import ( + "fmt" + "github.com/flytam/filenamify" + "github.com/leaanthony/slicer" + "io" + "os" + "os/exec" + "path/filepath" + "strings" + "time" + + "github.com/wailsapp/wails/v2/pkg/buildassets" + + "github.com/wailsapp/wails/v2/cmd/wails/internal/commands/initialise/templates" + + "github.com/leaanthony/clir" + "github.com/pkg/errors" + "github.com/wailsapp/wails/v2/pkg/clilogger" + "github.com/wailsapp/wails/v2/pkg/git" +) + +// AddSubcommand adds the `init` command for the Wails application +func AddSubcommand(app *clir.Cli, w io.Writer) error { + + command := app.NewSubCommand("init", "Initialise a new Wails project") + + // Setup template name flag + templateName := "vanilla" + description := "Name of built-in template to use, path to template or template url." + command.StringFlag("t", description, &templateName) + + // Setup project name + projectName := "" + command.StringFlag("n", "Name of project", &projectName) + + // Setup project directory + projectDirectory := "" + command.StringFlag("d", "Project directory", &projectDirectory) + + // Quiet Init + quiet := false + command.BoolFlag("q", "Suppress output to console", &quiet) + + initGit := false + gitInstalled := git.IsInstalled() + if gitInstalled { + // Git Init + command.BoolFlag("g", "Initialise git repository", &initGit) + } + + // VSCode project files + ide := "" + command.StringFlag("ide", "Generate IDE project files", &ide) + + // List templates + list := false + command.BoolFlag("l", "List templates", &list) + + command.Action(func() error { + + // Create logger + logger := clilogger.New(w) + logger.Mute(quiet) + + // Are we listing templates? + if list { + app.PrintBanner() + err := templates.OutputList(logger) + logger.Println("") + return err + } + + // Validate name + if len(projectName) == 0 { + logger.Println("ERROR: Project name required") + logger.Println("") + command.PrintHelp() + return nil + } + + // Validate IDE option + supportedIDEs := slicer.String([]string{"vscode", "goland"}) + ide = strings.ToLower(ide) + if ide != "" { + if !supportedIDEs.Contains(ide) { + return fmt.Errorf("ide '%s' not supported. Valid values: %s", ide, supportedIDEs.Join(" ")) + } + } + + if !quiet { + app.PrintBanner() + } + + task := fmt.Sprintf("Initialising Project %s", strings.Title(projectName)) + logger.Println(task) + logger.Println(strings.Repeat("-", len(task))) + + projectFilename, err := filenamify.Filenamify(projectName, filenamify.Options{ + Replacement: "_", + MaxLength: 255, + }) + if err != nil { + return err + } + goBinary, err := exec.LookPath("go") + if err != nil { + return fmt.Errorf("unable to find Go compiler. Please download and install Go: https://golang.org/dl/") + } + + // Get base path and convert to forward slashes + goPath := filepath.ToSlash(filepath.Dir(goBinary)) + // Trim bin directory + goSDKPath := strings.TrimSuffix(goPath, "/bin") + + // Create Template Options + options := &templates.Options{ + ProjectName: projectName, + TargetDir: projectDirectory, + TemplateName: templateName, + Logger: logger, + IDE: ide, + InitGit: initGit, + ProjectNameFilename: projectFilename, + WailsVersion: app.Version(), + GoSDKPath: goSDKPath, + } + + // Try to discover author details from git config + findAuthorDetails(options) + + return initProject(options, quiet) + }) + + return nil +} + +// initProject is our main init command +func initProject(options *templates.Options, quiet bool) error { + + // Start Time + start := time.Now() + + // Install the template + remote, template, err := templates.Install(options) + if err != nil { + return err + } + + // Install the default assets + err = buildassets.Install(options.TargetDir, options.ProjectName) + if err != nil { + return err + } + + // Run `go mod tidy` to ensure `go.sum` is up to date + cmd := exec.Command("go", "mod", "tidy") + cmd.Dir = options.TargetDir + cmd.Stderr = os.Stderr + if !quiet { + println("") + cmd.Stdout = os.Stdout + } + err = cmd.Run() + if err != nil { + return err + } + + if options.InitGit { + err = initGit(options) + if err != nil { + return err + } + } + + if quiet { + return nil + } + + // Output stats + elapsed := time.Since(start) + options.Logger.Println("") + options.Logger.Println("Project Name: " + options.ProjectName) + options.Logger.Println("Project Directory: " + options.TargetDir) + options.Logger.Println("Project Template: " + options.TemplateName) + options.Logger.Println("Template Support: " + template.HelpURL) + + // IDE message + switch options.IDE { + case "vscode": + options.Logger.Println("VSCode config files generated.") + case "goland": + options.Logger.Println("Goland config files generated.") + } + + if options.InitGit { + options.Logger.Println("Git repository initialised.") + } + + if remote { + options.Logger.Println("\nNOTE: You have created a project using a remote template. The Wails project takes no responsibility for 3rd party templates. Only use remote templates that you trust.") + } + + options.Logger.Println("") + options.Logger.Println(fmt.Sprintf("Initialised project '%s' in %s.", options.ProjectName, elapsed.Round(time.Millisecond).String())) + options.Logger.Println("") + + return nil +} + +func initGit(options *templates.Options) error { + err := git.InitRepo(options.TargetDir) + if err != nil { + return errors.Wrap(err, "Unable to initialise git repository:") + } + + return nil +} + +// findAuthorDetails tries to find the user's name and email +// from gitconfig. If it finds them, it stores them in the project options +func findAuthorDetails(options *templates.Options) { + if git.IsInstalled() { + name, err := git.Name() + if err == nil { + options.AuthorName = strings.TrimSpace(name) + } + + email, err := git.Email() + if err == nil { + options.AuthorEmail = strings.TrimSpace(email) + } + } +} diff --git a/v2/pkg/templates/ides/goland/gitignore.txt b/v2/cmd/wails/internal/commands/initialise/templates/ides/goland/gitignore.txt similarity index 100% rename from v2/pkg/templates/ides/goland/gitignore.txt rename to v2/cmd/wails/internal/commands/initialise/templates/ides/goland/gitignore.txt diff --git a/v2/pkg/templates/ides/goland/modules.tmpl.xml b/v2/cmd/wails/internal/commands/initialise/templates/ides/goland/modules.tmpl.xml similarity index 100% rename from v2/pkg/templates/ides/goland/modules.tmpl.xml rename to v2/cmd/wails/internal/commands/initialise/templates/ides/goland/modules.tmpl.xml diff --git a/v2/pkg/templates/ides/goland/name.tmpl b/v2/cmd/wails/internal/commands/initialise/templates/ides/goland/name.tmpl similarity index 100% rename from v2/pkg/templates/ides/goland/name.tmpl rename to v2/cmd/wails/internal/commands/initialise/templates/ides/goland/name.tmpl diff --git a/v2/pkg/templates/ides/goland/projectname.iml b/v2/cmd/wails/internal/commands/initialise/templates/ides/goland/projectname.iml similarity index 100% rename from v2/pkg/templates/ides/goland/projectname.iml rename to v2/cmd/wails/internal/commands/initialise/templates/ides/goland/projectname.iml diff --git a/v2/pkg/templates/ides/goland/vcs.xml b/v2/cmd/wails/internal/commands/initialise/templates/ides/goland/vcs.xml similarity index 100% rename from v2/pkg/templates/ides/goland/vcs.xml rename to v2/cmd/wails/internal/commands/initialise/templates/ides/goland/vcs.xml diff --git a/v2/pkg/templates/ides/goland/workspace.tmpl.xml b/v2/cmd/wails/internal/commands/initialise/templates/ides/goland/workspace.tmpl.xml similarity index 81% rename from v2/pkg/templates/ides/goland/workspace.tmpl.xml rename to v2/cmd/wails/internal/commands/initialise/templates/ides/goland/workspace.tmpl.xml index 27f8881bf..42f98045b 100644 --- a/v2/pkg/templates/ides/goland/workspace.tmpl.xml +++ b/v2/cmd/wails/internal/commands/initialise/templates/ides/goland/workspace.tmpl.xml @@ -30,32 +30,15 @@ - > + > + - - - - - - - - - - - - - - - - @@ -72,7 +55,6 @@ - diff --git a/v2/cmd/wails/internal/commands/initialise/templates/ides/vscode/launch.tmpl.json b/v2/cmd/wails/internal/commands/initialise/templates/ides/vscode/launch.tmpl.json new file mode 100644 index 000000000..d03d5ccdb --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/ides/vscode/launch.tmpl.json @@ -0,0 +1,19 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Wails: Debug {{.ProjectName}}", + "type": "go", + "request": "launch", + "mode": "exec", + "program": "${workspaceFolder}/{{.PathToDesktopBinary}}", + "preLaunchTask": "build", + "cwd": "${workspaceFolder}", + "env": {}, + "args": [ + "-assetdir", + "{{.AssetDir}}" + ] + } + ] +} \ No newline at end of file diff --git a/v2/cmd/wails/internal/commands/initialise/templates/ides/vscode/tasks.tmpl.json b/v2/cmd/wails/internal/commands/initialise/templates/ides/vscode/tasks.tmpl.json new file mode 100644 index 000000000..03c37e115 --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/ides/vscode/tasks.tmpl.json @@ -0,0 +1,23 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "type": "shell", + "options": { + "cwd": "${workspaceFolder}" + }, + "command": "go", + "args": [ + "build", + "-tags", + "dev", + "-gcflags", + "all=-N -l", + "-o", + "{{.PathToDesktopBinary}}" + ] + } + ] +} + \ No newline at end of file diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates.go b/v2/cmd/wails/internal/commands/initialise/templates/templates.go new file mode 100644 index 000000000..e01fecfb4 --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates.go @@ -0,0 +1,442 @@ +package templates + +import ( + "embed" + "encoding/json" + "fmt" + "github.com/go-git/go-git/v5" + gofs "io/fs" + "io/ioutil" + "log" + "os" + "path/filepath" + "runtime" + "strings" + + "github.com/pkg/errors" + + "github.com/leaanthony/debme" + "github.com/leaanthony/gosod" + "github.com/olekukonko/tablewriter" + "github.com/wailsapp/wails/v2/internal/fs" + "github.com/wailsapp/wails/v2/pkg/clilogger" +) + +//go:embed templates +var templates embed.FS + +//go:embed ides/* +var ides embed.FS + +// Cahce for the templates +// We use this because we need different views of the same data +var templateCache []Template = nil + +// Data contains the data we wish to embed during template installation +type Data struct { + ProjectName string + BinaryName string + WailsVersion string + NPMProjectName string + AuthorName string + AuthorEmail string + AuthorNameAndEmail string + WailsDirectory string + GoSDKPath string + AssetDir string + WindowsFlags string + CGOEnabled string + OutputFile string +} + +// Options for installing a template +type Options struct { + ProjectName string + TemplateName string + BinaryName string + TargetDir string + Logger *clilogger.CLILogger + PathToDesktopBinary string + PathToServerBinary string + InitGit bool + AuthorName string + AuthorEmail string + AssetDir string + IDE string + ProjectNameFilename string // The project name but as a valid filename + WailsVersion string + GoSDKPath string + WindowsFlags string + CGOEnabled string + OutputFile string +} + +// Template holds data relating to a template +// including the metadata stored in template.json +type Template struct { + + // Template details + Name string `json:"name"` + ShortName string `json:"shortname"` + Author string `json:"author"` + Description string `json:"description"` + HelpURL string `json:"helpurl"` + + // Other data + FS gofs.FS `json:"-"` +} + +func parseTemplate(template gofs.FS) (Template, error) { + var result Template + data, err := gofs.ReadFile(template, "template.json") + if err != nil { + return result, errors.Wrap(err, "Error parsing template") + } + err = json.Unmarshal(data, &result) + if err != nil { + return result, err + } + result.FS = template + return result, nil +} + +// List returns the list of available templates +func List() ([]Template, error) { + + // If the cache isn't loaded, load it + if templateCache == nil { + err := loadTemplateCache() + if err != nil { + return nil, err + } + } + + return templateCache, nil +} + +// getTemplateByShortname returns the template with the given short name +func getTemplateByShortname(shortname string) (Template, error) { + + var result Template + + // If the cache isn't loaded, load it + if templateCache == nil { + err := loadTemplateCache() + if err != nil { + return result, err + } + } + + for _, template := range templateCache { + if template.ShortName == shortname { + return template, nil + } + } + + return result, fmt.Errorf("shortname '%s' is not a valid template shortname", shortname) +} + +// Loads the template cache +func loadTemplateCache() error { + + templatesFS, err := debme.FS(templates, "templates") + if err != nil { + return err + } + + // Get directories + files, err := templatesFS.ReadDir(".") + if err != nil { + return err + } + + // Reset cache + templateCache = []Template{} + + for _, file := range files { + if file.IsDir() { + templateFS, err := templatesFS.FS(file.Name()) + if err != nil { + return err + } + template, err := parseTemplate(templateFS) + if err != nil { + // Cannot parse this template, continue + continue + } + templateCache = append(templateCache, template) + } + } + + return nil +} + +// Install the given template. Returns true if the template is remote. +func Install(options *Options) (bool, *Template, error) { + // Get cwd + cwd, err := os.Getwd() + if err != nil { + return false, nil, err + } + + // Did the user want to install in current directory? + if options.TargetDir == "" { + options.TargetDir = filepath.Join(cwd, options.ProjectName) + if fs.DirExists(options.TargetDir) { + return false, nil, fmt.Errorf("cannot create project directory. Dir exists: %s", options.TargetDir) + } + } else { + // Get the absolute path of the given directory + targetDir, err := filepath.Abs(filepath.Join(cwd, options.TargetDir)) + if err != nil { + return false, nil, err + } + options.TargetDir = targetDir + if !fs.DirExists(options.TargetDir) { + err := fs.Mkdir(options.TargetDir) + if err != nil { + return false, nil, err + } + } + } + + // Flag to indicate remote template + remoteTemplate := false + + // Is this a shortname? + template, err := getTemplateByShortname(options.TemplateName) + if err != nil { + // Is this a filepath? + templatePath, err := filepath.Abs(options.TemplateName) + if fs.DirExists(templatePath) { + templateFS := os.DirFS(templatePath) + template, err = parseTemplate(templateFS) + if err != nil { + return false, nil, errors.Wrap(err, "Error installing template") + } + } else { + // git clone to temporary dir + tempdir, err := gitclone(options) + defer func(path string) { + err := os.RemoveAll(path) + if err != nil { + log.Fatal(err) + } + }(tempdir) + if err != nil { + return false, nil, err + } + // Remove the .git directory + err = os.RemoveAll(filepath.Join(tempdir, ".git")) + if err != nil { + return false, nil, err + } + + templateFS := os.DirFS(tempdir) + template, err = parseTemplate(templateFS) + if err != nil { + return false, nil, err + } + remoteTemplate = true + } + } + + // Use Gosod to install the template + installer := gosod.New(template.FS) + + // Ignore template.json files + installer.IgnoreFile("template.json") + + // Setup the data. + // We use the directory name for the binary name, like Go + BinaryName := filepath.Base(options.TargetDir) + NPMProjectName := strings.ToLower(strings.ReplaceAll(BinaryName, " ", "")) + localWailsDirectory := fs.RelativePath("../../../../../..") + + templateData := &Data{ + ProjectName: options.ProjectName, + BinaryName: filepath.Base(options.TargetDir), + NPMProjectName: NPMProjectName, + WailsDirectory: localWailsDirectory, + AuthorEmail: options.AuthorEmail, + AuthorName: options.AuthorName, + WailsVersion: options.WailsVersion, + GoSDKPath: options.GoSDKPath, + AssetDir: options.AssetDir, + } + + // Create a formatted name and email combo. + if options.AuthorName != "" { + templateData.AuthorNameAndEmail = options.AuthorName + " " + } + if options.AuthorEmail != "" { + templateData.AuthorNameAndEmail += "<" + options.AuthorEmail + ">" + } + templateData.AuthorNameAndEmail = strings.TrimSpace(templateData.AuthorNameAndEmail) + + installer.RenameFiles(map[string]string{ + "gitignore.txt": ".gitignore", + }) + + // Extract the template + err = installer.Extract(options.TargetDir, templateData) + if err != nil { + return false, nil, err + } + + err = generateIDEFiles(options) + if err != nil { + return false, nil, err + } + + return remoteTemplate, &template, nil +} + +// Clones the given uri and returns the temporary cloned directory +func gitclone(options *Options) (string, error) { + // Create temporary directory + dirname, err := ioutil.TempDir("", "wails-template-*") + if err != nil { + return "", err + } + _, err = git.PlainClone(dirname, false, &git.CloneOptions{ + URL: options.TemplateName, + }) + + return dirname, err + +} + +// OutputList prints the list of available tempaltes to the given logger +func OutputList(logger *clilogger.CLILogger) error { + templates, err := List() + if err != nil { + return err + } + + table := tablewriter.NewWriter(logger.Writer) + table.SetHeader([]string{"Template", "Short Name", "Description"}) + table.SetAutoWrapText(false) + table.SetAutoFormatHeaders(true) + table.SetHeaderAlignment(tablewriter.ALIGN_LEFT) + table.SetAlignment(tablewriter.ALIGN_LEFT) + table.SetCenterSeparator("") + table.SetColumnSeparator("") + table.SetRowSeparator("") + table.SetHeaderLine(false) + table.SetBorder(false) + table.SetTablePadding("\t") // pad with tabs + table.SetNoWhiteSpace(true) + for _, template := range templates { + table.Append([]string{template.Name, template.ShortName, template.Description}) + } + table.Render() + return nil +} + +func generateIDEFiles(options *Options) error { + + switch options.IDE { + case "vscode": + return generateVSCodeFiles(options) + case "goland": + return generateGolandFiles(options) + } + + return nil +} + +type ideOptions struct { + name string + targetDir string + options *Options + renameFiles map[string]string + ignoredFiles []string +} + +func generateGolandFiles(options *Options) error { + ideoptions := ideOptions{ + name: "goland", + targetDir: filepath.Join(options.TargetDir, ".idea"), + options: options, + renameFiles: map[string]string{ + "projectname.iml": options.ProjectNameFilename + ".iml", + "gitignore.txt": ".gitignore", + "name": ".name", + }, + } + if !options.InitGit { + ideoptions.ignoredFiles = []string{"vcs.xml"} + } + err := installIDEFiles(ideoptions) + if err != nil { + return errors.Wrap(err, "generating Goland IDE files") + } + + return nil +} + +func generateVSCodeFiles(options *Options) error { + ideoptions := ideOptions{ + name: "vscode", + targetDir: filepath.Join(options.TargetDir, ".vscode"), + options: options, + } + return installIDEFiles(ideoptions) + +} + +func installIDEFiles(o ideOptions) error { + source, err := debme.FS(ides, "ides/"+o.name) + if err != nil { + return err + } + + // Use gosod to install the template + installer := gosod.New(source) + + if o.renameFiles != nil { + installer.RenameFiles(o.renameFiles) + } + + for _, ignoreFile := range o.ignoredFiles { + installer.IgnoreFile(ignoreFile) + } + + binaryName := filepath.Base(o.options.TargetDir) + if runtime.GOOS == "windows" { + // yay windows + binaryName += ".exe" + } + + // Parse wails.json for assetdir + wailsJSONBytes, err := os.ReadFile(filepath.Join(o.options.TargetDir, "wails.json")) + if err != nil { + return err + } + var wailsJSON map[string]interface{} + err = json.Unmarshal(wailsJSONBytes, &wailsJSON) + if err != nil { + return err + } + assetDir := wailsJSON["assetdir"] + if assetDir == "" { + return fmt.Errorf("Unable to find 'assetdir' in 'wails.json' ") + } + + o.options.AssetDir = assetDir.(string) + o.options.PathToDesktopBinary = filepath.ToSlash(filepath.Join("build", "bin", binaryName)) + + o.options.WindowsFlags = "" + o.options.CGOEnabled = "1" + if runtime.GOOS == "windows" { + o.options.WindowsFlags = " -H windowsgui" + o.options.CGOEnabled = "0" + } + err = installer.Extract(o.targetDir, o.options) + if err != nil { + return err + } + + return nil +} diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/README.md b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/README.md new file mode 100644 index 000000000..45c57ab69 --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/README.md @@ -0,0 +1,22 @@ +# README + +## About + +This is a basic Svelte template, using rollup to bundle the assets into a single JS file. +Rollup is configured to do the following: + +- Convert imported images to base64 strings +- Convert `url()` in `@font-face` declarations to base64 strings +- Bundle all css into the JS bundle +- Copy `index.html` from `frontend/src/` to `frontend/dist/` + +Clicking the button will call the backend. + +## Live Development + +To run in live development mode, run `wails dev` in the project directory. The frontend dev server will run +on http://localhost:34115. Open this in your browser to connect to your application. + +## Building + +For a production build, use `wails build`. diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/app.go b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/app.go new file mode 100644 index 000000000..d03f9fc11 --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/app.go @@ -0,0 +1,37 @@ +package main + +import ( + "context" + "fmt" +) + +// App application struct +type App struct { + ctx context.Context +} + +// NewApp creates a new App application struct +func NewApp() *App { + return &App{} +} + +// startup is called at application startup +func (b *App) startup(ctx context.Context) { + // Perform your setup here + b.ctx = ctx +} + +// domReady is called after the front-end dom has been loaded +func (b *App) domReady(ctx context.Context) { + // Add your action here +} + +// shutdown is called at application termination +func (b *App) shutdown(ctx context.Context) { + // Perform your teardown here +} + +// Greet returns a greeting for the given name +func (b *App) Greet(name string) string { + return fmt.Sprintf("Hello %s!", name) +} diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/.gitignore b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/.gitignore new file mode 100644 index 000000000..ba0af2a15 --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/.gitignore @@ -0,0 +1,4 @@ +/node_modules/ +/dist/build/ + +.DS_Store diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/README.md b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/README.md new file mode 100644 index 000000000..7b1ba8363 --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/README.md @@ -0,0 +1,105 @@ +*Looking for a shareable component template? Go here --> [sveltejs/component-template](https://github.com/sveltejs/component-template)* + +--- + +# svelte app + +This is a project template for [Svelte](https://svelte.dev) apps. It lives at https://github.com/sveltejs/template. + +To create a new project based on this template using [degit](https://github.com/Rich-Harris/degit): + +```bash +npx degit sveltejs/template svelte-app +cd svelte-app +``` + +*Note that you will need to have [Node.js](https://nodejs.org) installed.* + + +## Get started + +Install the dependencies... + +```bash +cd svelte-app +npm install +``` + +...then start [Rollup](https://rollupjs.org): + +```bash +npm run dev +``` + +Navigate to [localhost:5000](http://localhost:5000). You should see your app running. Edit a component file in `src`, save it, and reload the page to see your changes. + +By default, the server will only respond to requests from localhost. To allow connections from other computers, edit the `sirv` commands in package.json to include the option `--host 0.0.0.0`. + +If you're using [Visual Studio Code](https://code.visualstudio.com/) we recommend installing the official extension [Svelte for VS Code](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode). If you are using other editors you may need to install a plugin in order to get syntax highlighting and intellisense. + +## Building and running in production mode + +To create an optimised version of the app: + +```bash +npm run build +``` + +You can run the newly built app with `npm run start`. This uses [sirv](https://github.com/lukeed/sirv), which is included in your package.json's `dependencies` so that the app will work when you deploy to platforms like [Heroku](https://heroku.com). + + +## Single-page app mode + +By default, sirv will only respond to requests that match files in `public`. This is to maximise compatibility with static fileservers, allowing you to deploy your app anywhere. + +If you're building a single-page app (SPA) with multiple routes, sirv needs to be able to respond to requests for *any* path. You can make it so by editing the `"start"` command in package.json: + +```js +"start": "sirv public --single" +``` + +## Using TypeScript + +This template comes with a script to set up a TypeScript development environment, you can run it immediately after cloning the template with: + +```bash +node scripts/setupTypeScript.js +``` + +Or remove the script via: + +```bash +rm scripts/setupTypeScript.js +``` + +## Deploying to the web + +### With [Vercel](https://vercel.com) + +Install `vercel` if you haven't already: + +```bash +npm install -g vercel +``` + +Then, from within your project folder: + +```bash +cd public +vercel deploy --name my-project +``` + +### With [surge](https://surge.sh/) + +Install `surge` if you haven't already: + +```bash +npm install -g surge +``` + +Then, from within your project folder: + +```bash +npm run build +surge public my-project.surge.sh +``` diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/dist/index.html b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/dist/index.html new file mode 100644 index 000000000..58f98f0d1 --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/dist/index.html @@ -0,0 +1 @@ + diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/package-lock.tmpl.json b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/package-lock.tmpl.json new file mode 100644 index 000000000..f5c7c84cc --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/package-lock.tmpl.json @@ -0,0 +1,3638 @@ +{ + "name": "{{.ProjectName}}", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", + "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.14.5" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", + "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==", + "dev": true + }, + "@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.7.tgz", + "integrity": "sha512-BTIhocbPBSrRmHxOAJFtR18oLhxTtAFDAvL8hY1S3iU8k+E60W/YFs4jrixGzQjMpF4qPXxIQHcjVD9dz1C2QA==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@polka/url": { + "version": "1.0.0-next.15", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.15.tgz", + "integrity": "sha512-15spi3V28QdevleWBNXE4pIls3nFZmBbUGrW9IVPwiQczuSb9n76TCB4bsk8TSel+I1OkHEdPhu5QKMfY6rQHA==" + }, + "@rollup/plugin-commonjs": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-17.1.0.tgz", + "integrity": "sha512-PoMdXCw0ZyvjpCMT5aV4nkL0QywxP29sODQsSGeDpr/oI49Qq9tRtAsb/LbYbDzFlOydVEqHmmZWFtXJEAX9ew==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.1.0", + "commondir": "^1.0.1", + "estree-walker": "^2.0.1", + "glob": "^7.1.6", + "is-reference": "^1.2.1", + "magic-string": "^0.25.7", + "resolve": "^1.17.0" + } + }, + "@rollup/plugin-image": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@rollup/plugin-image/-/plugin-image-2.0.6.tgz", + "integrity": "sha512-bB+spXogbPiFjhBS7i8ajUOgOnVwWK3bnJ6VroxKey/q8/EPRkoSh+4O1qPCw97qMIDspF4TlzXVBhZ7nojIPw==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.1.0", + "mini-svg-data-uri": "^1.2.3" + } + }, + "@rollup/plugin-node-resolve": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", + "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "builtin-modules": "^3.1.0", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.19.0" + } + }, + "@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, + "requires": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "dependencies": { + "estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true + } + } + }, + "@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + }, + "@types/fs-extra": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.1.tgz", + "integrity": "sha512-TcUlBem321DFQzBNuz8p0CLLKp0VvF/XH9E4KHNmgwyp4E3AfgI5cjiIVZWlbfThBop2qxFIh4+LeY6hVWWZ2w==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", + "dev": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==", + "dev": true + }, + "@types/node": { + "version": "15.12.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.5.tgz", + "integrity": "sha512-se3yX7UHv5Bscf8f1ERKvQOD6sTyycH3hdaoozvaLxgUiY5lIGEeH37AD0G0Qi9kPqihPn0HOfd2yaIEN9VwEg==", + "dev": true + }, + "@types/q": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz", + "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==", + "dev": true + }, + "@types/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "alphanum-sort": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", + "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browserslist": { + "version": "4.16.6", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", + "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001219", + "colorette": "^1.2.2", + "electron-to-chromium": "^1.3.723", + "escalade": "^3.1.1", + "node-releases": "^1.1.71" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "builtin-modules": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz", + "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==", + "dev": true + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "dev": true, + "requires": { + "callsites": "^2.0.0" + } + }, + "caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "dev": true, + "requires": { + "caller-callsite": "^2.0.0" + } + }, + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "dev": true + }, + "caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "caniuse-lite": { + "version": "1.0.30001241", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001241.tgz", + "integrity": "sha512-1uoSZ1Pq1VpH0WerIMqwptXHNNGfdl7d1cJUFs80CwQ/lVzdhTvsFZCeNFslze7AjsQnb4C85tzclPa1VShbeQ==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chokidar": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "coa": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", + "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", + "dev": true, + "requires": { + "@types/q": "^1.5.1", + "chalk": "^2.4.1", + "q": "^1.1.2" + } + }, + "color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/color/-/color-3.1.3.tgz", + "integrity": "sha512-xgXAcTHa2HeFCGLE9Xs/R82hujGtu9Jd9x4NW3T34+OMs7VoPsjwzRczKHvTAHeJwWFwX5j15+MgAppE8ztObQ==", + "dev": true, + "requires": { + "color-convert": "^1.9.1", + "color-string": "^1.5.4" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "color-string": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.5.tgz", + "integrity": "sha512-jgIoum0OfQfq9Whcfc2z/VhCNcmQjWbey6qBX0vqt7YICflUmBCh9E9CiQD5GSJ+Uehixm3NUwHVhqUAWRivZg==", + "dev": true, + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "colorette": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", + "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", + "dev": true + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-with-sourcemaps": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz", + "integrity": "sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==", + "dev": true, + "requires": { + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "console-clear": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/console-clear/-/console-clear-1.1.1.tgz", + "integrity": "sha512-pMD+MVR538ipqkG5JXeOEbKWS5um1H4LUUccUQG68qpeqBYbzYy79Gh55jkd2TtPdRfUaLWdv6LPP//5Zt0aPQ==" + }, + "cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dev": true, + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + } + }, + "css-color-names": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", + "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", + "dev": true + }, + "css-declaration-sorter": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", + "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", + "dev": true, + "requires": { + "postcss": "^7.0.1", + "timsort": "^0.3.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "css-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", + "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^3.2.1", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + } + }, + "css-select-base-adapter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", + "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==", + "dev": true + }, + "css-tree": { + "version": "1.0.0-alpha.37", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", + "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", + "dev": true, + "requires": { + "mdn-data": "2.0.4", + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "css-what": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", + "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==", + "dev": true + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true + }, + "cssnano": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.11.tgz", + "integrity": "sha512-6gZm2htn7xIPJOHY824ERgj8cNPgPxyCSnkXc4v7YvNW+TdVfzgngHcEhy/8D11kUWRUMbke+tC+AUcUsnMz2g==", + "dev": true, + "requires": { + "cosmiconfig": "^5.0.0", + "cssnano-preset-default": "^4.0.8", + "is-resolvable": "^1.0.0", + "postcss": "^7.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "cssnano-preset-default": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.8.tgz", + "integrity": "sha512-LdAyHuq+VRyeVREFmuxUZR1TXjQm8QQU/ktoo/x7bz+SdOge1YKc5eMN6pRW7YWBmyq59CqYba1dJ5cUukEjLQ==", + "dev": true, + "requires": { + "css-declaration-sorter": "^4.0.1", + "cssnano-util-raw-cache": "^4.0.1", + "postcss": "^7.0.0", + "postcss-calc": "^7.0.1", + "postcss-colormin": "^4.0.3", + "postcss-convert-values": "^4.0.1", + "postcss-discard-comments": "^4.0.2", + "postcss-discard-duplicates": "^4.0.2", + "postcss-discard-empty": "^4.0.1", + "postcss-discard-overridden": "^4.0.1", + "postcss-merge-longhand": "^4.0.11", + "postcss-merge-rules": "^4.0.3", + "postcss-minify-font-values": "^4.0.2", + "postcss-minify-gradients": "^4.0.2", + "postcss-minify-params": "^4.0.2", + "postcss-minify-selectors": "^4.0.2", + "postcss-normalize-charset": "^4.0.1", + "postcss-normalize-display-values": "^4.0.2", + "postcss-normalize-positions": "^4.0.2", + "postcss-normalize-repeat-style": "^4.0.2", + "postcss-normalize-string": "^4.0.2", + "postcss-normalize-timing-functions": "^4.0.2", + "postcss-normalize-unicode": "^4.0.1", + "postcss-normalize-url": "^4.0.1", + "postcss-normalize-whitespace": "^4.0.2", + "postcss-ordered-values": "^4.1.2", + "postcss-reduce-initial": "^4.0.3", + "postcss-reduce-transforms": "^4.0.2", + "postcss-svgo": "^4.0.3", + "postcss-unique-selectors": "^4.0.1" + }, + "dependencies": { + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "cssnano-util-get-arguments": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz", + "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=", + "dev": true + }, + "cssnano-util-get-match": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz", + "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=", + "dev": true + }, + "cssnano-util-raw-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz", + "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "cssnano-util-same-parent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz", + "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==", + "dev": true + }, + "csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dev": true, + "requires": { + "css-tree": "^1.1.2" + }, + "dependencies": { + "css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dev": true, + "requires": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + } + }, + "mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "cuint": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz", + "integrity": "sha1-QICG1AlVDCYxFVYZ6fp7ytw7mRs=", + "dev": true + }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + }, + "dependencies": { + "domelementtype": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", + "dev": true + } + } + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "dev": true + }, + "domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "dev": true, + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "requires": { + "is-obj": "^2.0.0" + } + }, + "electron-to-chromium": { + "version": "1.3.762", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.762.tgz", + "integrity": "sha512-LehWjRpfPcK8F1Lf/NZoAwWLWnjJVo0SZeQ9j/tvnBWYcT99qDqgo4raAfS2oTKZjPrR/jxruh85DGgDUmywEA==", + "dev": true + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", + "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "is-callable": "^1.2.3", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.3", + "is-string": "^1.0.6", + "object-inspect": "^1.10.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true + }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "fast-glob": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.6.tgz", + "integrity": "sha512-GnLuqj/pvQ7pX8/L4J84nijv6sAnlwvSDpMkJi9i7nPmPxGtRPkBSStfvDW5l6nMdX9VWe+pkKWFTgD+vF2QSQ==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, + "fastq": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", + "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "generic-names": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generic-names/-/generic-names-2.0.1.tgz", + "integrity": "sha512-kPCHWa1m9wGG/OwQpeweTwM/PYiQLrUIxXbt/P4Nic3LbGjCP0YwrALHW1uNLKZ0LIMg+RF+XRlj2ekT9ZlZAQ==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0" + } + }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "get-port": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", + "integrity": "sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw=" + }, + "glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globby": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz", + "integrity": "sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "dev": true + }, + "hex-color-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", + "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==", + "dev": true + }, + "hsl-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz", + "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=", + "dev": true + }, + "hsla-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz", + "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=", + "dev": true + }, + "icss-replace-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", + "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=", + "dev": true + }, + "icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true + }, + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true + }, + "import-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-3.0.0.tgz", + "integrity": "sha512-4pnzH16plW+hgvRECbDWpQl3cqtvSofHWh44met7ESfZ8UZOWWddm8hEyDTqREJ9RbYHY8gi8DqmaelApoOGMg==", + "dev": true, + "requires": { + "import-from": "^3.0.0" + } + }, + "import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "dev": true, + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + } + }, + "import-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-3.0.0.tgz", + "integrity": "sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + } + } + }, + "indexes-of": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", + "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-absolute-url": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", + "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-bigint": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz", + "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-boolean-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz", + "integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-callable": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", + "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", + "dev": true + }, + "is-color-stop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz", + "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=", + "dev": true, + "requires": { + "css-color-names": "^0.0.4", + "hex-color-regex": "^1.1.0", + "hsl-regex": "^1.0.0", + "hsla-regex": "^1.0.0", + "rgb-regex": "^1.0.1", + "rgba-regex": "^1.0.0" + } + }, + "is-core-module": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", + "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-date-object": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.4.tgz", + "integrity": "sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A==", + "dev": true + }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", + "dev": true + }, + "is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-number-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz", + "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==", + "dev": true + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true + }, + "is-plain-object": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz", + "integrity": "sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==", + "dev": true + }, + "is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "dev": true, + "requires": { + "@types/estree": "*" + } + }, + "is-regex": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", + "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-symbols": "^1.0.2" + } + }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", + "dev": true + }, + "is-string": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", + "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==", + "dev": true + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "jest-worker": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" + }, + "lilconfig": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.3.tgz", + "integrity": "sha512-EHKqr/+ZvdKCifpNrJCKxBTgk5XupZA3y/aCPY9mxfgBzmgh93Mt/WqjjQ38oMxXuvDokaKiM3lAgvSH2sjtHg==", + "dev": true + }, + "livereload": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/livereload/-/livereload-0.9.3.tgz", + "integrity": "sha512-q7Z71n3i4X0R9xthAryBdNGVGAO2R5X+/xXpmKeuPMrteg+W2U8VusTKV3YiJbXZwKsOlFlHe+go6uSNjfxrZw==", + "dev": true, + "requires": { + "chokidar": "^3.5.0", + "livereload-js": "^3.3.1", + "opts": ">= 1.2.0", + "ws": "^7.4.3" + } + }, + "livereload-js": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-3.3.2.tgz", + "integrity": "sha512-w677WnINxFkuixAoUEXOStewzLYGI76XVag+0JWMMEyjJQKs0ibWZMxkTlB96Lm3EjZ7IeOxVziBEbtxVQqQZA==", + "dev": true + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + }, + "local-access": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/local-access/-/local-access-1.1.0.tgz", + "integrity": "sha512-XfegD5pyTAfb+GY6chk283Ox5z8WexG56OvM06RWLpAc/UHozO8X6xAxEkIitZOtsSMM1Yr3DkHgW5W+onLhCw==" + }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", + "dev": true + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", + "dev": true + }, + "magic-string": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", + "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "dev": true, + "requires": { + "sourcemap-codec": "^1.4.4" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "mdn-data": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", + "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", + "dev": true + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + } + }, + "mime": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", + "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==" + }, + "mini-svg-data-uri": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.3.3.tgz", + "integrity": "sha512-+fA2oRcR1dJI/7ITmeQJDrYWks0wodlOz0pAEhKYJ2IVc1z0AnwJUsKY2fzFmPAM3Jo9J0rBx8JAA9QQSJ5PuA==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "mri": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.6.tgz", + "integrity": "sha512-oi1b3MfbyGa7FJMP9GmLTttni5JoICpYBRlq+x5V16fZbLsnL9N3wFqqIm/nIG43FjUFkFh9Epzp/kzUGUnJxQ==" + }, + "nanoid": { + "version": "3.1.23", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz", + "integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==", + "dev": true + }, + "node-releases": { + "version": "1.1.73", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz", + "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-url": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", + "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==", + "dev": true + }, + "nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "dev": true, + "requires": { + "boolbase": "~1.0.0" + } + }, + "object-inspect": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", + "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz", + "integrity": "sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2" + } + }, + "object.values": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.4.tgz", + "integrity": "sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.2" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "opts": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/opts/-/opts-2.0.2.tgz", + "integrity": "sha512-k41FwbcLnlgnFh69f4qdUfvDQ+5vaSDnVPFI/y5XuhKRq97EnVVneO9F1ESVCdiVu4fCS2L8usX3mU331hB7pg==", + "dev": true + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-queue": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", + "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", + "dev": true, + "requires": { + "eventemitter3": "^4.0.4", + "p-timeout": "^3.2.0" + } + }, + "p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "dev": true, + "requires": { + "p-finally": "^1.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true + }, + "pify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz", + "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", + "dev": true + }, + "postcss": { + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.5.tgz", + "integrity": "sha512-NxTuJocUhYGsMiMFHDUkmjSKT3EdH4/WbGF6GCi1NDGk+vbcUTun4fpbOqaPtD8IIsztA2ilZm2DhYCuyN58gA==", + "dev": true, + "requires": { + "colorette": "^1.2.2", + "nanoid": "^3.1.23", + "source-map-js": "^0.6.2" + } + }, + "postcss-calc": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.5.tgz", + "integrity": "sha512-1tKHutbGtLtEZF6PT4JSihCHfIVldU72mZ8SdZHIYriIZ9fh9k9aWSppaT8rHsyI3dX+KSR+W+Ix9BMY3AODrg==", + "dev": true, + "requires": { + "postcss": "^7.0.27", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.0.2" + }, + "dependencies": { + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-colormin": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz", + "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "color": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-convert-values": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz", + "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", + "dev": true, + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-discard-comments": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz", + "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-discard-duplicates": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz", + "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-discard-empty": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz", + "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-discard-overridden": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz", + "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-load-config": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.0.tgz", + "integrity": "sha512-ipM8Ds01ZUophjDTQYSVP70slFSYg3T0/zyfII5vzhN6V57YSxMgG5syXuwi5VtS8wSf3iL30v0uBdoIVx4Q0g==", + "dev": true, + "requires": { + "import-cwd": "^3.0.0", + "lilconfig": "^2.0.3", + "yaml": "^1.10.2" + } + }, + "postcss-merge-longhand": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz", + "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==", + "dev": true, + "requires": { + "css-color-names": "0.0.4", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "stylehacks": "^4.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-merge-rules": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz", + "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "cssnano-util-same-parent": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0", + "vendors": "^1.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "dev": true, + "requires": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-minify-font-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz", + "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", + "dev": true, + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-minify-gradients": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz", + "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "is-color-stop": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-minify-params": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz", + "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.0", + "browserslist": "^4.0.0", + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "uniqs": "^2.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-minify-selectors": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz", + "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "dev": true, + "requires": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-modules": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-4.1.3.tgz", + "integrity": "sha512-dBT39hrXe4OAVYJe/2ZuIZ9BzYhOe7t+IhedYeQ2OxKwDpAGlkEN/fR0fGnrbx4BvgbMReRX4hCubYK9cE/pJQ==", + "dev": true, + "requires": { + "generic-names": "^2.0.1", + "icss-replace-symbols": "^1.1.0", + "lodash.camelcase": "^4.3.0", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "string-hash": "^1.1.1" + } + }, + "postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "dev": true + }, + "postcss-modules-local-by-default": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", + "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", + "dev": true, + "requires": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + } + }, + "postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.4" + } + }, + "postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "requires": { + "icss-utils": "^5.0.0" + } + }, + "postcss-normalize-charset": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz", + "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-normalize-display-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz", + "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==", + "dev": true, + "requires": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-normalize-positions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz", + "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-normalize-repeat-style": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz", + "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-normalize-string": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz", + "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==", + "dev": true, + "requires": { + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-normalize-timing-functions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz", + "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==", + "dev": true, + "requires": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-normalize-unicode": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz", + "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-normalize-url": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz", + "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", + "dev": true, + "requires": { + "is-absolute-url": "^2.0.0", + "normalize-url": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-normalize-whitespace": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz", + "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==", + "dev": true, + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-ordered-values": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz", + "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-reduce-initial": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz", + "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-reduce-transforms": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz", + "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==", + "dev": true, + "requires": { + "cssnano-util-get-match": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-selector-parser": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz", + "integrity": "sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "postcss-svgo": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.3.tgz", + "integrity": "sha512-NoRbrcMWTtUghzuKSoIm6XV+sJdvZ7GZSc3wdBN0W19FTtp2ko8NqLsgoh/m9CzNhU3KLPvQmjIwtaNFkaFTvw==", + "dev": true, + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "svgo": "^1.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-unique-selectors": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", + "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.0", + "postcss": "^7.0.0", + "uniqs": "^2.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-url": { + "version": "10.1.3", + "resolved": "https://registry.npmjs.org/postcss-url/-/postcss-url-10.1.3.tgz", + "integrity": "sha512-FUzyxfI5l2tKmXdYc6VTu3TWZsInayEKPbiyW+P6vmmIrrb4I6CGX0BFoewgYHLK+oIL5FECEK02REYRpBvUCw==", + "dev": true, + "requires": { + "make-dir": "~3.1.0", + "mime": "~2.5.2", + "minimatch": "~3.0.4", + "xxhashjs": "~0.2.2" + } + }, + "postcss-value-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", + "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", + "dev": true + }, + "promise.series": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/promise.series/-/promise.series-0.2.0.tgz", + "integrity": "sha1-LMfr6Vn8OmYZwEq029yeRS2GS70=", + "dev": true + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "dev": true + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "require-relative": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz", + "integrity": "sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4=", + "dev": true + }, + "resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "dev": true, + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rgb-regex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz", + "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=", + "dev": true + }, + "rgba-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz", + "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=", + "dev": true + }, + "rollup": { + "version": "2.52.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.52.4.tgz", + "integrity": "sha512-AXgUxxWXyGfsj8GKleR1k8KsG8G+7ZZDRU9RZb9PnLGSyTqI/1qf/+QSp1hRaR40j4yfBCKXs5khtGKiFwihfg==", + "dev": true, + "requires": { + "fsevents": "~2.3.2" + } + }, + "rollup-plugin-copy": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-copy/-/rollup-plugin-copy-3.4.0.tgz", + "integrity": "sha512-rGUmYYsYsceRJRqLVlE9FivJMxJ7X6jDlP79fmFkL8sJs7VVMSVyA2yfyL+PGyO/vJs4A87hwhgVfz61njI+uQ==", + "dev": true, + "requires": { + "@types/fs-extra": "^8.0.1", + "colorette": "^1.1.0", + "fs-extra": "^8.1.0", + "globby": "10.0.1", + "is-plain-object": "^3.0.0" + } + }, + "rollup-plugin-css-only": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-css-only/-/rollup-plugin-css-only-3.1.0.tgz", + "integrity": "sha512-TYMOE5uoD76vpj+RTkQLzC9cQtbnJNktHPB507FzRWBVaofg7KhIqq1kGbcVOadARSozWF883Ho9KpSPKH8gqA==", + "dev": true, + "requires": { + "@rollup/pluginutils": "4" + }, + "dependencies": { + "@rollup/pluginutils": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.1.0.tgz", + "integrity": "sha512-TrBhfJkFxA+ER+ew2U2/fHbebhLT/l/2pRk0hfj9KusXUuRXd2v0R58AfaZK9VXDQ4TogOSEmICVrQAA3zFnHQ==", + "dev": true, + "requires": { + "estree-walker": "^2.0.1", + "picomatch": "^2.2.2" + } + } + } + }, + "rollup-plugin-livereload": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/rollup-plugin-livereload/-/rollup-plugin-livereload-2.0.5.tgz", + "integrity": "sha512-vqQZ/UQowTW7VoiKEM5ouNW90wE5/GZLfdWuR0ELxyKOJUIaj+uismPZZaICU4DnWPVjnpCDDxEqwU7pcKY/PA==", + "dev": true, + "requires": { + "livereload": "^0.9.1" + } + }, + "rollup-plugin-postcss": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-postcss/-/rollup-plugin-postcss-4.0.0.tgz", + "integrity": "sha512-OQzT+YspV01/6dxfyEw8lBO2px3hyL8Xn+k2QGctL7V/Yx2Z1QaMKdYVslP1mqv7RsKt6DROIlnbpmgJ3yxf6g==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "concat-with-sourcemaps": "^1.1.0", + "cssnano": "^4.1.10", + "import-cwd": "^3.0.0", + "p-queue": "^6.6.2", + "pify": "^5.0.0", + "postcss-load-config": "^3.0.0", + "postcss-modules": "^4.0.0", + "promise.series": "^0.2.0", + "resolve": "^1.19.0", + "rollup-pluginutils": "^2.8.2", + "safe-identifier": "^0.4.2", + "style-inject": "^0.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "rollup-plugin-svelte": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-svelte/-/rollup-plugin-svelte-7.1.0.tgz", + "integrity": "sha512-vopCUq3G+25sKjwF5VilIbiY6KCuMNHP1PFvx2Vr3REBNMDllKHFZN2B9jwwC+MqNc3UPKkjXnceLPEjTjXGXg==", + "dev": true, + "requires": { + "require-relative": "^0.8.7", + "rollup-pluginutils": "^2.8.2" + } + }, + "rollup-plugin-terser": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", + "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "jest-worker": "^26.2.1", + "serialize-javascript": "^4.0.0", + "terser": "^5.0.0" + } + }, + "rollup-pluginutils": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", + "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", + "dev": true, + "requires": { + "estree-walker": "^0.6.1" + }, + "dependencies": { + "estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "dev": true + } + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "sade": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.7.4.tgz", + "integrity": "sha512-y5yauMD93rX840MwUJr7C1ysLFBgMspsdTo4UVrDg3fXDvtwOyIqykhVAAm6fk/3au77773itJStObgK+LKaiA==", + "requires": { + "mri": "^1.1.0" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "safe-identifier": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/safe-identifier/-/safe-identifier-0.4.2.tgz", + "integrity": "sha512-6pNbSMW6OhAi9j+N8V+U715yBQsaWJ7eyEUaOrawX+isg5ZxhUlV1NipNtgaKHmFGiABwt+ZF04Ii+3Xjkg+8w==", + "dev": true + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "semiver": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/semiver/-/semiver-1.1.0.tgz", + "integrity": "sha512-QNI2ChmuioGC1/xjyYwyZYADILWyW6AmS1UH6gDj/SFUUUS4MBAWs/7mxnkRPc/F4iHezDP+O8t0dO8WHiEOdg==" + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "dev": true, + "requires": { + "is-arrayish": "^0.3.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "dev": true + } + } + }, + "sirv": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.12.tgz", + "integrity": "sha512-+jQoCxndz7L2tqQL4ZyzfDhky0W/4ZJip3XoOuxyQWnAwMxindLl3Xv1qT4x1YX/re0leShvTm8Uk0kQspGhBg==", + "requires": { + "@polka/url": "^1.0.0-next.15", + "mime": "^2.3.1", + "totalist": "^1.0.0" + } + }, + "sirv-cli": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/sirv-cli/-/sirv-cli-1.0.12.tgz", + "integrity": "sha512-Rs5PvF3a48zuLmrl8vcqVv9xF/WWPES19QawVkpdzqx7vD5SMZS07+ece1gK4umbslXN43YeIksYtQM5csgIzQ==", + "requires": { + "console-clear": "^1.1.0", + "get-port": "^3.2.0", + "kleur": "^3.0.0", + "local-access": "^1.0.1", + "sade": "^1.6.0", + "semiver": "^1.0.0", + "sirv": "^1.0.12", + "tinydate": "^1.0.0" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + }, + "source-map-js": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz", + "integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==", + "dev": true + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "dev": true + }, + "string-hash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", + "integrity": "sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs=", + "dev": true + }, + "string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "style-inject": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/style-inject/-/style-inject-0.3.0.tgz", + "integrity": "sha512-IezA2qp+vcdlhJaVm5SOdPPTUu0FCEqfNSli2vRuSIBbu5Nq5UvygTk/VzeCqfLz2Atj3dVII5QBKGZRZ0edzw==", + "dev": true + }, + "stylehacks": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", + "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "dev": true, + "requires": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "svelte": { + "version": "3.38.3", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.38.3.tgz", + "integrity": "sha512-N7bBZJH0iF24wsalFZF+fVYMUOigaAUQMIcEKHO3jstK/iL8VmP9xE+P0/a76+FkNcWt+TDv2Gx1taUoUscrvw==", + "dev": true + }, + "svgo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", + "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "coa": "^2.0.2", + "css-select": "^2.0.0", + "css-select-base-adapter": "^0.1.1", + "css-tree": "1.0.0-alpha.37", + "csso": "^4.0.2", + "js-yaml": "^3.13.1", + "mkdirp": "~0.5.1", + "object.values": "^1.1.0", + "sax": "~1.2.4", + "stable": "^0.1.8", + "unquote": "~1.1.1", + "util.promisify": "~1.0.0" + } + }, + "terser": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.7.1.tgz", + "integrity": "sha512-b3e+d5JbHAe/JSjwsC3Zn55wsBIM7AsHLjKxT31kGCldgbpFePaFo+PiddtO6uwRZWRw7sPXmAN8dTW61xmnSg==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.7.2", + "source-map-support": "~0.5.19" + } + }, + "timsort": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", + "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", + "dev": true + }, + "tinydate": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/tinydate/-/tinydate-1.3.0.tgz", + "integrity": "sha512-7cR8rLy2QhYHpsBDBVYnnWXm8uRTr38RoZakFSW7Bs7PzfMPNZthuMLkwqZv7MTu8lhQ91cOFYS5a7iFj2oR3w==" + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "totalist": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz", + "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==" + }, + "unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + } + }, + "uniq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", + "dev": true + }, + "uniqs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", + "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=", + "dev": true + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "unquote": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", + "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "util.promisify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", + "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.2", + "has-symbols": "^1.0.1", + "object.getownpropertydescriptors": "^2.1.0" + } + }, + "vendors": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz", + "integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==", + "dev": true + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "ws": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.1.tgz", + "integrity": "sha512-2c6faOUH/nhoQN6abwMloF7Iyl0ZS2E9HGtsiLrWn0zOOMWlhtDmdf/uihDt6jnuCxgtwGBNy6Onsoy2s2O2Ow==", + "dev": true + }, + "xxhashjs": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/xxhashjs/-/xxhashjs-0.2.2.tgz", + "integrity": "sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw==", + "dev": true, + "requires": { + "cuint": "^0.2.2" + } + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true + } + } +} diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/package.tmpl.json b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/package.tmpl.json new file mode 100644 index 000000000..a49448c62 --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/package.tmpl.json @@ -0,0 +1,28 @@ +{ + "name": "{{.ProjectName}}", + "version": "1.0.0", + "private": true, + "scripts": { + "build": "rollup -c", + "dev": "rollup -c -w", + "start": "sirv dist --no-clear" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "^17.0.0", + "@rollup/plugin-image": "^2.0.6", + "@rollup/plugin-node-resolve": "^11.0.0", + "postcss": "^8.3.5", + "postcss-url": "^10.1.3", + "rollup": "^2.3.4", + "rollup-plugin-copy": "^3.4.0", + "rollup-plugin-livereload": "^2.0.0", + "rollup-plugin-postcss": "^4.0.0", + "rollup-plugin-svelte": "^7.0.0", + "rollup-plugin-terser": "^7.0.0", + "svelte": "^3.0.0" + }, + "dependencies": { + "sirv-cli": "^1.0.0" + }, + "author": "{{.AuthorName}}" +} diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/rollup.config.js b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/rollup.config.js new file mode 100644 index 000000000..42685908c --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/rollup.config.js @@ -0,0 +1,83 @@ +import svelte from 'rollup-plugin-svelte'; +import commonjs from '@rollup/plugin-commonjs'; +import resolve from '@rollup/plugin-node-resolve'; +import livereload from 'rollup-plugin-livereload'; +import {terser} from 'rollup-plugin-terser'; +import copy from 'rollup-plugin-copy'; +import postcss from 'rollup-plugin-postcss' + +const production = !process.env.ROLLUP_WATCH; + +function serve() { + let server; + + function toExit() { + if (server) server.kill(0); + } + + return { + writeBundle() { + if (server) return; + server = require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], { + stdio: ['ignore', 'inherit', 'inherit'], + shell: true + }); + + process.on('SIGTERM', toExit); + process.on('exit', toExit); + } + }; +} + +export default { + input: 'src/main.js', + output: { + sourcemap: true, + format: 'iife', + name: 'app', + file: 'dist/bundle.js' + }, + plugins: [ + svelte({ + compilerOptions: { + // enable run-time checks when not in production + dev: !production + } + }), + postcss({ + minimize: true, + }), + // If you have external dependencies installed from + // npm, you'll most likely need these plugins. In + // some cases you'll need additional configuration - + // consult the documentation for details: + // https://github.com/rollup/plugins/tree/master/packages/commonjs + resolve({ + browser: true, + dedupe: ['svelte'] + }), + commonjs(), + copy({ + targets: [ + {src: 'src/index.html', dest: 'dist/'}, + {src: 'src/global.css', dest: 'dist/'}, + {src: 'src/assets', dest: 'dist/'}, + ] + }), + + // In dev mode, call `npm run start` once + // the bundle has been generated + !production && serve(), + + // Watch the `dist` directory and refresh the + // browser on changes when not in production + !production && livereload('dist'), + + // If we're building for production (npm run build + // instead of npm run dev), minify + production && terser() + ], + watch: { + clearScreen: false + } +}; diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/scripts/setupTypeScript.js b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/scripts/setupTypeScript.js new file mode 100644 index 000000000..133658af1 --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/scripts/setupTypeScript.js @@ -0,0 +1,121 @@ +// @ts-check + +/** This script modifies the project to support TS code in .svelte files like: + + + + As well as validating the code for CI. + */ + +/** To work on this script: + rm -rf test-template template && git clone sveltejs/template test-template && node scripts/setupTypeScript.js test-template +*/ + +const fs = require("fs") +const path = require("path") +const { argv } = require("process") + +const projectRoot = argv[2] || path.join(__dirname, "..") + +// Add deps to pkg.json +const packageJSON = JSON.parse(fs.readFileSync(path.join(projectRoot, "package.json"), "utf8")) +packageJSON.devDependencies = Object.assign(packageJSON.devDependencies, { + "svelte-check": "^2.0.0", + "svelte-preprocess": "^4.0.0", + "@rollup/plugin-typescript": "^8.0.0", + "typescript": "^4.0.0", + "tslib": "^2.0.0", + "@tsconfig/svelte": "^2.0.0" +}) + +// Add script for checking +packageJSON.scripts = Object.assign(packageJSON.scripts, { + "check": "svelte-check --tsconfig ./tsconfig.json" +}) + +// Write the package JSON +fs.writeFileSync(path.join(projectRoot, "package.json"), JSON.stringify(packageJSON, null, " ")) + +// mv src/main.js to main.ts - note, we need to edit rollup.config.js for this too +const beforeMainJSPath = path.join(projectRoot, "src", "main.js") +const afterMainTSPath = path.join(projectRoot, "src", "main.ts") +fs.renameSync(beforeMainJSPath, afterMainTSPath) + +// Switch the app.svelte file to use TS +const appSveltePath = path.join(projectRoot, "src", "App.svelte") +let appFile = fs.readFileSync(appSveltePath, "utf8") +appFile = appFile.replace(" + +
+ +
+ + +
+ {#if greeting} +
{greeting}
+ {/if} +
+ + \ No newline at end of file diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/src/assets/fonts/OFL.txt b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/src/assets/fonts/OFL.txt new file mode 100644 index 000000000..bad763db1 --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/src/assets/fonts/OFL.txt @@ -0,0 +1,93 @@ +Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com), + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/v2/examples/customlayout/myfrontend/src/assets/fonts/nunito-v16-latin-regular.woff2 b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 similarity index 100% rename from v2/examples/customlayout/myfrontend/src/assets/fonts/nunito-v16-latin-regular.woff2 rename to v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/src/assets/images/logo-dark.svg b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/src/assets/images/logo-dark.svg new file mode 100644 index 000000000..66fa483c4 --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/src/assets/images/logo-dark.svg @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/src/global.css b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/src/global.css new file mode 100644 index 000000000..3827664ca --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/src/global.css @@ -0,0 +1,25 @@ + +html { + text-align: center; + color: white; + background-color: rgba(0, 0, 0, 255); + width: 100%; + height: 100%; +} + +body { + color: white; + font-family: 'Nunito', -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; + margin: 0; + width: 100%; + height: 100%; + overscroll-behavior: none; +} + +@font-face { + font-family: 'Nunito'; + font-style: normal; + font-weight: 400; + src: local(''), + url('./assets/fonts/nunito-v16-latin-regular.woff2') format('woff2') +} \ No newline at end of file diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/src/index.tmpl.html b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/src/index.tmpl.html new file mode 100644 index 000000000..d6dfa7948 --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/src/index.tmpl.html @@ -0,0 +1,14 @@ + + + + + + + {{.ProjectName}} + + + + + + + diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/src/main.js b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/src/main.js new file mode 100644 index 000000000..d80e9a350 --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/frontend/src/main.js @@ -0,0 +1,7 @@ +import App from './App.svelte'; + +const app = new App({ + target: document.body, +}); + +export default app; \ No newline at end of file diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/gitignore.txt b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/gitignore.txt new file mode 100644 index 000000000..da44b7c53 --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/gitignore.txt @@ -0,0 +1,9 @@ +# Wails bin directory +build/bin + +# IDEs +.idea +.vscode + +# The black hole that is... +node_modules diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/go.mod.tmpl b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/go.mod.tmpl new file mode 100644 index 000000000..2c68d66ed --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/go.mod.tmpl @@ -0,0 +1,38 @@ +module changeme + +go 1.17 + +require github.com/wailsapp/wails/v2 {{.WailsVersion}} + +require ( +github.com/andybalholm/brotli v1.0.2 // indirect +github.com/davecgh/go-spew v1.1.1 // indirect +github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect +github.com/gabriel-vasile/mimetype v1.3.1 // indirect +github.com/go-ole/go-ole v1.2.5 // indirect +github.com/gofiber/fiber/v2 v2.17.0 // indirect +github.com/gofiber/websocket/v2 v2.0.8 // indirect +github.com/google/uuid v1.1.2 // indirect +github.com/imdario/mergo v0.3.12 // indirect +github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5 // indirect +github.com/klauspost/compress v1.12.2 // indirect +github.com/leaanthony/debme v1.2.1 // indirect +github.com/leaanthony/go-ansi-parser v1.0.1 // indirect +github.com/leaanthony/go-common-file-dialog v1.0.3 // indirect +github.com/leaanthony/go-webview2 v0.0.0-20210914103035-f00aa774a934 // indirect +github.com/leaanthony/slicer v1.5.0 // indirect +github.com/leaanthony/typescriptify-golang-structs v0.1.7 // indirect +github.com/leaanthony/webview2runtime v1.1.0 // indirect +github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 // indirect +github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect +github.com/pkg/errors v0.9.1 // indirect +github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect +github.com/tkrajina/go-reflector v0.5.5 // indirect +github.com/valyala/bytebufferpool v1.0.0 // indirect +github.com/valyala/fasthttp v1.28.0 // indirect +github.com/valyala/tcplisten v1.0.0 // indirect +golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf // indirect +) + +// replace github.com/wailsapp/wails/v2 {{.WailsVersion}} => {{.WailsDirectory}} diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/go.sum b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/go.sum new file mode 100644 index 000000000..575af8230 --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/go.sum @@ -0,0 +1,228 @@ +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= +github.com/andybalholm/brotli v1.0.2 h1:JKnhI/XQ75uFBTiuzXpzFrUriDPiZjlOSzh6wXogP0E= +github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab h1:9e2joQGp642wHGFP5m86SDptAavrdGBe8/x9DGEEAaI= +github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab/go.mod h1:smsv/h4PBEBaU0XDTY5UwJTpZv69fQ0FfcLJr21mA6Y= +github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/flytam/filenamify v1.0.0/go.mod h1:Dzf9kVycwcsBlr2ATg6uxjqiFgKGH+5SKFuhdeP5zu8= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/gabriel-vasile/mimetype v1.3.1 h1:qevA6c2MtE1RorlScnixeG0VA1H4xrXyhyX3oWBynNQ= +github.com/gabriel-vasile/mimetype v1.3.1/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= +github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= +github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-billy/v5 v5.1.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= +github.com/go-git/go-git/v5 v5.3.0/go.mod h1:xdX4bWJ48aOrdhnl2XqHYstHbbp6+LFS4r4X+lNVprw= +github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= +github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY= +github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/gofiber/fiber/v2 v2.17.0 h1:qP3PkGUbBB0i9iQh5E057XI1yO5CZigUxZhyUFYAFoM= +github.com/gofiber/fiber/v2 v2.17.0/go.mod h1:iftruuHGkRYGEXVISmdD7HTYWyfS2Bh+Dkfq4n/1Owg= +github.com/gofiber/websocket/v2 v2.0.8 h1:Hb4y6IxYZVMO0segROODXJiXVgVD3a6i7wnfot8kM6k= +github.com/gofiber/websocket/v2 v2.0.8/go.mod h1:fv8HSGQX09sauNv9g5Xq8GeGAaahLFYQKKb4ZdT0x2w= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/jackmordaunt/icns v1.0.0/go.mod h1:7TTQVEuGzVVfOPPlLNHJIkzA6CoV7aH1Dv9dW351oOo= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs= +github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck= +github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs= +github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.12.2 h1:2KCfW3I9M7nSc5wOqXAlW2v2U6v+w6cbjvbfp+OykW8= +github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leaanthony/clir v1.0.4/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0= +github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc= +github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA= +github.com/leaanthony/go-ansi-parser v1.0.1 h1:97v6c5kYppVsbScf4r/VZdXyQ21KQIfeQOk2DgKxGG4= +github.com/leaanthony/go-ansi-parser v1.0.1/go.mod h1:7arTzgVI47srICYhvgUV4CGd063sGEeoSlych5yeSPM= +github.com/leaanthony/go-common-file-dialog v1.0.3 h1:O0uGjKnWtdEADGrkg+TyAAbZylykMwwx/MNEXn9fp+Y= +github.com/leaanthony/go-common-file-dialog v1.0.3/go.mod h1:TGhEc9eSJgRsupZ+iH1ZgAOnEo9zp05cRH2j08RPrF0= +github.com/leaanthony/go-webview2 v0.0.0-20210928094513-a94a08b538bd h1:6m4zZ/esiByaDbzgdvDxjsOaIDgtuG1q2cyhjAi6uAg= +github.com/leaanthony/go-webview2 v0.0.0-20210928094513-a94a08b538bd/go.mod h1:lS5ds4bruPk9d7lzdF/OH31Z0YCerI6MmHNFGsWoUnM= +github.com/leaanthony/gosod v1.0.3/go.mod h1:BJ2J+oHsQIyIQpnLPjnqFGTMnOZXDbvWtRCSG7jGxs4= +github.com/leaanthony/idgen v1.0.0/go.mod h1:4nBZnt8ml/f/ic/EVQuLxuj817RccT2fyrUaZFxrcVA= +github.com/leaanthony/slicer v1.5.0 h1:aHYTN8xbCCLxJmkNKiLB6tgcMARl4eWmH9/F+S/0HtY= +github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY= +github.com/leaanthony/typescriptify-golang-structs v0.1.7 h1:yoznzWzyxkO/iWdlpq+aPcuJ5Y/hpjq/lmgMFmpjwl0= +github.com/leaanthony/typescriptify-golang-structs v0.1.7/go.mod h1:cWtOkiVhMF77e6phAXUcfNwYmMwCJ67Sij24lfvi9Js= +github.com/leaanthony/webview2runtime v1.1.0 h1:N0pv55ift8XtqozIp4PNOtRCJ/Qdd/qzx80lUpalS4c= +github.com/leaanthony/webview2runtime v1.1.0/go.mod h1:hH9GnWCve3DYzNaPOcPbhHQ7fodXR1QJNsnwixid4Tk= +github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 h1:5iOd93PZbpH4Iir8QkC4coFD+zEQEZSIRcjwjTFZkr0= +github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18/go.mod h1:KEbMsKoznsebyGHwLk5LqkFOxL5uXSRdvpP4+avmAMs= +github.com/leaanthony/winicon v1.0.0/go.mod h1:en5xhijl92aphrJdmRPlh4NI1L6wq3gEm0LpXAPghjU= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= +github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= +github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= +github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 h1:acNfDZXmm28D2Yg/c3ALnZStzNaZMSagpbr96vY6Zjc= +github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f h1:PgA+Olipyj258EIEYnpFFONrrCcAIWNUNoFhUfMqAGY= +github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f/go.mod h1:lHhJedqxCoHN+zMtwGNTXWmF0u9Jt363FYRhV6g0CdY= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tc-hib/winres v0.1.5/go.mod h1:pe6dOR40VOrGz8PkzreVKNvEKnlE8t4yR8A8naL+t7A= +github.com/tdewolff/minify v2.3.6+incompatible/go.mod h1:9Ov578KJUmAWpS6NeZwRZyT56Uf6o3Mcz9CEsg8USYs= +github.com/tdewolff/parse v2.3.4+incompatible/go.mod h1:8oBwCsVmUkgHO8M5iCzSIDtpzXOT0WXX9cWhz+bIzJQ= +github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= +github.com/tidwall/gjson v1.8.0/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk= +github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/sjson v1.1.7/go.mod h1:w/yG+ezBeTdUxiKs5NcPicO9diP38nk96QBAbIIGeFs= +github.com/tkrajina/go-reflector v0.5.5 h1:gwoQFNye30Kk7NrExj8zm3zFtrGPqOkzFMLuQZg1DtQ= +github.com/tkrajina/go-reflector v0.5.5/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.9.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= +github.com/valyala/fasthttp v1.26.0/go.mod h1:cmWIqlu99AO/RKcp1HWaViTqc57FswJOfYYdPJBl8BA= +github.com/valyala/fasthttp v1.28.0 h1:ruVmTmZaBR5i67NqnjvvH5gEv0zwHfWtbjoyW98iho4= +github.com/valyala/fasthttp v1.28.0/go.mod h1:cmWIqlu99AO/RKcp1HWaViTqc57FswJOfYYdPJBl8BA= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= +github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +github.com/wailsapp/wails/v2 v2.0.0-beta.3 h1:8vhBbnjpYDF6cCUwKadon7J/98UjcP1nrnptUl70Tfg= +github.com/wailsapp/wails/v2 v2.0.0-beta.3/go.mod h1:aku28riyHF2G5jmx/qtxjLWi7VwpTjhhX/HVLCptWFA= +github.com/wzshiming/ctc v1.2.3/go.mod h1:2tVAtIY7SUyraSk0JxvwmONNPFL4ARavPuEsg5+KA28= +github.com/wzshiming/winseq v0.0.0-20200112104235-db357dc107ae/go.mod h1:VTAq37rkGeV+WOybvZwjXiJOicICdpLCN8ifpISjK20= +github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= +github.com/xyproto/xpm v1.2.1/go.mod h1:cMnesLsD0PBXLgjDfTDEaKr8XyTFsnP1QycSqRw7BiY= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/ztrue/tracerr v0.3.0/go.mod h1:qEalzze4VN9O8tnhBXScfCrmoJo10o8TN5ciKjm6Mww= +golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= +golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210510120150-4163338589ed h1:p9UgmWI9wKpfYmgaV/IZKGdXc5qEK45tDwwwDyjS26I= +golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210611083646-a4fc73990273/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 h1:foEbQz/B0Oz6YIqu/69kfXPYeFQAuuMYFkjaqXzl5Wo= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/main.tmpl.go b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/main.tmpl.go new file mode 100644 index 000000000..89a4cecbb --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/main.tmpl.go @@ -0,0 +1,54 @@ +package main + +import ( + "embed" + "log" + + "github.com/wailsapp/wails/v2" + "github.com/wailsapp/wails/v2/pkg/logger" + "github.com/wailsapp/wails/v2/pkg/options" + "github.com/wailsapp/wails/v2/pkg/options/windows" +) + +//go:embed frontend/dist +var assets embed.FS + +func main() { + // Create an instance of the app structure + app := NewApp() + + // Create application with options + err := wails.Run(&options.App{ + Title: "{{.ProjectName}}", + Width: 720, + Height: 570, + MinWidth: 720, + MinHeight: 570, + MaxWidth: 1280, + MaxHeight: 740, + DisableResize: false, + Fullscreen: false, + Frameless: false, + StartHidden: false, + HideWindowOnClose: false, + RGBA: &options.RGBA{R: 255, G: 255, B: 255, A: 255}, + Assets: assets, + LogLevel: logger.DEBUG, + OnStartup: app.startup, + OnDomReady: app.domReady, + OnShutdown: app.shutdown, + Bind: []interface{}{ + app, + }, + // Windows platform specific options + Windows: &windows.Options{ + WebviewIsTransparent: false, + WindowIsTranslucent: false, + DisableWindowIcon: false, + }, + }) + + if err != nil { + log.Fatal(err) + } +} diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/template.json b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/template.json new file mode 100644 index 000000000..f04858241 --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/template.json @@ -0,0 +1,7 @@ +{ + "name": "Basic Svelte + Rollup", + "shortname": "svelte", + "author": "Lea Anthony ", + "description": "Svelte template using rollup to bundle css, images and fonts", + "helpurl": "https://github.com/wailsapp/wails" +} diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/wails.tmpl.json b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/wails.tmpl.json new file mode 100644 index 000000000..b8d08108d --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/wails.tmpl.json @@ -0,0 +1,11 @@ +{ + "name": "{{.ProjectName}}", + "outputfilename": "{{.BinaryName}}", + "assetdir": "frontend/dist", + "frontend:install": "npm install", + "frontend:build": "npm run build", + "author": { + "name": "{{.AuthorName}}", + "email": "{{.AuthorEmail}}" + } +} diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/README.md b/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/README.md new file mode 100644 index 000000000..5b2db9baf --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/README.md @@ -0,0 +1,15 @@ +# README + +## About + +This template uses vanilla JS / HTML and CSS. + +## Live Development + +To run in live development mode, run `wails dev` in the project directory. The frontend dev server will run +on http://localhost:34115. Open this in your browser to connect to your application. + +## Building + +For a production build, use `wails build`. + diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/app.go b/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/app.go new file mode 100644 index 000000000..d04d123d4 --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/app.go @@ -0,0 +1,37 @@ +package main + +import ( + "context" + "fmt" +) + +// App struct +type App struct { + ctx context.Context +} + +// NewApp creates a new App application struct +func NewApp() *App { + return &App{} +} + +// startup is called at application startup +func (b *App) startup(ctx context.Context) { + // Perform your setup here + b.ctx = ctx +} + +// domReady is called after the front-end dom has been loaded +func (b *App) domReady(ctx context.Context) { + // Add your action here +} + +// shutdown is called at application termination +func (b *App) shutdown(ctx context.Context) { + // Perform your teardown here +} + +// Greet returns a greeting for the given name +func (b *App) Greet(name string) string { + return fmt.Sprintf("Hello %s, It's show time!", name) +} diff --git a/v2/examples/customlayout/myfrontend/src/assets/fonts/OFL.txt b/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/frontend/src/assets/fonts/OFL.txt similarity index 100% rename from v2/examples/customlayout/myfrontend/src/assets/fonts/OFL.txt rename to v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/frontend/src/assets/fonts/OFL.txt diff --git a/v2/examples/dragdrop-test/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 b/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 similarity index 100% rename from v2/examples/dragdrop-test/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 rename to v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/frontend/src/assets/images/logo-dark.svg b/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/frontend/src/assets/images/logo-dark.svg new file mode 100644 index 000000000..855d7e0ef --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/frontend/src/assets/images/logo-dark.svg @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/frontend/src/index.tmpl.html b/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/frontend/src/index.tmpl.html new file mode 100644 index 000000000..73eebf442 --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/frontend/src/index.tmpl.html @@ -0,0 +1,19 @@ + + + + {{.ProjectName}} + + + + + +
Please enter your name below 👇
+
+ + +
+ + + + + \ No newline at end of file diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/frontend/src/main.css b/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/frontend/src/main.css new file mode 100644 index 000000000..1a73a0da8 --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/frontend/src/main.css @@ -0,0 +1,73 @@ +html { + background-color: rgba(33, 37, 43, 1); + text-align: center; + color: white; +} + +body { + margin: 0; + color: white; + font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", + "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", + sans-serif; + overscroll-behavior: none; +} + +@font-face { + font-family: "Nunito"; + font-style: normal; + font-weight: 400; + src: local(""), + url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2"); +} + +.logo { + display: block; + width: 35%; + height: 35%; + margin: auto; + padding: 15% 0 0; + background-position: center; + background-repeat: no-repeat; + background-image: url("./assets/images/logo-dark.svg"); +} +.result { + height: 20px; + line-height: 20px; + margin: 1.5rem auto; +} +.input-box .btn { + width: 60px; + height: 30px; + line-height: 30px; + border-radius: 3px; + border: none; + margin: 0 0 0 20px; + padding: 0 8px; + cursor: pointer; +} +.input-box .btn:hover { + background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%); + color: #333333; +} + +.input-box .input { + border: none; + border-radius: 3px; + outline: none; + height: 30px; + line-height: 30px; + padding: 0 10px; + background-color: rgba(240, 240, 240, 1); + -webkit-font-smoothing: antialiased; +} + +.input-box .input:hover { + border: none; + background-color: rgba(255, 255, 255, 1); +} + +.input-box .input:focus { + border: none; + background-color: rgba(255, 255, 255, 1); +} diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/frontend/src/main.js b/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/frontend/src/main.js new file mode 100644 index 000000000..db404e459 --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/frontend/src/main.js @@ -0,0 +1,23 @@ +// Get input + focus +let nameElement = document.getElementById("name"); +nameElement.focus(); + +// Setup the greet function +window.greet = function () { + + // Get name + let name = nameElement.value; + + // Call App.Greet(name) + window.go.main.App.Greet(name).then((result) => { + // Update result with data back from App.Greet() + document.getElementById("result").innerText = result; + }); +}; + +nameElement.onkeydown = function (e) { + console.log(e) + if (e.keyCode == 13) { + window.greet() + } +} \ No newline at end of file diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/gitignore.txt b/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/gitignore.txt new file mode 100644 index 000000000..da44b7c53 --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/gitignore.txt @@ -0,0 +1,9 @@ +# Wails bin directory +build/bin + +# IDEs +.idea +.vscode + +# The black hole that is... +node_modules diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/go.mod.tmpl b/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/go.mod.tmpl new file mode 100644 index 000000000..2c68d66ed --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/go.mod.tmpl @@ -0,0 +1,38 @@ +module changeme + +go 1.17 + +require github.com/wailsapp/wails/v2 {{.WailsVersion}} + +require ( +github.com/andybalholm/brotli v1.0.2 // indirect +github.com/davecgh/go-spew v1.1.1 // indirect +github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect +github.com/gabriel-vasile/mimetype v1.3.1 // indirect +github.com/go-ole/go-ole v1.2.5 // indirect +github.com/gofiber/fiber/v2 v2.17.0 // indirect +github.com/gofiber/websocket/v2 v2.0.8 // indirect +github.com/google/uuid v1.1.2 // indirect +github.com/imdario/mergo v0.3.12 // indirect +github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5 // indirect +github.com/klauspost/compress v1.12.2 // indirect +github.com/leaanthony/debme v1.2.1 // indirect +github.com/leaanthony/go-ansi-parser v1.0.1 // indirect +github.com/leaanthony/go-common-file-dialog v1.0.3 // indirect +github.com/leaanthony/go-webview2 v0.0.0-20210914103035-f00aa774a934 // indirect +github.com/leaanthony/slicer v1.5.0 // indirect +github.com/leaanthony/typescriptify-golang-structs v0.1.7 // indirect +github.com/leaanthony/webview2runtime v1.1.0 // indirect +github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 // indirect +github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect +github.com/pkg/errors v0.9.1 // indirect +github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect +github.com/tkrajina/go-reflector v0.5.5 // indirect +github.com/valyala/bytebufferpool v1.0.0 // indirect +github.com/valyala/fasthttp v1.28.0 // indirect +github.com/valyala/tcplisten v1.0.0 // indirect +golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf // indirect +) + +// replace github.com/wailsapp/wails/v2 {{.WailsVersion}} => {{.WailsDirectory}} diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/go.sum b/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/go.sum new file mode 100644 index 000000000..575af8230 --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/go.sum @@ -0,0 +1,228 @@ +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= +github.com/andybalholm/brotli v1.0.2 h1:JKnhI/XQ75uFBTiuzXpzFrUriDPiZjlOSzh6wXogP0E= +github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab h1:9e2joQGp642wHGFP5m86SDptAavrdGBe8/x9DGEEAaI= +github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab/go.mod h1:smsv/h4PBEBaU0XDTY5UwJTpZv69fQ0FfcLJr21mA6Y= +github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/flytam/filenamify v1.0.0/go.mod h1:Dzf9kVycwcsBlr2ATg6uxjqiFgKGH+5SKFuhdeP5zu8= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/gabriel-vasile/mimetype v1.3.1 h1:qevA6c2MtE1RorlScnixeG0VA1H4xrXyhyX3oWBynNQ= +github.com/gabriel-vasile/mimetype v1.3.1/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= +github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= +github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-billy/v5 v5.1.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= +github.com/go-git/go-git/v5 v5.3.0/go.mod h1:xdX4bWJ48aOrdhnl2XqHYstHbbp6+LFS4r4X+lNVprw= +github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= +github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY= +github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/gofiber/fiber/v2 v2.17.0 h1:qP3PkGUbBB0i9iQh5E057XI1yO5CZigUxZhyUFYAFoM= +github.com/gofiber/fiber/v2 v2.17.0/go.mod h1:iftruuHGkRYGEXVISmdD7HTYWyfS2Bh+Dkfq4n/1Owg= +github.com/gofiber/websocket/v2 v2.0.8 h1:Hb4y6IxYZVMO0segROODXJiXVgVD3a6i7wnfot8kM6k= +github.com/gofiber/websocket/v2 v2.0.8/go.mod h1:fv8HSGQX09sauNv9g5Xq8GeGAaahLFYQKKb4ZdT0x2w= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/jackmordaunt/icns v1.0.0/go.mod h1:7TTQVEuGzVVfOPPlLNHJIkzA6CoV7aH1Dv9dW351oOo= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs= +github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck= +github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs= +github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.12.2 h1:2KCfW3I9M7nSc5wOqXAlW2v2U6v+w6cbjvbfp+OykW8= +github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leaanthony/clir v1.0.4/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0= +github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc= +github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA= +github.com/leaanthony/go-ansi-parser v1.0.1 h1:97v6c5kYppVsbScf4r/VZdXyQ21KQIfeQOk2DgKxGG4= +github.com/leaanthony/go-ansi-parser v1.0.1/go.mod h1:7arTzgVI47srICYhvgUV4CGd063sGEeoSlych5yeSPM= +github.com/leaanthony/go-common-file-dialog v1.0.3 h1:O0uGjKnWtdEADGrkg+TyAAbZylykMwwx/MNEXn9fp+Y= +github.com/leaanthony/go-common-file-dialog v1.0.3/go.mod h1:TGhEc9eSJgRsupZ+iH1ZgAOnEo9zp05cRH2j08RPrF0= +github.com/leaanthony/go-webview2 v0.0.0-20210928094513-a94a08b538bd h1:6m4zZ/esiByaDbzgdvDxjsOaIDgtuG1q2cyhjAi6uAg= +github.com/leaanthony/go-webview2 v0.0.0-20210928094513-a94a08b538bd/go.mod h1:lS5ds4bruPk9d7lzdF/OH31Z0YCerI6MmHNFGsWoUnM= +github.com/leaanthony/gosod v1.0.3/go.mod h1:BJ2J+oHsQIyIQpnLPjnqFGTMnOZXDbvWtRCSG7jGxs4= +github.com/leaanthony/idgen v1.0.0/go.mod h1:4nBZnt8ml/f/ic/EVQuLxuj817RccT2fyrUaZFxrcVA= +github.com/leaanthony/slicer v1.5.0 h1:aHYTN8xbCCLxJmkNKiLB6tgcMARl4eWmH9/F+S/0HtY= +github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY= +github.com/leaanthony/typescriptify-golang-structs v0.1.7 h1:yoznzWzyxkO/iWdlpq+aPcuJ5Y/hpjq/lmgMFmpjwl0= +github.com/leaanthony/typescriptify-golang-structs v0.1.7/go.mod h1:cWtOkiVhMF77e6phAXUcfNwYmMwCJ67Sij24lfvi9Js= +github.com/leaanthony/webview2runtime v1.1.0 h1:N0pv55ift8XtqozIp4PNOtRCJ/Qdd/qzx80lUpalS4c= +github.com/leaanthony/webview2runtime v1.1.0/go.mod h1:hH9GnWCve3DYzNaPOcPbhHQ7fodXR1QJNsnwixid4Tk= +github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 h1:5iOd93PZbpH4Iir8QkC4coFD+zEQEZSIRcjwjTFZkr0= +github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18/go.mod h1:KEbMsKoznsebyGHwLk5LqkFOxL5uXSRdvpP4+avmAMs= +github.com/leaanthony/winicon v1.0.0/go.mod h1:en5xhijl92aphrJdmRPlh4NI1L6wq3gEm0LpXAPghjU= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= +github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= +github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= +github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 h1:acNfDZXmm28D2Yg/c3ALnZStzNaZMSagpbr96vY6Zjc= +github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f h1:PgA+Olipyj258EIEYnpFFONrrCcAIWNUNoFhUfMqAGY= +github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f/go.mod h1:lHhJedqxCoHN+zMtwGNTXWmF0u9Jt363FYRhV6g0CdY= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tc-hib/winres v0.1.5/go.mod h1:pe6dOR40VOrGz8PkzreVKNvEKnlE8t4yR8A8naL+t7A= +github.com/tdewolff/minify v2.3.6+incompatible/go.mod h1:9Ov578KJUmAWpS6NeZwRZyT56Uf6o3Mcz9CEsg8USYs= +github.com/tdewolff/parse v2.3.4+incompatible/go.mod h1:8oBwCsVmUkgHO8M5iCzSIDtpzXOT0WXX9cWhz+bIzJQ= +github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= +github.com/tidwall/gjson v1.8.0/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk= +github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/sjson v1.1.7/go.mod h1:w/yG+ezBeTdUxiKs5NcPicO9diP38nk96QBAbIIGeFs= +github.com/tkrajina/go-reflector v0.5.5 h1:gwoQFNye30Kk7NrExj8zm3zFtrGPqOkzFMLuQZg1DtQ= +github.com/tkrajina/go-reflector v0.5.5/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.9.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= +github.com/valyala/fasthttp v1.26.0/go.mod h1:cmWIqlu99AO/RKcp1HWaViTqc57FswJOfYYdPJBl8BA= +github.com/valyala/fasthttp v1.28.0 h1:ruVmTmZaBR5i67NqnjvvH5gEv0zwHfWtbjoyW98iho4= +github.com/valyala/fasthttp v1.28.0/go.mod h1:cmWIqlu99AO/RKcp1HWaViTqc57FswJOfYYdPJBl8BA= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= +github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +github.com/wailsapp/wails/v2 v2.0.0-beta.3 h1:8vhBbnjpYDF6cCUwKadon7J/98UjcP1nrnptUl70Tfg= +github.com/wailsapp/wails/v2 v2.0.0-beta.3/go.mod h1:aku28riyHF2G5jmx/qtxjLWi7VwpTjhhX/HVLCptWFA= +github.com/wzshiming/ctc v1.2.3/go.mod h1:2tVAtIY7SUyraSk0JxvwmONNPFL4ARavPuEsg5+KA28= +github.com/wzshiming/winseq v0.0.0-20200112104235-db357dc107ae/go.mod h1:VTAq37rkGeV+WOybvZwjXiJOicICdpLCN8ifpISjK20= +github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= +github.com/xyproto/xpm v1.2.1/go.mod h1:cMnesLsD0PBXLgjDfTDEaKr8XyTFsnP1QycSqRw7BiY= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/ztrue/tracerr v0.3.0/go.mod h1:qEalzze4VN9O8tnhBXScfCrmoJo10o8TN5ciKjm6Mww= +golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= +golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210510120150-4163338589ed h1:p9UgmWI9wKpfYmgaV/IZKGdXc5qEK45tDwwwDyjS26I= +golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210611083646-a4fc73990273/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 h1:foEbQz/B0Oz6YIqu/69kfXPYeFQAuuMYFkjaqXzl5Wo= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/main.tmpl.go b/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/main.tmpl.go new file mode 100644 index 000000000..28d7826d9 --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/main.tmpl.go @@ -0,0 +1,54 @@ +package main + +import ( + "embed" + "log" + + "github.com/wailsapp/wails/v2" + "github.com/wailsapp/wails/v2/pkg/logger" + "github.com/wailsapp/wails/v2/pkg/options" + "github.com/wailsapp/wails/v2/pkg/options/windows" +) + +//go:embed frontend/src +var assets embed.FS + +func main() { + // Create an instance of the app structure + app := NewApp() + + // Create application with options + err := wails.Run(&options.App{ + Title: "{{.ProjectName}}", + Width: 720, + Height: 570, + MinWidth: 720, + MinHeight: 570, + MaxWidth: 1280, + MaxHeight: 740, + DisableResize: false, + Fullscreen: false, + Frameless: false, + StartHidden: false, + HideWindowOnClose: false, + RGBA: &options.RGBA{R: 255, G: 255, B: 255, A: 255}, + Assets: assets, + LogLevel: logger.DEBUG, + OnStartup: app.startup, + OnDomReady: app.domReady, + OnShutdown: app.shutdown, + Bind: []interface{}{ + app, + }, + // Windows platform specific options + Windows: &windows.Options{ + WebviewIsTransparent: false, + WindowIsTranslucent: false, + DisableWindowIcon: false, + }, + }) + + if err != nil { + log.Fatal(err) + } +} diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/template.json b/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/template.json new file mode 100644 index 000000000..f235e50e7 --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/template.json @@ -0,0 +1,7 @@ +{ + "name": "Vanilla HTML/JS/CSS", + "shortname": "vanilla", + "author": "Lea Anthony ", + "description": "A simple template using only HTML/CSS/JS", + "helpurl": "https://github.com/wailsapp/wails" +} diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/wails.tmpl.json b/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/wails.tmpl.json new file mode 100644 index 000000000..0f6a23103 --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/wails.tmpl.json @@ -0,0 +1,9 @@ +{ + "name": "{{.ProjectName}}", + "outputfilename": "{{.BinaryName}}", + "assetdir": "frontend/src", + "author": { + "name": "{{.AuthorName}}", + "email": "{{.AuthorEmail}}" + } +} diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates_test.go b/v2/cmd/wails/internal/commands/initialise/templates/templates_test.go new file mode 100644 index 000000000..dcff8d6e8 --- /dev/null +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates_test.go @@ -0,0 +1,46 @@ +package templates + +import ( + "fmt" + "testing" + + "github.com/matryer/is" +) + +func TestList(t *testing.T) { + + is2 := is.New(t) + templates, err := List() + is2.NoErr(err) + + println("Found these templates:") + for _, template := range templates { + fmt.Printf("%+v\n", template) + } +} + +func TestShortname(t *testing.T) { + + is2 := is.New(t) + + template, err := getTemplateByShortname("vanilla") + is2.NoErr(err) + + println("Found this template:") + fmt.Printf("%+v\n", template) +} + +func TestInstall(t *testing.T) { + + is2 := is.New(t) + + options := &Options{ + ProjectName: "test", + TemplateName: "vanilla", + AuthorName: "Lea Anthony", + AuthorEmail: "lea.anthony@gmail.com", + } + + _, _, err := Install(options) + is2.NoErr(err) +} diff --git a/v2/cmd/wails/internal/commands/update/update.go b/v2/cmd/wails/internal/commands/update/update.go new file mode 100644 index 000000000..5eef6af25 --- /dev/null +++ b/v2/cmd/wails/internal/commands/update/update.go @@ -0,0 +1,166 @@ +package update + +import ( + "fmt" + "io" + "log" + "os" + + "github.com/wailsapp/wails/v2/internal/shell" + + "github.com/wailsapp/wails/v2/internal/github" + + "github.com/leaanthony/clir" + "github.com/wailsapp/wails/v2/pkg/clilogger" +) + +// AddSubcommand adds the `init` command for the Wails application +func AddSubcommand(app *clir.Cli, w io.Writer, currentVersion string) error { + + command := app.NewSubCommand("update", "Update the Wails CLI") + command.LongDescription(`This command allows you to update your version of the Wails CLI.`) + + // Setup flags + var prereleaseRequired bool + command.BoolFlag("pre", "Update CLI to latest Prerelease", &prereleaseRequired) + + var specificVersion string + command.StringFlag("version", "Install a specific version (Overrides other flags) of the CLI", &specificVersion) + + command.Action(func() error { + + // Create logger + logger := clilogger.New(w) + + // Print banner + app.PrintBanner() + logger.Println("Checking for updates...") + + var desiredVersion *github.SemanticVersion + var err error + var valid bool + + if len(specificVersion) > 0 { + // Check if this is a valid version + valid, err = github.IsValidTag(specificVersion) + if err == nil { + if !valid { + err = fmt.Errorf("version '%s' is invalid", specificVersion) + } else { + desiredVersion, err = github.NewSemanticVersion(specificVersion) + } + } + } else { + if prereleaseRequired { + desiredVersion, err = github.GetLatestPreRelease() + } else { + desiredVersion, err = github.GetLatestStableRelease() + } + } + if err != nil { + return err + } + fmt.Println() + + fmt.Println(" Current Version : " + currentVersion) + + if len(specificVersion) > 0 { + fmt.Printf(" Desired Version : v%s\n", desiredVersion) + } else { + if prereleaseRequired { + fmt.Printf(" Latest Prerelease : v%s\n", desiredVersion) + } else { + fmt.Printf(" Latest Release : v%s\n", desiredVersion) + } + } + + return updateToVersion(logger, desiredVersion, len(specificVersion) > 0, currentVersion) + }) + + return nil +} + +func updateToVersion(logger *clilogger.CLILogger, targetVersion *github.SemanticVersion, force bool, currentVersion string) error { + + var targetVersionString = "v" + targetVersion.String() + + // Early exit + if targetVersionString == currentVersion { + logger.Println("\nLooks like you're up to date!") + return nil + } + + var desiredVersion string + + if !force { + + compareVersion := currentVersion + + currentVersion, err := github.NewSemanticVersion(compareVersion) + if err != nil { + return err + } + + var success bool + + // Release -> Pre-Release = Massage current version to prerelease format + if targetVersion.IsPreRelease() && currentVersion.IsRelease() { + testVersion, err := github.NewSemanticVersion(compareVersion + "-0") + if err != nil { + return err + } + success, _ = targetVersion.IsGreaterThan(testVersion) + } + // Pre-Release -> Release = Massage target version to prerelease format + if targetVersion.IsRelease() && currentVersion.IsPreRelease() { + // We are ok with greater than or equal + mainversion := currentVersion.MainVersion() + targetVersion, err = github.NewSemanticVersion(targetVersion.String()) + if err != nil { + return err + } + success, _ = targetVersion.IsGreaterThanOrEqual(mainversion) + } + + // Release -> Release = Standard check + if (targetVersion.IsRelease() && currentVersion.IsRelease()) || + (targetVersion.IsPreRelease() && currentVersion.IsPreRelease()) { + + success, _ = targetVersion.IsGreaterThan(currentVersion) + } + + // Compare + if !success { + logger.Println("Error: The requested version is lower than the current version.") + logger.Println("If this is what you really want to do, use `wails update -version %s`", targetVersionString) + return nil + } + + desiredVersion = "v" + targetVersion.String() + + } else { + desiredVersion = "v" + targetVersion.String() + } + + fmt.Println() + logger.Print("Installing Wails CLI " + desiredVersion + "...") + + // Run command in non module directory + homeDir, err := os.UserHomeDir() + if err != nil { + log.Fatal("Cannot find home directory! Please file a bug report!") + } + + sout, serr, err := shell.RunCommand(homeDir, "go", "install", "github.com/wailsapp/wails/v2/cmd/wails@"+desiredVersion) + if err != nil { + logger.Println("Failed.") + logger.Println(sout + `\n` + serr) + return err + } + logger.Println("\n") + logger.Println("Wails CLI updated to " + desiredVersion) + logger.Println("Make sure you update your project go.mod file to use " + desiredVersion + ":") + logger.Println(" require github.com/wailsapp/wails/v2 " + desiredVersion) + + return nil +} diff --git a/v2/cmd/wails/internal/dev/dev.go b/v2/cmd/wails/internal/dev/dev.go deleted file mode 100644 index 9495b5bf2..000000000 --- a/v2/cmd/wails/internal/dev/dev.go +++ /dev/null @@ -1,525 +0,0 @@ -package dev - -import ( - "context" - "errors" - "fmt" - "io" - "log" - "net/http" - "net/url" - "os" - "os/exec" - "os/signal" - "path" - "path/filepath" - "strings" - "sync" - "sync/atomic" - "syscall" - "time" - - "github.com/samber/lo" - "github.com/wailsapp/wails/v2/cmd/wails/flags" - "github.com/wailsapp/wails/v2/cmd/wails/internal/gomod" - "github.com/wailsapp/wails/v2/cmd/wails/internal/logutils" - "golang.org/x/mod/semver" - - "github.com/wailsapp/wails/v2/pkg/commands/buildtags" - - "github.com/google/shlex" - - "github.com/pkg/browser" - - "github.com/fsnotify/fsnotify" - "github.com/wailsapp/wails/v2/internal/fs" - "github.com/wailsapp/wails/v2/internal/process" - "github.com/wailsapp/wails/v2/pkg/clilogger" - "github.com/wailsapp/wails/v2/pkg/commands/build" -) - -const ( - viteMinVersion = "v3.0.0" -) - -func sliceToMap(input []string) map[string]struct{} { - result := map[string]struct{}{} - for _, value := range input { - result[value] = struct{}{} - } - return result -} - -// Application runs the application in dev mode -func Application(f *flags.Dev, logger *clilogger.CLILogger) error { - cwd := lo.Must(os.Getwd()) - - // Update go.mod to use current wails version - err := gomod.SyncGoMod(logger, !f.NoSyncGoMod) - if err != nil { - return err - } - - if !f.SkipModTidy { - // Run go mod tidy to ensure we're up-to-date - err = runCommand(cwd, false, f.Compiler, "mod", "tidy") - if err != nil { - return err - } - } - - buildOptions := f.GenerateBuildOptions() - buildOptions.Logger = logger - - userTags, err := buildtags.Parse(f.Tags) - if err != nil { - return err - } - - projectConfig := f.ProjectConfig() - - projectTags, err := buildtags.Parse(projectConfig.BuildTags) - if err != nil { - return err - } - compiledTags := append(projectTags, userTags...) - buildOptions.UserTags = compiledTags - - // Setup signal handler - quitChannel := make(chan os.Signal, 1) - signal.Notify(quitChannel, os.Interrupt, syscall.SIGTERM) - exitCodeChannel := make(chan int, 1) - - // Build the frontend if requested, but ignore building the application itself. - ignoreFrontend := buildOptions.IgnoreFrontend - if !ignoreFrontend { - buildOptions.IgnoreApplication = true - if _, err := build.Build(buildOptions); err != nil { - return err - } - buildOptions.IgnoreApplication = false - } - - legacyUseDevServerInsteadofCustomScheme := false - // frontend:dev:watcher command. - frontendDevAutoDiscovery := projectConfig.IsFrontendDevServerURLAutoDiscovery() - if command := projectConfig.DevWatcherCommand; command != "" { - closer, devServerURL, devServerViteVersion, err := runFrontendDevWatcherCommand(projectConfig.GetFrontendDir(), command, frontendDevAutoDiscovery, projectConfig.ViteServerTimeout) - if err != nil { - return err - } - if devServerURL != "" { - projectConfig.FrontendDevServerURL = devServerURL - f.FrontendDevServerURL = devServerURL - } - defer closer() - - if devServerViteVersion != "" && semver.Compare(devServerViteVersion, viteMinVersion) < 0 { - logutils.LogRed("Please upgrade your Vite Server to at least '%s' future Wails versions will require at least Vite '%s'", viteMinVersion, viteMinVersion) - time.Sleep(3 * time.Second) - legacyUseDevServerInsteadofCustomScheme = true - } - } else if frontendDevAutoDiscovery { - return fmt.Errorf("unable to auto discover frontend:dev:serverUrl without a frontend:dev:watcher command, please either set frontend:dev:watcher or remove the auto discovery from frontend:dev:serverUrl") - } - - // Do initial build but only for the application. - logger.Println("Building application for development...") - buildOptions.IgnoreFrontend = true - debugBinaryProcess, appBinary, err := restartApp(buildOptions, nil, f, exitCodeChannel, legacyUseDevServerInsteadofCustomScheme) - buildOptions.IgnoreFrontend = ignoreFrontend || f.FrontendDevServerURL != "" - if err != nil { - return err - } - defer func() { - if err := killProcessAndCleanupBinary(debugBinaryProcess, appBinary); err != nil { - logutils.LogDarkYellow("Unable to kill process and cleanup binary: %s", err) - } - }() - - // open browser - if f.Browser { - err = browser.OpenURL(f.DevServerURL().String()) - if err != nil { - return err - } - } - - logutils.LogGreen("Using DevServer URL: %s", f.DevServerURL()) - if f.FrontendDevServerURL != "" { - logutils.LogGreen("Using Frontend DevServer URL: %s", f.FrontendDevServerURL) - } - logutils.LogGreen("Using reload debounce setting of %d milliseconds", f.Debounce) - - // Show dev server URL in terminal after 3 seconds - go func() { - time.Sleep(3 * time.Second) - logutils.LogGreen("\n\nTo develop in the browser and call your bound Go methods from Javascript, navigate to: %s", f.DevServerURL()) - }() - - // Watch for changes and trigger restartApp() - debugBinaryProcess, err = doWatcherLoop(cwd, projectConfig.ReloadDirectories, buildOptions, debugBinaryProcess, f, exitCodeChannel, quitChannel, f.DevServerURL(), legacyUseDevServerInsteadofCustomScheme) - if err != nil { - return err - } - - // Kill the current program if running and remove dev binary - if err := killProcessAndCleanupBinary(debugBinaryProcess, appBinary); err != nil { - return err - } - - // Reset the process and the binary so defer knows about it and is a nop. - debugBinaryProcess = nil - appBinary = "" - - logutils.LogGreen("Development mode exited") - - return nil -} - -func killProcessAndCleanupBinary(process *process.Process, binary string) error { - if process != nil && process.Running { - if err := process.Kill(); err != nil { - return err - } - } - - if binary != "" { - err := os.Remove(binary) - if err != nil && !errors.Is(err, os.ErrNotExist) { - return err - } - } - return nil -} - -func runCommand(dir string, exitOnError bool, command string, args ...string) error { - logutils.LogGreen("Executing: " + command + " " + strings.Join(args, " ")) - cmd := exec.Command(command, args...) - cmd.Dir = dir - output, err := cmd.CombinedOutput() - if err != nil { - println(string(output)) - println(err.Error()) - if exitOnError { - os.Exit(1) - } - return err - } - return nil -} - -// runFrontendDevWatcherCommand will run the `frontend:dev:watcher` command if it was given, ex- `npm run dev` -func runFrontendDevWatcherCommand(frontendDirectory string, devCommand string, discoverViteServerURL bool, viteServerTimeout int) (func(), string, string, error) { - ctx, cancel := context.WithCancel(context.Background()) - scanner := NewStdoutScanner() - cmdSlice := strings.Split(devCommand, " ") - cmd := exec.CommandContext(ctx, cmdSlice[0], cmdSlice[1:]...) - cmd.Stderr = os.Stderr - cmd.Stdout = scanner - cmd.Dir = frontendDirectory - setParentGID(cmd) - - if err := cmd.Start(); err != nil { - cancel() - return nil, "", "", fmt.Errorf("unable to start frontend DevWatcher: %w", err) - } - - var viteServerURL string - if discoverViteServerURL { - select { - case serverURL := <-scanner.ViteServerURLChan: - viteServerURL = serverURL - case <-time.After(time.Second * time.Duration(viteServerTimeout)): - cancel() - return nil, "", "", fmt.Errorf("failed to find Vite server URL: Timed out waiting for Vite to output a URL after %d seconds", viteServerTimeout) - } - } - - viteVersion := "" - select { - case version := <-scanner.ViteServerVersionC: - viteVersion = version - - case <-time.After(time.Second * 5): - // That's fine, then most probably it was not vite that was running - } - - logutils.LogGreen("Running frontend DevWatcher command: '%s'", devCommand) - var wg sync.WaitGroup - wg.Add(1) - - const ( - stateRunning int32 = 0 - stateCanceling int32 = 1 - stateStopped int32 = 2 - ) - state := stateRunning - go func() { - if err := cmd.Wait(); err != nil { - wasRunning := atomic.CompareAndSwapInt32(&state, stateRunning, stateStopped) - if err.Error() != "exit status 1" && wasRunning { - logutils.LogRed("Error from DevWatcher '%s': %s", devCommand, err.Error()) - } - } - atomic.StoreInt32(&state, stateStopped) - wg.Done() - }() - - return func() { - if atomic.CompareAndSwapInt32(&state, stateRunning, stateCanceling) { - killProc(cmd, devCommand) - } - cancel() - wg.Wait() - }, viteServerURL, viteVersion, nil -} - -// restartApp does the actual rebuilding of the application when files change -func restartApp(buildOptions *build.Options, debugBinaryProcess *process.Process, f *flags.Dev, exitCodeChannel chan int, legacyUseDevServerInsteadofCustomScheme bool) (*process.Process, string, error) { - appBinary, err := build.Build(buildOptions) - println() - if err != nil { - logutils.LogRed("Build error - " + err.Error()) - - msg := "Continuing to run current version" - if debugBinaryProcess == nil { - msg = "No version running, build will be retriggered as soon as changes have been detected" - } - logutils.LogDarkYellow(msg) - return nil, "", nil - } - - // Kill existing binary if need be - if debugBinaryProcess != nil { - killError := debugBinaryProcess.Kill() - - if killError != nil { - buildOptions.Logger.Fatal("Unable to kill debug binary (PID: %d)!", debugBinaryProcess.PID()) - } - - debugBinaryProcess = nil - } - - // parse appargs if any - args, err := shlex.Split(f.AppArgs) - if err != nil { - buildOptions.Logger.Fatal("Unable to parse appargs: %s", err.Error()) - } - - // Set environment variables accordingly - os.Setenv("loglevel", f.LogLevel) - os.Setenv("assetdir", f.AssetDir) - os.Setenv("devserver", f.DevServer) - os.Setenv("frontenddevserverurl", f.FrontendDevServerURL) - - // Start up new binary with correct args - newProcess := process.NewProcess(appBinary, args...) - err = newProcess.Start(exitCodeChannel) - if err != nil { - // Remove binary - if fs.FileExists(appBinary) { - deleteError := fs.DeleteFile(appBinary) - if deleteError != nil { - buildOptions.Logger.Fatal("Unable to delete app binary: " + appBinary) - } - } - buildOptions.Logger.Fatal("Unable to start application: %s", err.Error()) - } - - return newProcess, appBinary, nil -} - -// doWatcherLoop is the main watch loop that runs while dev is active -func doWatcherLoop(cwd string, reloadDirs string, buildOptions *build.Options, debugBinaryProcess *process.Process, f *flags.Dev, exitCodeChannel chan int, quitChannel chan os.Signal, devServerURL *url.URL, legacyUseDevServerInsteadofCustomScheme bool) (*process.Process, error) { - // create the project files watcher - watcher, err := initialiseWatcher(cwd, reloadDirs) - if err != nil { - logutils.LogRed("Unable to create filesystem watcher. Reloads will not occur.") - return nil, err - } - - defer func(watcher *fsnotify.Watcher) { - err := watcher.Close() - if err != nil { - log.Fatal(err.Error()) - } - }(watcher) - - logutils.LogGreen("Watching (sub)/directory: %s", cwd) - - // Main Loop - extensionsThatTriggerARebuild := sliceToMap(strings.Split(f.Extensions, ",")) - var dirsThatTriggerAReload []string - for _, dir := range strings.Split(f.ReloadDirs, ",") { - if dir == "" { - continue - } - thePath, err := filepath.Abs(dir) - if err != nil { - logutils.LogRed("Unable to expand reloadDir '%s': %s", dir, err) - continue - } - dirsThatTriggerAReload = append(dirsThatTriggerAReload, thePath) - err = watcher.Add(thePath) - if err != nil { - logutils.LogRed("Unable to watch path: %s due to error %v", thePath, err) - } else { - logutils.LogGreen("Watching (sub)/directory: %s", thePath) - } - } - - quit := false - interval := time.Duration(f.Debounce) * time.Millisecond - timer := time.NewTimer(interval) - rebuild := false - reload := false - assetDir := "" - changedPaths := map[string]struct{}{} - - // If we are using an external dev server, the reloading of the frontend part can be skipped or if the user requested it - skipAssetsReload := f.FrontendDevServerURL != "" || f.NoReload - - assetDirURL := joinPath(devServerURL, "/wails/assetdir") - reloadURL := joinPath(devServerURL, "/wails/reload") - for !quit { - // reload := false - select { - case exitCode := <-exitCodeChannel: - if exitCode == 0 { - quit = true - } - case err := <-watcher.Errors: - logutils.LogDarkYellow(err.Error()) - case item := <-watcher.Events: - isEligibleFile := func(fileName string) bool { - // Iterate all file patterns - ext := filepath.Ext(fileName) - if ext != "" { - ext = ext[1:] - if _, exists := extensionsThatTriggerARebuild[ext]; exists { - return true - } - } - return false - } - - // Handle write operations - if item.Op&fsnotify.Write == fsnotify.Write { - // Ignore directories - itemName := item.Name - if fs.DirExists(itemName) { - continue - } - - if isEligibleFile(itemName) { - rebuild = true - timer.Reset(interval) - continue - } - - for _, reloadDir := range dirsThatTriggerAReload { - if strings.HasPrefix(itemName, reloadDir) { - reload = true - break - } - } - - if !reload { - changedPaths[filepath.Dir(itemName)] = struct{}{} - } - - timer.Reset(interval) - } - - // Handle new fs entries that are created - if item.Op&fsnotify.Create == fsnotify.Create { - // If this is a folder, add it to our watch list - if fs.DirExists(item.Name) { - // node_modules is BANNED! - if !strings.Contains(item.Name, "node_modules") { - err := watcher.Add(item.Name) - if err != nil { - buildOptions.Logger.Fatal("%s", err.Error()) - } - logutils.LogGreen("Added new directory to watcher: %s", item.Name) - } - } else if isEligibleFile(item.Name) { - // Handle creation of new file. - // Note: On some platforms an update to a file is represented as - // REMOVE -> CREATE instead of WRITE, so this is not only new files - // but also updates to existing files - rebuild = true - timer.Reset(interval) - continue - } - } - case <-timer.C: - if rebuild { - rebuild = false - if f.NoGoRebuild { - logutils.LogGreen("[Rebuild triggered] skipping due to flag -nogorebuild") - } else { - logutils.LogGreen("[Rebuild triggered] files updated") - // Try and build the app - - newBinaryProcess, _, err := restartApp(buildOptions, debugBinaryProcess, f, exitCodeChannel, legacyUseDevServerInsteadofCustomScheme) - if err != nil { - logutils.LogRed("Error during build: %s", err.Error()) - continue - } - // If we have a new process, saveConfig it - if newBinaryProcess != nil { - debugBinaryProcess = newBinaryProcess - } - } - } - - if !skipAssetsReload && len(changedPaths) != 0 { - if assetDir == "" { - resp, err := http.Get(assetDirURL) - if err != nil { - logutils.LogRed("Error during retrieving assetdir: %s", err.Error()) - } else { - content, err := io.ReadAll(resp.Body) - if err != nil { - logutils.LogRed("Error reading assetdir from devserver: %s", err.Error()) - } else { - assetDir = string(content) - } - resp.Body.Close() - } - } - - if assetDir != "" { - for thePath := range changedPaths { - if strings.HasPrefix(thePath, assetDir) { - reload = true - break - } - } - } else if len(dirsThatTriggerAReload) == 0 { - logutils.LogRed("Reloading couldn't be triggered: Please specify -assetdir or -reloaddirs") - } - } - if reload { - reload = false - _, err := http.Get(reloadURL) - if err != nil { - logutils.LogRed("Error during refresh: %s", err.Error()) - } - } - changedPaths = map[string]struct{}{} - case <-quitChannel: - logutils.LogGreen("\nCaught quit") - quit = true - } - } - return debugBinaryProcess, nil -} - -func joinPath(url *url.URL, subPath string) string { - u := *url - u.Path = path.Join(u.Path, subPath) - return u.String() -} diff --git a/v2/cmd/wails/internal/dev/dev_other.go b/v2/cmd/wails/internal/dev/dev_other.go deleted file mode 100644 index 88e170ee3..000000000 --- a/v2/cmd/wails/internal/dev/dev_other.go +++ /dev/null @@ -1,37 +0,0 @@ -//go:build darwin || linux -// +build darwin linux - -package dev - -import ( - "os/exec" - "syscall" - - "github.com/wailsapp/wails/v2/cmd/wails/internal/logutils" - "golang.org/x/sys/unix" -) - -func setParentGID(cmd *exec.Cmd) { - cmd.SysProcAttr = &syscall.SysProcAttr{ - Setpgid: true, - } -} - -func killProc(cmd *exec.Cmd, devCommand string) { - if cmd == nil || cmd.Process == nil { - return - } - - // Experiencing the same issue on macOS BigSur - // I'm using Vite, but I would imagine this could be an issue with Node (npm) in general - // Also, after several edit/rebuild cycles any abnormal shutdown (crash or CTRL-C) may still leave Node running - // Credit: https://stackoverflow.com/a/29552044/14764450 (same page as the Windows solution above) - // Not tested on *nix - pgid, err := syscall.Getpgid(cmd.Process.Pid) - if err == nil { - err := syscall.Kill(-pgid, unix.SIGTERM) // note the minus sign - if err != nil { - logutils.LogRed("Error from '%s' when attempting to kill the process: %s", devCommand, err.Error()) - } - } -} diff --git a/v2/cmd/wails/internal/dev/dev_windows.go b/v2/cmd/wails/internal/dev/dev_windows.go deleted file mode 100644 index e219e6519..000000000 --- a/v2/cmd/wails/internal/dev/dev_windows.go +++ /dev/null @@ -1,34 +0,0 @@ -//go:build windows -// +build windows - -package dev - -import ( - "bytes" - "os/exec" - "strconv" - - "github.com/wailsapp/wails/v2/cmd/wails/internal/logutils" -) - -func setParentGID(_ *exec.Cmd) {} - -func killProc(cmd *exec.Cmd, devCommand string) { - // Credit: https://stackoverflow.com/a/44551450 - // For whatever reason, killing an npm script on windows just doesn't exit properly with cancel - if cmd != nil && cmd.Process != nil { - kill := exec.Command("TASKKILL", "/T", "/F", "/PID", strconv.Itoa(cmd.Process.Pid)) - var errorBuffer bytes.Buffer - var stdoutBuffer bytes.Buffer - kill.Stderr = &errorBuffer - kill.Stdout = &stdoutBuffer - err := kill.Run() - if err != nil { - if err.Error() != "exit status 1" { - println(stdoutBuffer.String()) - println(errorBuffer.String()) - logutils.LogRed("Error from '%s': %s", devCommand, err.Error()) - } - } - } -} diff --git a/v2/cmd/wails/internal/dev/stdout_scanner.go b/v2/cmd/wails/internal/dev/stdout_scanner.go deleted file mode 100644 index dad4e72cf..000000000 --- a/v2/cmd/wails/internal/dev/stdout_scanner.go +++ /dev/null @@ -1,84 +0,0 @@ -package dev - -import ( - "bufio" - "fmt" - "net/url" - "os" - "strings" - - "github.com/acarl005/stripansi" - "github.com/wailsapp/wails/v2/cmd/wails/internal/logutils" - "golang.org/x/mod/semver" -) - -// stdoutScanner acts as a stdout target that will scan the incoming -// data to find out the vite server url -type stdoutScanner struct { - ViteServerURLChan chan string - ViteServerVersionC chan string - versionDetected bool -} - -// NewStdoutScanner creates a new stdoutScanner -func NewStdoutScanner() *stdoutScanner { - return &stdoutScanner{ - ViteServerURLChan: make(chan string, 2), - ViteServerVersionC: make(chan string, 2), - } -} - -// Write bytes to the scanner. Will copy the bytes to stdout -func (s *stdoutScanner) Write(data []byte) (n int, err error) { - input := stripansi.Strip(string(data)) - if !s.versionDetected { - v, err := detectViteVersion(input) - if v != "" || err != nil { - if err != nil { - logutils.LogRed("ViteStdoutScanner: %s", err) - v = "v0.0.0" - } - s.ViteServerVersionC <- v - s.versionDetected = true - } - } - - match := strings.Index(input, "Local:") - if match != -1 { - sc := bufio.NewScanner(strings.NewReader(input)) - for sc.Scan() { - line := sc.Text() - index := strings.Index(line, "Local:") - if index == -1 || len(line) < 7 { - continue - } - viteServerURL := strings.TrimSpace(line[index+6:]) - logutils.LogGreen("Vite Server URL: %s", viteServerURL) - _, err := url.Parse(viteServerURL) - if err != nil { - logutils.LogRed(err.Error()) - } else { - s.ViteServerURLChan <- viteServerURL - } - } - } - return os.Stdout.Write(data) -} - -func detectViteVersion(line string) (string, error) { - s := strings.Split(strings.TrimSpace(line), " ") - if strings.ToLower(s[0]) != "vite" { - return "", nil - } - - if len(line) < 2 { - return "", fmt.Errorf("unable to parse vite version") - } - - v := s[1] - if !semver.IsValid(v) { - return "", fmt.Errorf("%s is not a valid vite version string", v) - } - - return v, nil -} diff --git a/v2/cmd/wails/internal/dev/watcher.go b/v2/cmd/wails/internal/dev/watcher.go deleted file mode 100644 index e1161f87c..000000000 --- a/v2/cmd/wails/internal/dev/watcher.go +++ /dev/null @@ -1,78 +0,0 @@ -package dev - -import ( - "bufio" - "os" - "path/filepath" - "strings" - - "github.com/wailsapp/wails/v2/internal/fs" - - "github.com/fsnotify/fsnotify" - gitignore "github.com/sabhiram/go-gitignore" - "github.com/samber/lo" -) - -type Watcher interface { - Add(name string) error -} - -// initialiseWatcher creates the project directory watcher that will trigger recompile -func initialiseWatcher(cwd, reloadDirs string) (*fsnotify.Watcher, error) { - // Ignore dot files, node_modules and build directories by default - ignoreDirs := getIgnoreDirs(cwd) - - // Get all subdirectories - dirs, err := fs.GetSubdirectories(cwd) - if err != nil { - return nil, err - } - - customDirs := dirs.AsSlice() - seperatedDirs := strings.Split(reloadDirs, ",") - for _, dir := range seperatedDirs { - customSub, err := fs.GetSubdirectories(filepath.Join(cwd, dir)) - if err != nil { - return nil, err - } - customDirs = append(customDirs, customSub.AsSlice()...) - } - - watcher, err := fsnotify.NewWatcher() - if err != nil { - return nil, err - } - - for _, dir := range processDirectories(customDirs, ignoreDirs) { - err := watcher.Add(dir) - if err != nil { - return nil, err - } - } - return watcher, nil -} - -func getIgnoreDirs(cwd string) []string { - ignoreDirs := []string{filepath.Join(cwd, "build/*"), ".*", "node_modules"} - baseDir := filepath.Base(cwd) - // Read .gitignore into ignoreDirs - f, err := os.Open(filepath.Join(cwd, ".gitignore")) - if err == nil { - scanner := bufio.NewScanner(f) - for scanner.Scan() { - line := scanner.Text() - if line != baseDir { - ignoreDirs = append(ignoreDirs, line) - } - } - } - - return lo.Uniq(ignoreDirs) -} - -func processDirectories(dirs []string, ignoreDirs []string) []string { - ignorer := gitignore.CompileIgnoreLines(ignoreDirs...) - return lo.Filter(dirs, func(dir string, _ int) bool { - return !ignorer.MatchesPath(dir) - }) -} diff --git a/v2/cmd/wails/internal/dev/watcher_test.go b/v2/cmd/wails/internal/dev/watcher_test.go deleted file mode 100644 index ad228b66c..000000000 --- a/v2/cmd/wails/internal/dev/watcher_test.go +++ /dev/null @@ -1,113 +0,0 @@ -package dev - -import ( - "github.com/samber/lo" - "os" - "path/filepath" - "reflect" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/wailsapp/wails/v2/internal/fs" -) - -func Test_processDirectories(t *testing.T) { - tests := []struct { - name string - dirs []string - ignoreDirs []string - want []string - }{ - { - name: "Should ignore .git", - ignoreDirs: []string{".git"}, - dirs: []string{".git", "some/path/to/nested/.git", "some/path/to/nested/.git/CHANGELOG"}, - want: []string{}, - }, - { - name: "Should ignore node_modules", - ignoreDirs: []string{"node_modules"}, - dirs: []string{"node_modules", "path/to/node_modules", "path/to/node_modules/some/other/path"}, - want: []string{}, - }, - { - name: "Should ignore dirs starting with .", - ignoreDirs: []string{".*"}, - dirs: []string{".test", ".gitignore", ".someother", "valid"}, - want: []string{"valid"}, - }, - { - name: "Should ignore dirs in ignoreDirs", - dirs: []string{"build", "build/my.exe", "build/my.app"}, - ignoreDirs: []string{"build"}, - want: []string{}, - }, - { - name: "Should ignore subdirectories", - dirs: []string{"build", "some/path/to/build", "some/path/to/CHANGELOG", "some/other/path"}, - ignoreDirs: []string{"some/**/*"}, - want: []string{"build"}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := processDirectories(tt.dirs, tt.ignoreDirs) - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("processDirectories() got = %v, want %v", got, tt.want) - } - }) - } -} - -func Test_GetIgnoreDirs(t *testing.T) { - - // Remove testdir if it exists - _ = os.RemoveAll("testdir") - - tests := []struct { - name string - files []string - want []string - shouldErr bool - }{ - { - name: "Should have defaults", - files: []string{}, - want: []string{"testdir/build/*", ".*", "node_modules"}, - }, - { - name: "Should ignore dotFiles", - files: []string{".test1", ".wailsignore"}, - want: []string{"testdir/build/*", ".*", "node_modules"}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - // Create temporary file - err := fs.Mkdir("testdir") - require.NoError(t, err) - defer func() { - err := os.RemoveAll("testdir") - require.NoError(t, err) - }() - for _, file := range tt.files { - fs.MustWriteString(filepath.Join("testdir", file), "") - } - - got := getIgnoreDirs("testdir") - - got = lo.Map(got, func(s string, _ int) string { - return filepath.ToSlash(s) - }) - - if (err != nil) != tt.shouldErr { - t.Errorf("initialiseWatcher() error = %v, shouldErr %v", err, tt.shouldErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("initialiseWatcher() got = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/v2/cmd/wails/internal/gomod/gomod.go b/v2/cmd/wails/internal/gomod/gomod.go deleted file mode 100644 index 5da14a5ff..000000000 --- a/v2/cmd/wails/internal/gomod/gomod.go +++ /dev/null @@ -1,68 +0,0 @@ -package gomod - -import ( - "fmt" - "os" - "strings" - - "github.com/wailsapp/wails/v2/cmd/wails/internal" - "github.com/wailsapp/wails/v2/internal/colour" - "github.com/wailsapp/wails/v2/internal/fs" - "github.com/wailsapp/wails/v2/internal/gomod" - "github.com/wailsapp/wails/v2/internal/goversion" - "github.com/wailsapp/wails/v2/pkg/clilogger" -) - -func SyncGoMod(logger *clilogger.CLILogger, updateWailsVersion bool) error { - cwd, err := os.Getwd() - if err != nil { - return err - } - gomodFilename := fs.FindFileInParents(cwd, "go.mod") - if gomodFilename == "" { - return fmt.Errorf("no go.mod file found") - } - gomodData, err := os.ReadFile(gomodFilename) - if err != nil { - return err - } - - gomodData, updated, err := gomod.SyncGoVersion(gomodData, goversion.MinRequirement) - if err != nil { - return err - } else if updated { - LogGreen("Updated go.mod to use Go '%s'", goversion.MinRequirement) - } - - internalVersion := strings.TrimSpace(internal.Version) - if outOfSync, err := gomod.GoModOutOfSync(gomodData, internalVersion); err != nil { - return err - } else if outOfSync { - if updateWailsVersion { - LogGreen("Updating go.mod to use Wails '%s'", internalVersion) - gomodData, err = gomod.UpdateGoModVersion(gomodData, internalVersion) - if err != nil { - return err - } - updated = true - } else { - gomodversion, err := gomod.GetWailsVersionFromModFile(gomodData) - if err != nil { - return err - } - - logger.Println("Warning: go.mod is using Wails '%s' but the CLI is '%s'. Consider updating your project's `go.mod` file.\n", gomodversion.String(), internal.Version) - } - } - - if updated { - return os.WriteFile(gomodFilename, gomodData, 0o755) - } - - return nil -} - -func LogGreen(message string, args ...interface{}) { - text := fmt.Sprintf(message, args...) - println(colour.Green(text)) -} diff --git a/v2/cmd/wails/internal/logutils/color-logs.go b/v2/cmd/wails/internal/logutils/color-logs.go deleted file mode 100644 index 65553df3f..000000000 --- a/v2/cmd/wails/internal/logutils/color-logs.go +++ /dev/null @@ -1,31 +0,0 @@ -package logutils - -import ( - "fmt" - - "github.com/wailsapp/wails/v2/internal/colour" -) - -func LogGreen(message string, args ...interface{}) { - if len(message) == 0 { - return - } - text := fmt.Sprintf(message, args...) - println(colour.Green(text)) -} - -func LogRed(message string, args ...interface{}) { - if len(message) == 0 { - return - } - text := fmt.Sprintf(message, args...) - println(colour.Red(text)) -} - -func LogDarkYellow(message string, args ...interface{}) { - if len(message) == 0 { - return - } - text := fmt.Sprintf(message, args...) - println(colour.DarkYellow(text)) -} diff --git a/v2/cmd/wails/internal/tags.go b/v2/cmd/wails/internal/tags.go new file mode 100644 index 000000000..42743028d --- /dev/null +++ b/v2/cmd/wails/internal/tags.go @@ -0,0 +1,15 @@ +package internal + +import "strings" + +// ParseUserTags takes the string form of tags and converts to a slice of strings +func ParseUserTags(tagString string) []string { + userTags := make([]string, 0) + for _, tag := range strings.Split(tagString, " ") { + thisTag := strings.TrimSpace(tag) + if thisTag != "" { + userTags = append(userTags, thisTag) + } + } + return userTags +} diff --git a/v2/cmd/wails/internal/template/base/README.md b/v2/cmd/wails/internal/template/base/README.md deleted file mode 100644 index ed259fcff..000000000 --- a/v2/cmd/wails/internal/template/base/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# README - -## About - -About your template - -## Live Development - -To run in live development mode, run `wails dev` in the project directory. In another terminal, go into the `frontend` -directory and run `npm run dev`. The frontend dev server will run on http://localhost:34115. Connect to this in your -browser and connect to your application. - -## Building - -To build a redistributable, production mode package, use `wails build`. diff --git a/v2/cmd/wails/internal/template/base/app.tmpl.go b/v2/cmd/wails/internal/template/base/app.tmpl.go deleted file mode 100644 index 224be7156..000000000 --- a/v2/cmd/wails/internal/template/base/app.tmpl.go +++ /dev/null @@ -1,44 +0,0 @@ -package main - -import ( - "context" - "fmt" -) - -// App struct -type App struct { - ctx context.Context -} - -// NewApp creates a new App application struct -func NewApp() *App { - return &App{} -} - -// startup is called at application startup -func (a *App) startup(ctx context.Context) { - // Perform your setup here - a.ctx = ctx -} - -// domReady is called after front-end resources have been loaded -func (a App) domReady(ctx context.Context) { - // Add your action here -} - -// beforeClose is called when the application is about to quit, -// either by clicking the window close button or calling runtime.Quit. -// Returning true will cause the application to continue, false will continue shutdown as normal. -func (a *App) beforeClose(ctx context.Context) (prevent bool) { - return false -} - -// shutdown is called at application termination -func (a *App) shutdown(ctx context.Context) { - // Perform your teardown here -} - -// Greet returns a greeting for the given name -func (a *App) Greet(name string) string { - return fmt.Sprintf("Hello %s, It's show time!", name) -} diff --git a/v2/cmd/wails/internal/template/base/frontend/dist/assets/images/logo-universal.png b/v2/cmd/wails/internal/template/base/frontend/dist/assets/images/logo-universal.png deleted file mode 100644 index 27ef13655..000000000 Binary files a/v2/cmd/wails/internal/template/base/frontend/dist/assets/images/logo-universal.png and /dev/null differ diff --git a/v2/cmd/wails/internal/template/base/frontend/dist/index.html b/v2/cmd/wails/internal/template/base/frontend/dist/index.html deleted file mode 100644 index e2a14c1b5..000000000 --- a/v2/cmd/wails/internal/template/base/frontend/dist/index.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - -
- -
Please enter your name below 👇
-
- - -
-
- - - diff --git a/v2/cmd/wails/internal/template/base/frontend/dist/main.css b/v2/cmd/wails/internal/template/base/frontend/dist/main.css deleted file mode 100644 index f35a69f99..000000000 --- a/v2/cmd/wails/internal/template/base/frontend/dist/main.css +++ /dev/null @@ -1,79 +0,0 @@ -html { - background-color: rgba(27, 38, 54, 1); - text-align: center; - color: white; -} - -body { - margin: 0; - color: white; - font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", - "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", - sans-serif; -} - -@font-face { - font-family: "Nunito"; - font-style: normal; - font-weight: 400; - src: local(""), - url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2"); -} - -#app { - height: 100vh; - text-align: center; -} - -.logo { - display: block; - width: 50%; - height: 50%; - margin: auto; - padding: 10% 0 0; - background-position: center; - background-repeat: no-repeat; - background-image: url("./assets/images/logo-universal.png"); - background-size: 100% 100%; - background-origin: content-box; -} -.result { - height: 20px; - line-height: 20px; - margin: 1.5rem auto; -} -.input-box .btn { - width: 60px; - height: 30px; - line-height: 30px; - border-radius: 3px; - border: none; - margin: 0 0 0 20px; - padding: 0 8px; - cursor: pointer; -} -.input-box .btn:hover { - background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%); - color: #333333; -} - -.input-box .input { - border: none; - border-radius: 3px; - outline: none; - height: 30px; - line-height: 30px; - padding: 0 10px; - background-color: rgba(240, 240, 240, 1); - -webkit-font-smoothing: antialiased; -} - -.input-box .input:hover { - border: none; - background-color: rgba(255, 255, 255, 1); -} - -.input-box .input:focus { - border: none; - background-color: rgba(255, 255, 255, 1); -} diff --git a/v2/cmd/wails/internal/template/base/frontend/dist/main.js b/v2/cmd/wails/internal/template/base/frontend/dist/main.js deleted file mode 100644 index 98510cd39..000000000 --- a/v2/cmd/wails/internal/template/base/frontend/dist/main.js +++ /dev/null @@ -1,32 +0,0 @@ -// Get input + focus -let nameElement = document.getElementById("name"); -nameElement.focus(); - -// Setup the greet function -window.greet = function () { - // Get name - let name = nameElement.value; - - // Check if the input is empty - if (name === "") return; - - // Call App.Greet(name) - try { - window.go.main.App.Greet(name) - .then((result) => { - // Update result with data back from App.Greet() - document.getElementById("result").innerText = result; - }) - .catch((err) => { - console.error(err); - }); - } catch (err) { - console.error(err); - } -}; - -nameElement.onkeydown = function (e) { - if (e.keyCode == 13) { - window.greet(); - } -}; diff --git a/v2/cmd/wails/internal/template/base/go.sum b/v2/cmd/wails/internal/template/base/go.sum deleted file mode 100644 index 92f4d6d57..000000000 --- a/v2/cmd/wails/internal/template/base/go.sum +++ /dev/null @@ -1,180 +0,0 @@ -github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= -github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= -github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= -github.com/flytam/filenamify v1.0.0/go.mod h1:Dzf9kVycwcsBlr2ATg6uxjqiFgKGH+5SKFuhdeP5zu8= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= -github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= -github.com/go-git/go-billy/v5 v5.1.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= -github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= -github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= -github.com/go-git/go-git/v5 v5.3.0/go.mod h1:xdX4bWJ48aOrdhnl2XqHYstHbbp6+LFS4r4X+lNVprw= -github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= -github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= -github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= -github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/jackmordaunt/icns v1.0.0/go.mod h1:7TTQVEuGzVVfOPPlLNHJIkzA6CoV7aH1Dv9dW351oOo= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck= -github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs= -github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= -github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/labstack/echo/v4 v4.7.2 h1:Kv2/p8OaQ+M6Ex4eGimg9b9e6icoxA42JSlOR3msKtI= -github.com/labstack/echo/v4 v4.7.2/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks= -github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o= -github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= -github.com/leaanthony/clir v1.0.4/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0= -github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc= -github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA= -github.com/leaanthony/go-ansi-parser v1.0.1 h1:97v6c5kYppVsbScf4r/VZdXyQ21KQIfeQOk2DgKxGG4= -github.com/leaanthony/go-ansi-parser v1.0.1/go.mod h1:7arTzgVI47srICYhvgUV4CGd063sGEeoSlych5yeSPM= -github.com/leaanthony/gosod v1.0.3 h1:Fnt+/B6NjQOVuCWOKYRREZnjGyvg+mEhd1nkkA04aTQ= -github.com/leaanthony/gosod v1.0.3/go.mod h1:BJ2J+oHsQIyIQpnLPjnqFGTMnOZXDbvWtRCSG7jGxs4= -github.com/leaanthony/idgen v1.0.0/go.mod h1:4nBZnt8ml/f/ic/EVQuLxuj817RccT2fyrUaZFxrcVA= -github.com/leaanthony/slicer v1.5.0 h1:aHYTN8xbCCLxJmkNKiLB6tgcMARl4eWmH9/F+S/0HtY= -github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY= -github.com/leaanthony/typescriptify-golang-structs v0.1.7 h1:yoznzWzyxkO/iWdlpq+aPcuJ5Y/hpjq/lmgMFmpjwl0= -github.com/leaanthony/typescriptify-golang-structs v0.1.7/go.mod h1:cWtOkiVhMF77e6phAXUcfNwYmMwCJ67Sij24lfvi9Js= -github.com/leaanthony/winicon v1.0.0/go.mod h1:en5xhijl92aphrJdmRPlh4NI1L6wq3gEm0LpXAPghjU= -github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= -github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= -github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= -github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs= -github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= -github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 h1:acNfDZXmm28D2Yg/c3ALnZStzNaZMSagpbr96vY6Zjc= -github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/tc-hib/winres v0.1.5/go.mod h1:pe6dOR40VOrGz8PkzreVKNvEKnlE8t4yR8A8naL+t7A= -github.com/tidwall/gjson v1.8.0/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk= -github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/tidwall/sjson v1.1.7/go.mod h1:w/yG+ezBeTdUxiKs5NcPicO9diP38nk96QBAbIIGeFs= -github.com/tkrajina/go-reflector v0.5.5 h1:gwoQFNye30Kk7NrExj8zm3zFtrGPqOkzFMLuQZg1DtQ= -github.com/tkrajina/go-reflector v0.5.5/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4= -github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4= -github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -github.com/wailsapp/mimetype v1.4.1-beta.1.0.20220331112158-6df7e41671fe h1:FiWQ7XhDkc4zAH8SEx1BTte/6VHyceraUusH8jf5SQw= -github.com/wailsapp/mimetype v1.4.1-beta.1.0.20220331112158-6df7e41671fe/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o= -github.com/wzshiming/ctc v1.2.3/go.mod h1:2tVAtIY7SUyraSk0JxvwmONNPFL4ARavPuEsg5+KA28= -github.com/wzshiming/winseq v0.0.0-20200112104235-db357dc107ae/go.mod h1:VTAq37rkGeV+WOybvZwjXiJOicICdpLCN8ifpISjK20= -github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/ztrue/tracerr v0.3.0/go.mod h1:qEalzze4VN9O8tnhBXScfCrmoJo10o8TN5ciKjm6Mww= -golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= -golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/v2/cmd/wails/internal/template/base/go.tmpl.mod b/v2/cmd/wails/internal/template/base/go.tmpl.mod deleted file mode 100644 index 42478753c..000000000 --- a/v2/cmd/wails/internal/template/base/go.tmpl.mod +++ /dev/null @@ -1,32 +0,0 @@ -module changeme - - go 1.18 - - require github.com/wailsapp/wails/v2 {{.WailsVersion}} - - require ( - github.com/go-ole/go-ole v1.2.6 // indirect - github.com/google/uuid v1.1.2 // indirect - github.com/imdario/mergo v0.3.12 // indirect - github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect - github.com/labstack/echo/v4 v4.7.2 // indirect - github.com/labstack/gommon v0.3.1 // indirect - github.com/leaanthony/go-ansi-parser v1.0.1 // indirect - github.com/leaanthony/gosod v1.0.3 // indirect - github.com/leaanthony/slicer v1.5.0 // indirect - github.com/leaanthony/typescriptify-golang-structs v0.1.7 // indirect - github.com/mattn/go-colorable v0.1.11 // indirect - github.com/mattn/go-isatty v0.0.14 // indirect - github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect - github.com/pkg/errors v0.9.1 // indirect - github.com/tkrajina/go-reflector v0.5.5 // indirect - github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasttemplate v1.2.1 // indirect - github.com/wailsapp/mimetype v1.4.1-beta.1.0.20220331112158-6df7e41671fe // indirect - golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect - golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f // indirect - golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect - golang.org/x/text v0.3.7 // indirect - ) - - // replace github.com/wailsapp/wails/v2 {{.WailsVersion}} => {{.WailsDirectory}} \ No newline at end of file diff --git a/v2/cmd/wails/internal/template/base/main.go.tmpl b/v2/cmd/wails/internal/template/base/main.go.tmpl deleted file mode 100644 index d8e902027..000000000 --- a/v2/cmd/wails/internal/template/base/main.go.tmpl +++ /dev/null @@ -1,87 +0,0 @@ -package main - -import ( - "embed" - "log" - - "github.com/wailsapp/wails/v2" - "github.com/wailsapp/wails/v2/pkg/logger" - "github.com/wailsapp/wails/v2/pkg/options" - "github.com/wailsapp/wails/v2/pkg/options/assetserver" - "github.com/wailsapp/wails/v2/pkg/options/mac" - "github.com/wailsapp/wails/v2/pkg/options/windows" -) - -//go:embed all:frontend/dist -var assets embed.FS - -//go:embed build/appicon.png -var icon []byte - -func main() { - // Create an instance of the app structure - app := NewApp() - - // Create application with options - err := wails.Run(&options.App{ - Title: "{{.ProjectName}}", - Width: 1024, - Height: 768, - MinWidth: 1024, - MinHeight: 768, - MaxWidth: 1280, - MaxHeight: 800, - DisableResize: false, - Fullscreen: false, - Frameless: false, - StartHidden: false, - HideWindowOnClose: false, - BackgroundColour: &options.RGBA{R: 255, G: 255, B: 255, A: 255}, - AssetServer: &assetserver.Options{ - Assets: assets, - }, - Menu: nil, - Logger: nil, - LogLevel: logger.DEBUG, - OnStartup: app.startup, - OnDomReady: app.domReady, - OnBeforeClose: app.beforeClose, - OnShutdown: app.shutdown, - WindowStartState: options.Normal, - Bind: []interface{}{ - app, - }, - // Windows platform specific options - Windows: &windows.Options{ - WebviewIsTransparent: false, - WindowIsTranslucent: false, - DisableWindowIcon: false, - // DisableFramelessWindowDecorations: false, - WebviewUserDataPath: "", - ZoomFactor: 1.0, - }, - // Mac platform specific options - Mac: &mac.Options{ - TitleBar: &mac.TitleBar{ - TitlebarAppearsTransparent: true, - HideTitle: false, - HideTitleBar: false, - FullSizeContent: false, - UseToolbar: false, - HideToolbarSeparator: true, - }, - Appearance: mac.NSAppearanceNameDarkAqua, - WebviewIsTransparent: true, - WindowIsTranslucent: true, - About: &mac.AboutInfo{ - Title: "{{.ProjectName}}", - Message: "", - Icon: icon, - }, - }, - }) - - if err != nil { - log.Fatal(err) - } -} diff --git a/v2/cmd/wails/internal/template/base/scripts/build-macos-arm.sh b/v2/cmd/wails/internal/template/base/scripts/build-macos-arm.sh deleted file mode 100644 index bc6ee0acb..000000000 --- a/v2/cmd/wails/internal/template/base/scripts/build-macos-arm.sh +++ /dev/null @@ -1,9 +0,0 @@ -#! /bin/bash - -echo -e "Start running the script..." -cd ../ - -echo -e "Start building the app for macos platform..." -wails build --clean --platform darwin/arm64 - -echo -e "End running the script!" diff --git a/v2/cmd/wails/internal/template/base/scripts/build-macos-intel.sh b/v2/cmd/wails/internal/template/base/scripts/build-macos-intel.sh deleted file mode 100644 index f359f633a..000000000 --- a/v2/cmd/wails/internal/template/base/scripts/build-macos-intel.sh +++ /dev/null @@ -1,9 +0,0 @@ -#! /bin/bash - -echo -e "Start running the script..." -cd ../ - -echo -e "Start building the app for macos platform..." -wails build --clean --platform darwin - -echo -e "End running the script!" diff --git a/v2/cmd/wails/internal/template/base/scripts/build-macos.sh b/v2/cmd/wails/internal/template/base/scripts/build-macos.sh deleted file mode 100644 index d61531fd7..000000000 --- a/v2/cmd/wails/internal/template/base/scripts/build-macos.sh +++ /dev/null @@ -1,9 +0,0 @@ -#! /bin/bash - -echo -e "Start running the script..." -cd ../ - -echo -e "Start building the app for macos platform..." -wails build --clean --platform darwin/universal - -echo -e "End running the script!" diff --git a/v2/cmd/wails/internal/template/base/scripts/build-windows.sh b/v2/cmd/wails/internal/template/base/scripts/build-windows.sh deleted file mode 100644 index 47b778970..000000000 --- a/v2/cmd/wails/internal/template/base/scripts/build-windows.sh +++ /dev/null @@ -1,9 +0,0 @@ -#! /bin/bash - -echo -e "Start running the script..." -cd ../ - -echo -e "Start building the app for windows platform..." -wails build --clean --platform windows/amd64 - -echo -e "End running the script!" diff --git a/v2/cmd/wails/internal/template/base/scripts/build.sh b/v2/cmd/wails/internal/template/base/scripts/build.sh deleted file mode 100644 index 20ab7eb21..000000000 --- a/v2/cmd/wails/internal/template/base/scripts/build.sh +++ /dev/null @@ -1,9 +0,0 @@ -#! /bin/bash - -echo -e "Start running the script..." -cd ../ - -echo -e "Start building the app..." -wails build --clean - -echo -e "End running the script!" diff --git a/v2/cmd/wails/internal/template/base/scripts/install-wails-cli.sh b/v2/cmd/wails/internal/template/base/scripts/install-wails-cli.sh deleted file mode 100644 index 7539d8e33..000000000 --- a/v2/cmd/wails/internal/template/base/scripts/install-wails-cli.sh +++ /dev/null @@ -1,14 +0,0 @@ -#! /bin/bash - -echo -e "Start running the script..." -cd ../ - -echo -e "Current Go version: \c" -go version - -echo -e "Install the Wails command line tool..." -go install github.com/wailsapp/wails/v2/cmd/wails@latest - -echo -e "Successful installation!" - -echo -e "End running the script!" diff --git a/v2/cmd/wails/internal/template/base/wails.tmpl.json b/v2/cmd/wails/internal/template/base/wails.tmpl.json deleted file mode 100644 index cdb10e346..000000000 --- a/v2/cmd/wails/internal/template/base/wails.tmpl.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "$schema": "https://wails.io/schemas/config.v2.json", - "name": "{{.ProjectName}}", - "outputfilename": "{{.BinaryName}}", - "frontend:install": "npm install", - "frontend:build": "npm run build", - "author": { - "name": "{{.AuthorName}}", - "email": "{{.AuthorEmail}}" - } -} diff --git a/v2/cmd/wails/internal/template/template.go b/v2/cmd/wails/internal/template/template.go deleted file mode 100644 index 6b4937db6..000000000 --- a/v2/cmd/wails/internal/template/template.go +++ /dev/null @@ -1,8 +0,0 @@ -package template - -import ( - "embed" -) - -//go:embed base -var Base embed.FS diff --git a/v2/cmd/wails/internal/version.go b/v2/cmd/wails/internal/version.go index cfc37182c..4e6e434db 100644 --- a/v2/cmd/wails/internal/version.go +++ b/v2/cmd/wails/internal/version.go @@ -1,6 +1,3 @@ package internal -import _ "embed" - -//go:embed version.txt -var Version string +var Version = "v2.0.0-beta.15" diff --git a/v2/cmd/wails/internal/version.txt b/v2/cmd/wails/internal/version.txt deleted file mode 100644 index 805579f30..000000000 --- a/v2/cmd/wails/internal/version.txt +++ /dev/null @@ -1 +0,0 @@ -v2.11.0 \ No newline at end of file diff --git a/v2/cmd/wails/main.go b/v2/cmd/wails/main.go index ccf1576e9..e69db18d7 100644 --- a/v2/cmd/wails/main.go +++ b/v2/cmd/wails/main.go @@ -2,100 +2,80 @@ package main import ( "fmt" - "os" - "strings" - - "github.com/pterm/pterm" "github.com/wailsapp/wails/v2/cmd/wails/internal" + "os" "github.com/wailsapp/wails/v2/internal/colour" + "github.com/wailsapp/wails/v2/cmd/wails/internal/commands/update" + "github.com/leaanthony/clir" + "github.com/wailsapp/wails/v2/cmd/wails/internal/commands/build" + "github.com/wailsapp/wails/v2/cmd/wails/internal/commands/dev" + "github.com/wailsapp/wails/v2/cmd/wails/internal/commands/doctor" + "github.com/wailsapp/wails/v2/cmd/wails/internal/commands/generate" + "github.com/wailsapp/wails/v2/cmd/wails/internal/commands/initialise" ) -func banner(_ *clir.Cli) string { - return fmt.Sprintf("%s %s", - colour.Green("Wails CLI"), - colour.DarkRed(internal.Version)) -} - func fatal(message string) { - printer := pterm.PrefixPrinter{ - MessageStyle: &pterm.ThemeDefault.FatalMessageStyle, - Prefix: pterm.Prefix{ - Style: &pterm.ThemeDefault.FatalPrefixStyle, - Text: " FATAL ", - }, - } - printer.Println(message) + println(message) os.Exit(1) } -func printBulletPoint(text string, args ...any) { - item := pterm.BulletListItem{ - Level: 2, - Text: text, - } - t, err := pterm.DefaultBulletList.WithItems([]pterm.BulletListItem{item}).Srender() - if err != nil { - fatal(err.Error()) - } - t = strings.Trim(t, "\n\r") - pterm.Printfln(t, args...) +func banner(_ *clir.Cli) string { + return fmt.Sprintf("%s %s\n", + colour.Yellow("Wails CLI"), + colour.DarkRed(internal.Version)) } func printFooter() { - printer := pterm.PrefixPrinter{ - MessageStyle: pterm.NewStyle(pterm.FgLightGreen), - Prefix: pterm.Prefix{ - Style: pterm.NewStyle(pterm.FgRed, pterm.BgLightWhite), - Text: "♥ ", - }, - } - printer.Println("If Wails is useful to you or your company, please consider sponsoring the project:") - pterm.Println("https://github.com/sponsors/leaanthony") + println(colour.Yellow("\nIf Wails is useful to you or your company, please consider sponsoring the project:\nhttps://github.com/sponsors/leaanthony\n")) } -func bool2Str(b bool) string { - if b { - return "true" - } - return "false" -} - -var app *clir.Cli - func main() { + var err error - app = clir.NewCli("Wails", "Go/HTML Appkit", internal.Version) + app := clir.NewCli("Wails", "Go/HTML Appkit", internal.Version) app.SetBannerFunction(banner) defer printFooter() - app.NewSubCommandFunction("build", "Builds the application", buildApplication) - app.NewSubCommandFunction("dev", "Runs the application in development mode", devApplication) - app.NewSubCommandFunction("doctor", "Diagnose your environment", diagnoseEnvironment) - app.NewSubCommandFunction("init", "Initialises a new Wails project", initProject) - app.NewSubCommandFunction("update", "Update the Wails CLI", update) + build.AddBuildSubcommand(app, os.Stdout) + err = initialise.AddSubcommand(app, os.Stdout) + if err != nil { + fatal(err.Error()) + } - show := app.NewSubCommand("show", "Shows various information") - show.NewSubCommandFunction("releasenotes", "Shows the release notes for the current version", showReleaseNotes) + err = doctor.AddSubcommand(app, os.Stdout) + if err != nil { + fatal(err.Error()) + } - generate := app.NewSubCommand("generate", "Code Generation Tools") - generate.NewSubCommandFunction("module", "Generates a new Wails module", generateModule) - generate.NewSubCommandFunction("template", "Generates a new Wails template", generateTemplate) + err = dev.AddSubcommand(app, os.Stdout) + if err != nil { + fatal(err.Error()) + } + + err = generate.AddSubcommand(app, os.Stdout) + if err != nil { + fatal(err.Error()) + } + + err = update.AddSubcommand(app, os.Stdout, internal.Version) + if err != nil { + fatal(err.Error()) + } command := app.NewSubCommand("version", "The Wails CLI version") command.Action(func() error { - pterm.Println(internal.Version) + println(internal.Version) return nil }) err = app.Run() if err != nil { - pterm.Println() - pterm.Error.Println(err.Error()) + println("\n\nERROR: " + err.Error()) printFooter() os.Exit(1) } diff --git a/v2/cmd/wails/show.go b/v2/cmd/wails/show.go deleted file mode 100644 index c83900c8d..000000000 --- a/v2/cmd/wails/show.go +++ /dev/null @@ -1,27 +0,0 @@ -package main - -import ( - "github.com/pterm/pterm" - "github.com/wailsapp/wails/v2/cmd/wails/flags" - "github.com/wailsapp/wails/v2/cmd/wails/internal" - "github.com/wailsapp/wails/v2/internal/colour" - "github.com/wailsapp/wails/v2/internal/github" -) - -func showReleaseNotes(f *flags.ShowReleaseNotes) error { - if f.NoColour { - pterm.DisableColor() - colour.ColourEnabled = false - } - - version := internal.Version - if f.Version != "" { - version = f.Version - } - - app.PrintBanner() - releaseNotes := github.GetReleaseNotes(version, f.NoColour) - pterm.Println(releaseNotes) - - return nil -} diff --git a/v2/cmd/wails/update.go b/v2/cmd/wails/update.go deleted file mode 100644 index 9f8b6e604..000000000 --- a/v2/cmd/wails/update.go +++ /dev/null @@ -1,156 +0,0 @@ -package main - -import ( - "fmt" - "os" - - "github.com/labstack/gommon/color" - "github.com/pterm/pterm" - "github.com/wailsapp/wails/v2/cmd/wails/flags" - "github.com/wailsapp/wails/v2/internal/colour" - "github.com/wailsapp/wails/v2/internal/shell" - - "github.com/wailsapp/wails/v2/internal/github" -) - -// AddSubcommand adds the `init` command for the Wails application -func update(f *flags.Update) error { - if f.NoColour { - colour.ColourEnabled = false - pterm.DisableColor() - - } - // Print banner - app.PrintBanner() - pterm.Println("Checking for updates...") - - var desiredVersion *github.SemanticVersion - var err error - var valid bool - - if len(f.Version) > 0 { - // Check if this is a valid version - valid, err = github.IsValidTag(f.Version) - if err == nil { - if !valid { - err = fmt.Errorf("version '%s' is invalid", f.Version) - } else { - desiredVersion, err = github.NewSemanticVersion(f.Version) - } - } - } else { - if f.PreRelease { - desiredVersion, err = github.GetLatestPreRelease() - } else { - desiredVersion, err = github.GetLatestStableRelease() - if err != nil { - pterm.Println("") - pterm.Println("No stable release found for this major version. To update to the latest pre-release (eg beta), run:") - pterm.Println(" wails update -pre") - return nil - } - } - } - if err != nil { - return err - } - pterm.Println() - - pterm.Println(" Current Version : " + app.Version()) - - if len(f.Version) > 0 { - fmt.Printf(" Desired Version : v%s\n", desiredVersion) - } else { - if f.PreRelease { - fmt.Printf(" Latest Prerelease : v%s\n", desiredVersion) - } else { - fmt.Printf(" Latest Release : v%s\n", desiredVersion) - } - } - - return updateToVersion(desiredVersion, len(f.Version) > 0, app.Version()) -} - -func updateToVersion(targetVersion *github.SemanticVersion, force bool, currentVersion string) error { - targetVersionString := "v" + targetVersion.String() - - if targetVersionString == currentVersion { - pterm.Println("\nLooks like you're up to date!") - return nil - } - - var desiredVersion string - - if !force { - - compareVersion := currentVersion - - currentVersion, err := github.NewSemanticVersion(compareVersion) - if err != nil { - return err - } - - var success bool - - // Release -> Pre-Release = Massage current version to prerelease format - if targetVersion.IsPreRelease() && currentVersion.IsRelease() { - testVersion, err := github.NewSemanticVersion(compareVersion + "-0") - if err != nil { - return err - } - success, _ = targetVersion.IsGreaterThan(testVersion) - } - // Pre-Release -> Release = Massage target version to prerelease format - if targetVersion.IsRelease() && currentVersion.IsPreRelease() { - // We are ok with greater than or equal - mainversion := currentVersion.MainVersion() - targetVersion, err = github.NewSemanticVersion(targetVersion.String()) - if err != nil { - return err - } - success, _ = targetVersion.IsGreaterThanOrEqual(mainversion) - } - - // Release -> Release = Standard check - if (targetVersion.IsRelease() && currentVersion.IsRelease()) || - (targetVersion.IsPreRelease() && currentVersion.IsPreRelease()) { - - success, _ = targetVersion.IsGreaterThan(currentVersion) - } - - // Compare - if !success { - pterm.Println("Error: The requested version is lower than the current version.") - pterm.Println(fmt.Sprintf("If this is what you really want to do, use `wails update -version "+"%s`", targetVersionString)) - - return nil - } - - desiredVersion = "v" + targetVersion.String() - - } else { - desiredVersion = "v" + targetVersion.String() - } - - pterm.Println() - pterm.Print("Installing Wails CLI " + desiredVersion + "...") - - // Run command in non module directory - homeDir, err := os.UserHomeDir() - if err != nil { - fatal("Cannot find home directory! Please file a bug report!") - } - - sout, serr, err := shell.RunCommand(homeDir, "go", "install", "github.com/wailsapp/wails/v2/cmd/wails@"+desiredVersion) - if err != nil { - pterm.Println("Failed.") - pterm.Error.Println(sout + `\n` + serr) - return err - } - pterm.Println("Done.") - pterm.Println(color.Green("\nMake sure you update your project go.mod file to use " + desiredVersion + ":")) - pterm.Println(color.Green(" require github.com/wailsapp/wails/v2 " + desiredVersion)) - pterm.Println(color.Red("\nTo view the release notes, please run `wails show releasenotes`")) - - return nil -} diff --git a/v2/examples/customlayout/.gitignore b/v2/examples/customlayout/.gitignore deleted file mode 100644 index 53e9ed8b5..000000000 --- a/v2/examples/customlayout/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -build/bin -node_modules -myfrontend/wailsjs \ No newline at end of file diff --git a/v2/examples/customlayout/README.md b/v2/examples/customlayout/README.md deleted file mode 100644 index e4d79d4ec..000000000 --- a/v2/examples/customlayout/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# README - -This is an example project that shows how to use a custom layout. -Run `wails build` in the `cmd/customlayout` directory to build the project. \ No newline at end of file diff --git a/v2/examples/customlayout/build/README.md b/v2/examples/customlayout/build/README.md deleted file mode 100644 index 3018a06c4..000000000 --- a/v2/examples/customlayout/build/README.md +++ /dev/null @@ -1,35 +0,0 @@ -# Build Directory - -The build directory is used to house all the build files and assets for your application. - -The structure is: - -* bin - Output directory -* darwin - macOS specific files -* windows - Windows specific files - -## Mac - -The `darwin` directory holds files specific to Mac builds. -These may be customised and used as part of the build. To return these files to the default state, simply delete them -and -build with `wails build`. - -The directory contains the following files: - -- `Info.plist` - the main plist file used for Mac builds. It is used when building using `wails build`. -- `Info.dev.plist` - same as the main plist file but used when building using `wails dev`. - -## Windows - -The `windows` directory contains the manifest and rc files used when building with `wails build`. -These may be customised for your application. To return these files to the default state, simply delete them and -build with `wails build`. - -- `icon.ico` - The icon used for the application. This is used when building using `wails build`. If you wish to - use a different icon, simply replace this file with your own. If it is missing, a new `icon.ico` file - will be created using the `appicon.png` file in the build directory. -- `installer/*` - The files used to create the Windows installer. These are used when building using `wails build`. -- `info.json` - Application details used for Windows builds. The data here will be used by the Windows installer, - as well as the application itself (right click the exe -> properties -> details) -- `wails.exe.manifest` - The main application manifest file. \ No newline at end of file diff --git a/v2/examples/customlayout/build/appicon.png b/v2/examples/customlayout/build/appicon.png deleted file mode 100644 index 63617fe4f..000000000 Binary files a/v2/examples/customlayout/build/appicon.png and /dev/null differ diff --git a/v2/examples/customlayout/build/darwin/Info.dev.plist b/v2/examples/customlayout/build/darwin/Info.dev.plist deleted file mode 100644 index 02e7358ee..000000000 --- a/v2/examples/customlayout/build/darwin/Info.dev.plist +++ /dev/null @@ -1,32 +0,0 @@ - - - - CFBundlePackageType - APPL - CFBundleName - {{.Info.ProductName}} - CFBundleExecutable - {{.Name}} - CFBundleIdentifier - com.wails.{{.Name}} - CFBundleVersion - {{.Info.ProductVersion}} - CFBundleGetInfoString - {{.Info.Comments}} - CFBundleShortVersionString - {{.Info.ProductVersion}} - CFBundleIconFile - iconfile - LSMinimumSystemVersion - 10.13.0 - NSHighResolutionCapable - true - NSHumanReadableCopyright - {{.Info.Copyright}} - NSAppTransportSecurity - - NSAllowsLocalNetworking - - - - \ No newline at end of file diff --git a/v2/examples/customlayout/build/darwin/Info.plist b/v2/examples/customlayout/build/darwin/Info.plist deleted file mode 100644 index e7819a7e8..000000000 --- a/v2/examples/customlayout/build/darwin/Info.plist +++ /dev/null @@ -1,27 +0,0 @@ - - - - CFBundlePackageType - APPL - CFBundleName - {{.Info.ProductName}} - CFBundleExecutable - {{.Name}} - CFBundleIdentifier - com.wails.{{.Name}} - CFBundleVersion - {{.Info.ProductVersion}} - CFBundleGetInfoString - {{.Info.Comments}} - CFBundleShortVersionString - {{.Info.ProductVersion}} - CFBundleIconFile - iconfile - LSMinimumSystemVersion - 10.13.0 - NSHighResolutionCapable - true - NSHumanReadableCopyright - {{.Info.Copyright}} - - \ No newline at end of file diff --git a/v2/examples/customlayout/build/windows/icon.ico b/v2/examples/customlayout/build/windows/icon.ico deleted file mode 100644 index f33479841..000000000 Binary files a/v2/examples/customlayout/build/windows/icon.ico and /dev/null differ diff --git a/v2/examples/customlayout/build/windows/info.json b/v2/examples/customlayout/build/windows/info.json deleted file mode 100644 index c23c173c9..000000000 --- a/v2/examples/customlayout/build/windows/info.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "fixed": { - "file_version": "{{.Info.ProductVersion}}" - }, - "info": { - "0000": { - "ProductVersion": "{{.Info.ProductVersion}}", - "CompanyName": "{{.Info.CompanyName}}", - "FileDescription": "{{.Info.ProductName}}", - "LegalCopyright": "{{.Info.Copyright}}", - "ProductName": "{{.Info.ProductName}}", - "Comments": "{{.Info.Comments}}" - } - } -} \ No newline at end of file diff --git a/v2/examples/customlayout/build/windows/installer/project.nsi b/v2/examples/customlayout/build/windows/installer/project.nsi deleted file mode 100644 index 2ccc0f3f3..000000000 --- a/v2/examples/customlayout/build/windows/installer/project.nsi +++ /dev/null @@ -1,104 +0,0 @@ -Unicode true - -#### -## Please note: Template replacements don't work in this file. They are provided with default defines like -## mentioned underneath. -## If the keyword is not defined, "wails_tools.nsh" will populate them with the values from ProjectInfo. -## If they are defined here, "wails_tools.nsh" will not touch them. This allows to use this project.nsi manually -## from outside of Wails for debugging and development of the installer. -## -## For development first make a wails nsis build to populate the "wails_tools.nsh": -## > wails build --target windows/amd64 --nsis -## Then you can call makensis on this file with specifying the path to your binary: -## For a AMD64 only installer: -## > makensis -DARG_WAILS_AMD64_BINARY=..\..\bin\app.exe -## For a ARM64 only installer: -## > makensis -DARG_WAILS_ARM64_BINARY=..\..\bin\app.exe -## For a installer with both architectures: -## > makensis -DARG_WAILS_AMD64_BINARY=..\..\bin\app-amd64.exe -DARG_WAILS_ARM64_BINARY=..\..\bin\app-arm64.exe -#### -## The following information is taken from the ProjectInfo file, but they can be overwritten here. -#### -## !define INFO_PROJECTNAME "MyProject" # Default "{{.Name}}" -## !define INFO_COMPANYNAME "MyCompany" # Default "{{.Info.CompanyName}}" -## !define INFO_PRODUCTNAME "MyProduct" # Default "{{.Info.ProductName}}" -## !define INFO_PRODUCTVERSION "1.0.0" # Default "{{.Info.ProductVersion}}" -## !define INFO_COPYRIGHT "Copyright" # Default "{{.Info.Copyright}}" -### -## !define PRODUCT_EXECUTABLE "Application.exe" # Default "${INFO_PROJECTNAME}.exe" -## !define UNINST_KEY_NAME "UninstKeyInRegistry" # Default "${INFO_COMPANYNAME}${INFO_PRODUCTNAME}" -#### -## !define REQUEST_EXECUTION_LEVEL "admin" # Default "admin" see also https://nsis.sourceforge.io/Docs/Chapter4.html -#### -## Include the wails tools -#### -!include "wails_tools.nsh" - -# The version information for this two must consist of 4 parts -VIProductVersion "${INFO_PRODUCTVERSION}.0" -VIFileVersion "${INFO_PRODUCTVERSION}.0" - -VIAddVersionKey "CompanyName" "${INFO_COMPANYNAME}" -VIAddVersionKey "FileDescription" "${INFO_PRODUCTNAME} Installer" -VIAddVersionKey "ProductVersion" "${INFO_PRODUCTVERSION}" -VIAddVersionKey "FileVersion" "${INFO_PRODUCTVERSION}" -VIAddVersionKey "LegalCopyright" "${INFO_COPYRIGHT}" -VIAddVersionKey "ProductName" "${INFO_PRODUCTNAME}" - -# Enable HiDPI support. https://nsis.sourceforge.io/Reference/ManifestDPIAware -ManifestDPIAware true - -!include "MUI.nsh" - -!define MUI_ICON "..\icon.ico" -!define MUI_UNICON "..\icon.ico" -# !define MUI_WELCOMEFINISHPAGE_BITMAP "resources\leftimage.bmp" #Include this to add a bitmap on the left side of the Welcome Page. Must be a size of 164x314 -!define MUI_FINISHPAGE_NOAUTOCLOSE # Wait on the INSTFILES page so the user can take a look into the details of the installation steps -!define MUI_ABORTWARNING # This will warn the user if they exit from the installer. - -!insertmacro MUI_PAGE_WELCOME # Welcome to the installer page. -# !insertmacro MUI_PAGE_LICENSE "resources\eula.txt" # Adds a EULA page to the installer -!insertmacro MUI_PAGE_DIRECTORY # In which folder install page. -!insertmacro MUI_PAGE_INSTFILES # Installing page. -!insertmacro MUI_PAGE_FINISH # Finished installation page. - -!insertmacro MUI_UNPAGE_INSTFILES # Uinstalling page - -!insertmacro MUI_LANGUAGE "English" # Set the Language of the installer - -## The following two statements can be used to sign the installer and the uninstaller. The path to the binaries are provided in %1 -#!uninstfinalize 'signtool --file "%1"' -#!finalize 'signtool --file "%1"' - -Name "${INFO_PRODUCTNAME}" -OutFile "..\..\bin\${INFO_PROJECTNAME}-${ARCH}-installer.exe" # Name of the installer's file. -InstallDir "$PROGRAMFILES64\${INFO_COMPANYNAME}\${INFO_PRODUCTNAME}" # Default installing folder ($PROGRAMFILES is Program Files folder). -ShowInstDetails show # This will always show the installation details. - -Function .onInit - !insertmacro wails.checkArchitecture -FunctionEnd - -Section - !insertmacro wails.webview2runtime - - SetOutPath $INSTDIR - - !insertmacro wails.files - - CreateShortcut "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}" - CreateShortCut "$DESKTOP\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}" - - !insertmacro wails.writeUninstaller -SectionEnd - -Section "uninstall" - RMDir /r "$AppData\${PRODUCT_EXECUTABLE}" # Remove the WebView2 DataPath - - RMDir /r $INSTDIR - - Delete "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk" - Delete "$DESKTOP\${INFO_PRODUCTNAME}.lnk" - - !insertmacro wails.deleteUninstaller -SectionEnd diff --git a/v2/examples/customlayout/build/windows/installer/wails_tools.nsh b/v2/examples/customlayout/build/windows/installer/wails_tools.nsh deleted file mode 100644 index 66dc209a3..000000000 --- a/v2/examples/customlayout/build/windows/installer/wails_tools.nsh +++ /dev/null @@ -1,171 +0,0 @@ -# DO NOT EDIT - Generated automatically by `wails build` - -!include "x64.nsh" -!include "WinVer.nsh" -!include "FileFunc.nsh" - -!ifndef INFO_PROJECTNAME - !define INFO_PROJECTNAME "{{.Name}}" -!endif -!ifndef INFO_COMPANYNAME - !define INFO_COMPANYNAME "{{.Info.CompanyName}}" -!endif -!ifndef INFO_PRODUCTNAME - !define INFO_PRODUCTNAME "{{.Info.ProductName}}" -!endif -!ifndef INFO_PRODUCTVERSION - !define INFO_PRODUCTVERSION "{{.Info.ProductVersion}}" -!endif -!ifndef INFO_COPYRIGHT - !define INFO_COPYRIGHT "{{.Info.Copyright}}" -!endif -!ifndef PRODUCT_EXECUTABLE - !define PRODUCT_EXECUTABLE "${INFO_PROJECTNAME}.exe" -!endif -!ifndef UNINST_KEY_NAME - !define UNINST_KEY_NAME "${INFO_COMPANYNAME}${INFO_PRODUCTNAME}" -!endif -!define UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINST_KEY_NAME}" - -!ifndef REQUEST_EXECUTION_LEVEL - !define REQUEST_EXECUTION_LEVEL "admin" -!endif - -RequestExecutionLevel "${REQUEST_EXECUTION_LEVEL}" - -!ifdef ARG_WAILS_AMD64_BINARY - !define SUPPORTS_AMD64 -!endif - -!ifdef ARG_WAILS_ARM64_BINARY - !define SUPPORTS_ARM64 -!endif - -!ifdef SUPPORTS_AMD64 - !ifdef SUPPORTS_ARM64 - !define ARCH "amd64_arm64" - !else - !define ARCH "amd64" - !endif -!else - !ifdef SUPPORTS_ARM64 - !define ARCH "arm64" - !else - !error "Wails: Undefined ARCH, please provide at least one of ARG_WAILS_AMD64_BINARY or ARG_WAILS_ARM64_BINARY" - !endif -!endif - -!macro wails.checkArchitecture - !ifndef WAILS_WIN10_REQUIRED - !define WAILS_WIN10_REQUIRED "This product is only supported on Windows 10 (Server 2016) and later." - !endif - - !ifndef WAILS_ARCHITECTURE_NOT_SUPPORTED - !define WAILS_ARCHITECTURE_NOT_SUPPORTED "This product can't be installed on the current Windows architecture. Supports: ${ARCH}" - !endif - - ${If} ${AtLeastWin10} - !ifdef SUPPORTS_AMD64 - ${if} ${IsNativeAMD64} - Goto ok - ${EndIf} - !endif - - !ifdef SUPPORTS_ARM64 - ${if} ${IsNativeARM64} - Goto ok - ${EndIf} - !endif - - IfSilent silentArch notSilentArch - silentArch: - SetErrorLevel 65 - Abort - notSilentArch: - MessageBox MB_OK "${WAILS_ARCHITECTURE_NOT_SUPPORTED}" - Quit - ${else} - IfSilent silentWin notSilentWin - silentWin: - SetErrorLevel 64 - Abort - notSilentWin: - MessageBox MB_OK "${WAILS_WIN10_REQUIRED}" - Quit - ${EndIf} - - ok: -!macroend - -!macro wails.files - !ifdef SUPPORTS_AMD64 - ${if} ${IsNativeAMD64} - File "/oname=${PRODUCT_EXECUTABLE}" "${ARG_WAILS_AMD64_BINARY}" - ${EndIf} - !endif - - !ifdef SUPPORTS_ARM64 - ${if} ${IsNativeARM64} - File "/oname=${PRODUCT_EXECUTABLE}" "${ARG_WAILS_ARM64_BINARY}" - ${EndIf} - !endif -!macroend - -!macro wails.writeUninstaller - WriteUninstaller "$INSTDIR\uninstall.exe" - - SetRegView 64 - WriteRegStr HKLM "${UNINST_KEY}" "Publisher" "${INFO_COMPANYNAME}" - WriteRegStr HKLM "${UNINST_KEY}" "DisplayName" "${INFO_PRODUCTNAME}" - WriteRegStr HKLM "${UNINST_KEY}" "DisplayVersion" "${INFO_PRODUCTVERSION}" - WriteRegStr HKLM "${UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PRODUCT_EXECUTABLE}" - WriteRegStr HKLM "${UNINST_KEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\"" - WriteRegStr HKLM "${UNINST_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S" - - ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2 - IntFmt $0 "0x%08X" $0 - WriteRegDWORD HKLM "${UNINST_KEY}" "EstimatedSize" "$0" -!macroend - -!macro wails.deleteUninstaller - Delete "$INSTDIR\uninstall.exe" - - SetRegView 64 - DeleteRegKey HKLM "${UNINST_KEY}" -!macroend - -# Install webview2 by launching the bootstrapper -# See https://docs.microsoft.com/en-us/microsoft-edge/webview2/concepts/distribution#online-only-deployment -!macro wails.webview2runtime - !ifndef WAILS_INSTALL_WEBVIEW_DETAILPRINT - !define WAILS_INSTALL_WEBVIEW_DETAILPRINT "Installing: WebView2 Runtime" - !endif - - SetRegView 64 - # If the admin key exists and is not empty then webview2 is already installed - ReadRegStr $0 HKLM "SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv" - ${If} $0 != "" - Goto ok - ${EndIf} - - ${If} ${REQUEST_EXECUTION_LEVEL} == "user" - # If the installer is run in user level, check the user specific key exists and is not empty then webview2 is already installed - ReadRegStr $0 HKCU "Software\Microsoft\EdgeUpdate\Clients{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv" - ${If} $0 != "" - Goto ok - ${EndIf} - ${EndIf} - - SetDetailsPrint both - DetailPrint "${WAILS_INSTALL_WEBVIEW_DETAILPRINT}" - SetDetailsPrint listonly - - InitPluginsDir - CreateDirectory "$pluginsdir\webview2bootstrapper" - SetOutPath "$pluginsdir\webview2bootstrapper" - File "tmp\MicrosoftEdgeWebview2Setup.exe" - ExecWait '"$pluginsdir\webview2bootstrapper\MicrosoftEdgeWebview2Setup.exe" /silent /install' - - SetDetailsPrint both - ok: -!macroend \ No newline at end of file diff --git a/v2/examples/customlayout/build/windows/wails.exe.manifest b/v2/examples/customlayout/build/windows/wails.exe.manifest deleted file mode 100644 index 17e1a2387..000000000 --- a/v2/examples/customlayout/build/windows/wails.exe.manifest +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - true/pm - permonitorv2,permonitor - - - \ No newline at end of file diff --git a/v2/examples/customlayout/cmd/customlayout/app.go b/v2/examples/customlayout/cmd/customlayout/app.go deleted file mode 100644 index af53038a1..000000000 --- a/v2/examples/customlayout/cmd/customlayout/app.go +++ /dev/null @@ -1,27 +0,0 @@ -package main - -import ( - "context" - "fmt" -) - -// App struct -type App struct { - ctx context.Context -} - -// NewApp creates a new App application struct -func NewApp() *App { - return &App{} -} - -// startup is called when the app starts. The context is saved -// so we can call the runtime methods -func (a *App) startup(ctx context.Context) { - a.ctx = ctx -} - -// Greet returns a greeting for the given name -func (a *App) Greet(name string) string { - return fmt.Sprintf("Hello %s, It's show time!", name) -} diff --git a/v2/examples/customlayout/cmd/customlayout/main.go b/v2/examples/customlayout/cmd/customlayout/main.go deleted file mode 100644 index dcb59a80c..000000000 --- a/v2/examples/customlayout/cmd/customlayout/main.go +++ /dev/null @@ -1,29 +0,0 @@ -package main - -import ( - "changeme/myfrontend" - "github.com/wailsapp/wails/v2" - "github.com/wailsapp/wails/v2/pkg/options" -) - -func main() { - // Create an instance of the app structure - app := NewApp() - - // Create application with options - err := wails.Run(&options.App{ - Title: "customlayout", - Width: 1024, - Height: 768, - Assets: myfrontend.Assets, - BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, - OnStartup: app.startup, - Bind: []interface{}{ - app, - }, - }) - - if err != nil { - println("Error:", err.Error()) - } -} diff --git a/v2/examples/customlayout/cmd/customlayout/wails.json b/v2/examples/customlayout/cmd/customlayout/wails.json deleted file mode 100644 index e37c2ec7d..000000000 --- a/v2/examples/customlayout/cmd/customlayout/wails.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "$schema": "https://wails.io/schemas/config.v2.json", - "name": "customlayout", - "outputfilename": "customlayout", - "build:dir": "../../build", - "frontend:dir": "../../myfrontend", - "frontend:install": "npm install", - "frontend:build": "npm run build", - "frontend:dev:watcher": "npm run dev", - "frontend:dev:serverUrl": "auto", - "author": { - "name": "Lea Anthony", - "email": "lea.anthony@gmail.com" - } -} diff --git a/v2/examples/customlayout/go.mod b/v2/examples/customlayout/go.mod deleted file mode 100644 index e1a17304e..000000000 --- a/v2/examples/customlayout/go.mod +++ /dev/null @@ -1,39 +0,0 @@ -module changeme - -go 1.22.0 - -toolchain go1.24.1 - -require github.com/wailsapp/wails/v2 v2.1.0 - -require ( - github.com/bep/debounce v1.2.1 // indirect - github.com/go-ole/go-ole v1.3.0 // indirect - github.com/godbus/dbus/v5 v5.1.0 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect - github.com/labstack/echo/v4 v4.13.3 // indirect - github.com/labstack/gommon v0.4.2 // indirect - github.com/leaanthony/go-ansi-parser v1.6.1 // indirect - github.com/leaanthony/gosod v1.0.4 // indirect - github.com/leaanthony/slicer v1.6.0 // indirect - github.com/leaanthony/u v1.1.1 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect - github.com/pkg/errors v0.9.1 // indirect - github.com/rivo/uniseg v0.4.7 // indirect - github.com/samber/lo v1.49.1 // indirect - github.com/tkrajina/go-reflector v0.5.8 // indirect - github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasttemplate v1.2.2 // indirect - github.com/wailsapp/go-webview2 v1.0.22 // indirect - github.com/wailsapp/mimetype v1.4.1 // indirect - golang.org/x/crypto v0.33.0 // indirect - golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect - golang.org/x/net v0.35.0 // indirect - golang.org/x/sys v0.30.0 // indirect - golang.org/x/text v0.22.0 // indirect -) - -replace github.com/wailsapp/wails/v2 v2.1.0 => ../.. diff --git a/v2/examples/customlayout/go.sum b/v2/examples/customlayout/go.sum deleted file mode 100644 index f1995affb..000000000 --- a/v2/examples/customlayout/go.sum +++ /dev/null @@ -1,111 +0,0 @@ -github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY= -github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= -github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= -github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= -github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck= -github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs= -github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M= -github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k= -github.com/labstack/echo/v4 v4.13.3/go.mod h1:o90YNEeQWjDozo584l7AwhJMHN0bOC4tAfg+Xox9q5g= -github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= -github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= -github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= -github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc= -github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA= -github.com/leaanthony/go-ansi-parser v1.6.0 h1:T8TuMhFB6TUMIUm0oRrSbgJudTFw9csT3ZK09w0t4Pg= -github.com/leaanthony/go-ansi-parser v1.6.0/go.mod h1:+vva/2y4alzVmmIEpk9QDhA7vLC5zKDTRwfZGOp3IWU= -github.com/leaanthony/go-ansi-parser v1.6.1/go.mod h1:+vva/2y4alzVmmIEpk9QDhA7vLC5zKDTRwfZGOp3IWU= -github.com/leaanthony/gosod v1.0.3 h1:Fnt+/B6NjQOVuCWOKYRREZnjGyvg+mEhd1nkkA04aTQ= -github.com/leaanthony/gosod v1.0.3/go.mod h1:BJ2J+oHsQIyIQpnLPjnqFGTMnOZXDbvWtRCSG7jGxs4= -github.com/leaanthony/gosod v1.0.4/go.mod h1:GKuIL0zzPj3O1SdWQOdgURSuhkF+Urizzxh26t9f1cw= -github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY= -github.com/leaanthony/slicer v1.6.0 h1:1RFP5uiPJvT93TAHi+ipd3NACobkW53yUiBqZheE/Js= -github.com/leaanthony/slicer v1.6.0/go.mod h1:o/Iz29g7LN0GqH3aMjWAe90381nyZlDNquK+mtH2Fj8= -github.com/leaanthony/u v1.1.0 h1:2n0d2BwPVXSUq5yhe8lJPHdxevE2qK5G99PMStMZMaI= -github.com/leaanthony/u v1.1.0/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQcaRfI= -github.com/leaanthony/u v1.1.1/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQcaRfI= -github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= -github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= -github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= -github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= -github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= -github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= -github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= -github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/tkrajina/go-reflector v0.5.6 h1:hKQ0gyocG7vgMD2M3dRlYN6WBBOmdoOzJ6njQSepKdE= -github.com/tkrajina/go-reflector v0.5.6/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4= -github.com/tkrajina/go-reflector v0.5.8/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4= -github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= -github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -github.com/wailsapp/go-webview2 v1.0.10 h1:PP5Hug6pnQEAhfRzLCoOh2jJaPdrqeRgJKZhyYyDV/w= -github.com/wailsapp/go-webview2 v1.0.10/go.mod h1:Uk2BePfCRzttBBjFrBmqKGJd41P6QIHeV9kTgIeOZNo= -github.com/wailsapp/go-webview2 v1.0.19/go.mod h1:qJmWAmAmaniuKGZPWwne+uor3AHMB5PFhqiK0Bbj8kc= -github.com/wailsapp/go-webview2 v1.0.22/go.mod h1:qJmWAmAmaniuKGZPWwne+uor3AHMB5PFhqiK0Bbj8kc= -github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs= -github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= -golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= -golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= -golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/v2/examples/customlayout/myfrontend/assets.go b/v2/examples/customlayout/myfrontend/assets.go deleted file mode 100644 index a6dec2f8f..000000000 --- a/v2/examples/customlayout/myfrontend/assets.go +++ /dev/null @@ -1,6 +0,0 @@ -package myfrontend - -import "embed" - -//go:embed all:dist -var Assets embed.FS diff --git a/v2/examples/customlayout/myfrontend/index.html b/v2/examples/customlayout/myfrontend/index.html deleted file mode 100644 index 1ceda7392..000000000 --- a/v2/examples/customlayout/myfrontend/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - customlayout - - -
- - - diff --git a/v2/examples/customlayout/myfrontend/package.json b/v2/examples/customlayout/myfrontend/package.json deleted file mode 100644 index a1b6f8e1a..000000000 --- a/v2/examples/customlayout/myfrontend/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "frontend", - "private": true, - "version": "0.0.0", - "scripts": { - "dev": "vite", - "build": "vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^3.0.7" - } -} \ No newline at end of file diff --git a/v2/examples/customlayout/myfrontend/src/app.css b/v2/examples/customlayout/myfrontend/src/app.css deleted file mode 100644 index 59d06f692..000000000 --- a/v2/examples/customlayout/myfrontend/src/app.css +++ /dev/null @@ -1,54 +0,0 @@ -#logo { - display: block; - width: 50%; - height: 50%; - margin: auto; - padding: 10% 0 0; - background-position: center; - background-repeat: no-repeat; - background-size: 100% 100%; - background-origin: content-box; -} - -.result { - height: 20px; - line-height: 20px; - margin: 1.5rem auto; -} - -.input-box .btn { - width: 60px; - height: 30px; - line-height: 30px; - border-radius: 3px; - border: none; - margin: 0 0 0 20px; - padding: 0 8px; - cursor: pointer; -} - -.input-box .btn:hover { - background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%); - color: #333333; -} - -.input-box .input { - border: none; - border-radius: 3px; - outline: none; - height: 30px; - line-height: 30px; - padding: 0 10px; - background-color: rgba(240, 240, 240, 1); - -webkit-font-smoothing: antialiased; -} - -.input-box .input:hover { - border: none; - background-color: rgba(255, 255, 255, 1); -} - -.input-box .input:focus { - border: none; - background-color: rgba(255, 255, 255, 1); -} \ No newline at end of file diff --git a/v2/examples/customlayout/myfrontend/src/assets/images/logo-universal.png b/v2/examples/customlayout/myfrontend/src/assets/images/logo-universal.png deleted file mode 100644 index d63303bfa..000000000 Binary files a/v2/examples/customlayout/myfrontend/src/assets/images/logo-universal.png and /dev/null differ diff --git a/v2/examples/customlayout/myfrontend/src/main.js b/v2/examples/customlayout/myfrontend/src/main.js deleted file mode 100644 index 6cb4ad78d..000000000 --- a/v2/examples/customlayout/myfrontend/src/main.js +++ /dev/null @@ -1,48 +0,0 @@ -import './style.css'; -import './app.css'; - -import logo from './assets/images/logo-universal.png'; -import { Greet } from '../wailsjs/go/main/App'; - -document.querySelector('#app').innerHTML = ` - -
Please enter your name below 👇
-
- - -
- -`; -document.getElementById('logo').src = logo; -document.addEventListener("keydown", (e) => { - if (e.code === "Enter") { - window.greet(); - } -}); - -let nameElement = document.getElementById("name"); -nameElement.focus(); -let resultElement = document.getElementById("result"); - -// Setup the greet function -window.greet = function () { - // Get name - let name = nameElement.value; - - // Check if the input is empty - if (name === "") return; - - // Call App.Greet(name) - try { - Greet(name) - .then((result) => { - // Update result with data back from App.Greet() - resultElement.innerText = result; - }) - .catch((err) => { - console.error(err); - }); - } catch (err) { - console.error(err); - } -}; diff --git a/v2/examples/customlayout/myfrontend/src/style.css b/v2/examples/customlayout/myfrontend/src/style.css deleted file mode 100644 index 3940d6c63..000000000 --- a/v2/examples/customlayout/myfrontend/src/style.css +++ /dev/null @@ -1,26 +0,0 @@ -html { - background-color: rgba(27, 38, 54, 1); - text-align: center; - color: white; -} - -body { - margin: 0; - color: white; - font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", - "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", - sans-serif; -} - -@font-face { - font-family: "Nunito"; - font-style: normal; - font-weight: 400; - src: local(""), - url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2"); -} - -#app { - height: 100vh; - text-align: center; -} diff --git a/v2/examples/dragdrop-test/.gitignore b/v2/examples/dragdrop-test/.gitignore deleted file mode 100644 index a11bbf414..000000000 --- a/v2/examples/dragdrop-test/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -build/bin -node_modules -frontend/dist -frontend/wailsjs diff --git a/v2/examples/dragdrop-test/README.md b/v2/examples/dragdrop-test/README.md deleted file mode 100644 index 397b08b92..000000000 --- a/v2/examples/dragdrop-test/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# README - -## About - -This is the official Wails Vanilla template. - -You can configure the project by editing `wails.json`. More information about the project settings can be found -here: https://wails.io/docs/reference/project-config - -## Live Development - -To run in live development mode, run `wails dev` in the project directory. This will run a Vite development -server that will provide very fast hot reload of your frontend changes. If you want to develop in a browser -and have access to your Go methods, there is also a dev server that runs on http://localhost:34115. Connect -to this in your browser, and you can call your Go code from devtools. - -## Building - -To build a redistributable, production mode package, use `wails build`. diff --git a/v2/examples/dragdrop-test/app.go b/v2/examples/dragdrop-test/app.go deleted file mode 100644 index af53038a1..000000000 --- a/v2/examples/dragdrop-test/app.go +++ /dev/null @@ -1,27 +0,0 @@ -package main - -import ( - "context" - "fmt" -) - -// App struct -type App struct { - ctx context.Context -} - -// NewApp creates a new App application struct -func NewApp() *App { - return &App{} -} - -// startup is called when the app starts. The context is saved -// so we can call the runtime methods -func (a *App) startup(ctx context.Context) { - a.ctx = ctx -} - -// Greet returns a greeting for the given name -func (a *App) Greet(name string) string { - return fmt.Sprintf("Hello %s, It's show time!", name) -} diff --git a/v2/examples/dragdrop-test/build/README.md b/v2/examples/dragdrop-test/build/README.md deleted file mode 100644 index 1ae2f677f..000000000 --- a/v2/examples/dragdrop-test/build/README.md +++ /dev/null @@ -1,35 +0,0 @@ -# Build Directory - -The build directory is used to house all the build files and assets for your application. - -The structure is: - -* bin - Output directory -* darwin - macOS specific files -* windows - Windows specific files - -## Mac - -The `darwin` directory holds files specific to Mac builds. -These may be customised and used as part of the build. To return these files to the default state, simply delete them -and -build with `wails build`. - -The directory contains the following files: - -- `Info.plist` - the main plist file used for Mac builds. It is used when building using `wails build`. -- `Info.dev.plist` - same as the main plist file but used when building using `wails dev`. - -## Windows - -The `windows` directory contains the manifest and rc files used when building with `wails build`. -These may be customised for your application. To return these files to the default state, simply delete them and -build with `wails build`. - -- `icon.ico` - The icon used for the application. This is used when building using `wails build`. If you wish to - use a different icon, simply replace this file with your own. If it is missing, a new `icon.ico` file - will be created using the `appicon.png` file in the build directory. -- `installer/*` - The files used to create the Windows installer. These are used when building using `wails build`. -- `info.json` - Application details used for Windows builds. The data here will be used by the Windows installer, - as well as the application itself (right click the exe -> properties -> details) -- `wails.exe.manifest` - The main application manifest file. \ No newline at end of file diff --git a/v2/examples/dragdrop-test/build/appicon.png b/v2/examples/dragdrop-test/build/appicon.png deleted file mode 100644 index 63617fe4f..000000000 Binary files a/v2/examples/dragdrop-test/build/appicon.png and /dev/null differ diff --git a/v2/examples/dragdrop-test/build/darwin/Info.dev.plist b/v2/examples/dragdrop-test/build/darwin/Info.dev.plist deleted file mode 100644 index 14121ef7c..000000000 --- a/v2/examples/dragdrop-test/build/darwin/Info.dev.plist +++ /dev/null @@ -1,68 +0,0 @@ - - - - CFBundlePackageType - APPL - CFBundleName - {{.Info.ProductName}} - CFBundleExecutable - {{.OutputFilename}} - CFBundleIdentifier - com.wails.{{.Name}} - CFBundleVersion - {{.Info.ProductVersion}} - CFBundleGetInfoString - {{.Info.Comments}} - CFBundleShortVersionString - {{.Info.ProductVersion}} - CFBundleIconFile - iconfile - LSMinimumSystemVersion - 10.13.0 - NSHighResolutionCapable - true - NSHumanReadableCopyright - {{.Info.Copyright}} - {{if .Info.FileAssociations}} - CFBundleDocumentTypes - - {{range .Info.FileAssociations}} - - CFBundleTypeExtensions - - {{.Ext}} - - CFBundleTypeName - {{.Name}} - CFBundleTypeRole - {{.Role}} - CFBundleTypeIconFile - {{.IconName}} - - {{end}} - - {{end}} - {{if .Info.Protocols}} - CFBundleURLTypes - - {{range .Info.Protocols}} - - CFBundleURLName - com.wails.{{.Scheme}} - CFBundleURLSchemes - - {{.Scheme}} - - CFBundleTypeRole - {{.Role}} - - {{end}} - - {{end}} - NSAppTransportSecurity - - NSAllowsLocalNetworking - - - - diff --git a/v2/examples/dragdrop-test/build/darwin/Info.plist b/v2/examples/dragdrop-test/build/darwin/Info.plist deleted file mode 100644 index d17a7475c..000000000 --- a/v2/examples/dragdrop-test/build/darwin/Info.plist +++ /dev/null @@ -1,63 +0,0 @@ - - - - CFBundlePackageType - APPL - CFBundleName - {{.Info.ProductName}} - CFBundleExecutable - {{.OutputFilename}} - CFBundleIdentifier - com.wails.{{.Name}} - CFBundleVersion - {{.Info.ProductVersion}} - CFBundleGetInfoString - {{.Info.Comments}} - CFBundleShortVersionString - {{.Info.ProductVersion}} - CFBundleIconFile - iconfile - LSMinimumSystemVersion - 10.13.0 - NSHighResolutionCapable - true - NSHumanReadableCopyright - {{.Info.Copyright}} - {{if .Info.FileAssociations}} - CFBundleDocumentTypes - - {{range .Info.FileAssociations}} - - CFBundleTypeExtensions - - {{.Ext}} - - CFBundleTypeName - {{.Name}} - CFBundleTypeRole - {{.Role}} - CFBundleTypeIconFile - {{.IconName}} - - {{end}} - - {{end}} - {{if .Info.Protocols}} - CFBundleURLTypes - - {{range .Info.Protocols}} - - CFBundleURLName - com.wails.{{.Scheme}} - CFBundleURLSchemes - - {{.Scheme}} - - CFBundleTypeRole - {{.Role}} - - {{end}} - - {{end}} - - diff --git a/v2/examples/dragdrop-test/build/windows/icon.ico b/v2/examples/dragdrop-test/build/windows/icon.ico deleted file mode 100644 index f33479841..000000000 Binary files a/v2/examples/dragdrop-test/build/windows/icon.ico and /dev/null differ diff --git a/v2/examples/dragdrop-test/build/windows/info.json b/v2/examples/dragdrop-test/build/windows/info.json deleted file mode 100644 index 9727946b7..000000000 --- a/v2/examples/dragdrop-test/build/windows/info.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "fixed": { - "file_version": "{{.Info.ProductVersion}}" - }, - "info": { - "0000": { - "ProductVersion": "{{.Info.ProductVersion}}", - "CompanyName": "{{.Info.CompanyName}}", - "FileDescription": "{{.Info.ProductName}}", - "LegalCopyright": "{{.Info.Copyright}}", - "ProductName": "{{.Info.ProductName}}", - "Comments": "{{.Info.Comments}}" - } - } -} \ No newline at end of file diff --git a/v2/examples/dragdrop-test/build/windows/installer/project.nsi b/v2/examples/dragdrop-test/build/windows/installer/project.nsi deleted file mode 100644 index 654ae2e49..000000000 --- a/v2/examples/dragdrop-test/build/windows/installer/project.nsi +++ /dev/null @@ -1,114 +0,0 @@ -Unicode true - -#### -## Please note: Template replacements don't work in this file. They are provided with default defines like -## mentioned underneath. -## If the keyword is not defined, "wails_tools.nsh" will populate them with the values from ProjectInfo. -## If they are defined here, "wails_tools.nsh" will not touch them. This allows to use this project.nsi manually -## from outside of Wails for debugging and development of the installer. -## -## For development first make a wails nsis build to populate the "wails_tools.nsh": -## > wails build --target windows/amd64 --nsis -## Then you can call makensis on this file with specifying the path to your binary: -## For a AMD64 only installer: -## > makensis -DARG_WAILS_AMD64_BINARY=..\..\bin\app.exe -## For a ARM64 only installer: -## > makensis -DARG_WAILS_ARM64_BINARY=..\..\bin\app.exe -## For a installer with both architectures: -## > makensis -DARG_WAILS_AMD64_BINARY=..\..\bin\app-amd64.exe -DARG_WAILS_ARM64_BINARY=..\..\bin\app-arm64.exe -#### -## The following information is taken from the ProjectInfo file, but they can be overwritten here. -#### -## !define INFO_PROJECTNAME "MyProject" # Default "{{.Name}}" -## !define INFO_COMPANYNAME "MyCompany" # Default "{{.Info.CompanyName}}" -## !define INFO_PRODUCTNAME "MyProduct" # Default "{{.Info.ProductName}}" -## !define INFO_PRODUCTVERSION "1.0.0" # Default "{{.Info.ProductVersion}}" -## !define INFO_COPYRIGHT "Copyright" # Default "{{.Info.Copyright}}" -### -## !define PRODUCT_EXECUTABLE "Application.exe" # Default "${INFO_PROJECTNAME}.exe" -## !define UNINST_KEY_NAME "UninstKeyInRegistry" # Default "${INFO_COMPANYNAME}${INFO_PRODUCTNAME}" -#### -## !define REQUEST_EXECUTION_LEVEL "admin" # Default "admin" see also https://nsis.sourceforge.io/Docs/Chapter4.html -#### -## Include the wails tools -#### -!include "wails_tools.nsh" - -# The version information for this two must consist of 4 parts -VIProductVersion "${INFO_PRODUCTVERSION}.0" -VIFileVersion "${INFO_PRODUCTVERSION}.0" - -VIAddVersionKey "CompanyName" "${INFO_COMPANYNAME}" -VIAddVersionKey "FileDescription" "${INFO_PRODUCTNAME} Installer" -VIAddVersionKey "ProductVersion" "${INFO_PRODUCTVERSION}" -VIAddVersionKey "FileVersion" "${INFO_PRODUCTVERSION}" -VIAddVersionKey "LegalCopyright" "${INFO_COPYRIGHT}" -VIAddVersionKey "ProductName" "${INFO_PRODUCTNAME}" - -# Enable HiDPI support. https://nsis.sourceforge.io/Reference/ManifestDPIAware -ManifestDPIAware true - -!include "MUI.nsh" - -!define MUI_ICON "..\icon.ico" -!define MUI_UNICON "..\icon.ico" -# !define MUI_WELCOMEFINISHPAGE_BITMAP "resources\leftimage.bmp" #Include this to add a bitmap on the left side of the Welcome Page. Must be a size of 164x314 -!define MUI_FINISHPAGE_NOAUTOCLOSE # Wait on the INSTFILES page so the user can take a look into the details of the installation steps -!define MUI_ABORTWARNING # This will warn the user if they exit from the installer. - -!insertmacro MUI_PAGE_WELCOME # Welcome to the installer page. -# !insertmacro MUI_PAGE_LICENSE "resources\eula.txt" # Adds a EULA page to the installer -!insertmacro MUI_PAGE_DIRECTORY # In which folder install page. -!insertmacro MUI_PAGE_INSTFILES # Installing page. -!insertmacro MUI_PAGE_FINISH # Finished installation page. - -!insertmacro MUI_UNPAGE_INSTFILES # Uinstalling page - -!insertmacro MUI_LANGUAGE "English" # Set the Language of the installer - -## The following two statements can be used to sign the installer and the uninstaller. The path to the binaries are provided in %1 -#!uninstfinalize 'signtool --file "%1"' -#!finalize 'signtool --file "%1"' - -Name "${INFO_PRODUCTNAME}" -OutFile "..\..\bin\${INFO_PROJECTNAME}-${ARCH}-installer.exe" # Name of the installer's file. -InstallDir "$PROGRAMFILES64\${INFO_COMPANYNAME}\${INFO_PRODUCTNAME}" # Default installing folder ($PROGRAMFILES is Program Files folder). -ShowInstDetails show # This will always show the installation details. - -Function .onInit - !insertmacro wails.checkArchitecture -FunctionEnd - -Section - !insertmacro wails.setShellContext - - !insertmacro wails.webview2runtime - - SetOutPath $INSTDIR - - !insertmacro wails.files - - CreateShortcut "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}" - CreateShortCut "$DESKTOP\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}" - - !insertmacro wails.associateFiles - !insertmacro wails.associateCustomProtocols - - !insertmacro wails.writeUninstaller -SectionEnd - -Section "uninstall" - !insertmacro wails.setShellContext - - RMDir /r "$AppData\${PRODUCT_EXECUTABLE}" # Remove the WebView2 DataPath - - RMDir /r $INSTDIR - - Delete "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk" - Delete "$DESKTOP\${INFO_PRODUCTNAME}.lnk" - - !insertmacro wails.unassociateFiles - !insertmacro wails.unassociateCustomProtocols - - !insertmacro wails.deleteUninstaller -SectionEnd diff --git a/v2/examples/dragdrop-test/build/windows/installer/wails_tools.nsh b/v2/examples/dragdrop-test/build/windows/installer/wails_tools.nsh deleted file mode 100644 index f9c0f8852..000000000 --- a/v2/examples/dragdrop-test/build/windows/installer/wails_tools.nsh +++ /dev/null @@ -1,249 +0,0 @@ -# DO NOT EDIT - Generated automatically by `wails build` - -!include "x64.nsh" -!include "WinVer.nsh" -!include "FileFunc.nsh" - -!ifndef INFO_PROJECTNAME - !define INFO_PROJECTNAME "{{.Name}}" -!endif -!ifndef INFO_COMPANYNAME - !define INFO_COMPANYNAME "{{.Info.CompanyName}}" -!endif -!ifndef INFO_PRODUCTNAME - !define INFO_PRODUCTNAME "{{.Info.ProductName}}" -!endif -!ifndef INFO_PRODUCTVERSION - !define INFO_PRODUCTVERSION "{{.Info.ProductVersion}}" -!endif -!ifndef INFO_COPYRIGHT - !define INFO_COPYRIGHT "{{.Info.Copyright}}" -!endif -!ifndef PRODUCT_EXECUTABLE - !define PRODUCT_EXECUTABLE "${INFO_PROJECTNAME}.exe" -!endif -!ifndef UNINST_KEY_NAME - !define UNINST_KEY_NAME "${INFO_COMPANYNAME}${INFO_PRODUCTNAME}" -!endif -!define UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINST_KEY_NAME}" - -!ifndef REQUEST_EXECUTION_LEVEL - !define REQUEST_EXECUTION_LEVEL "admin" -!endif - -RequestExecutionLevel "${REQUEST_EXECUTION_LEVEL}" - -!ifdef ARG_WAILS_AMD64_BINARY - !define SUPPORTS_AMD64 -!endif - -!ifdef ARG_WAILS_ARM64_BINARY - !define SUPPORTS_ARM64 -!endif - -!ifdef SUPPORTS_AMD64 - !ifdef SUPPORTS_ARM64 - !define ARCH "amd64_arm64" - !else - !define ARCH "amd64" - !endif -!else - !ifdef SUPPORTS_ARM64 - !define ARCH "arm64" - !else - !error "Wails: Undefined ARCH, please provide at least one of ARG_WAILS_AMD64_BINARY or ARG_WAILS_ARM64_BINARY" - !endif -!endif - -!macro wails.checkArchitecture - !ifndef WAILS_WIN10_REQUIRED - !define WAILS_WIN10_REQUIRED "This product is only supported on Windows 10 (Server 2016) and later." - !endif - - !ifndef WAILS_ARCHITECTURE_NOT_SUPPORTED - !define WAILS_ARCHITECTURE_NOT_SUPPORTED "This product can't be installed on the current Windows architecture. Supports: ${ARCH}" - !endif - - ${If} ${AtLeastWin10} - !ifdef SUPPORTS_AMD64 - ${if} ${IsNativeAMD64} - Goto ok - ${EndIf} - !endif - - !ifdef SUPPORTS_ARM64 - ${if} ${IsNativeARM64} - Goto ok - ${EndIf} - !endif - - IfSilent silentArch notSilentArch - silentArch: - SetErrorLevel 65 - Abort - notSilentArch: - MessageBox MB_OK "${WAILS_ARCHITECTURE_NOT_SUPPORTED}" - Quit - ${else} - IfSilent silentWin notSilentWin - silentWin: - SetErrorLevel 64 - Abort - notSilentWin: - MessageBox MB_OK "${WAILS_WIN10_REQUIRED}" - Quit - ${EndIf} - - ok: -!macroend - -!macro wails.files - !ifdef SUPPORTS_AMD64 - ${if} ${IsNativeAMD64} - File "/oname=${PRODUCT_EXECUTABLE}" "${ARG_WAILS_AMD64_BINARY}" - ${EndIf} - !endif - - !ifdef SUPPORTS_ARM64 - ${if} ${IsNativeARM64} - File "/oname=${PRODUCT_EXECUTABLE}" "${ARG_WAILS_ARM64_BINARY}" - ${EndIf} - !endif -!macroend - -!macro wails.writeUninstaller - WriteUninstaller "$INSTDIR\uninstall.exe" - - SetRegView 64 - WriteRegStr HKLM "${UNINST_KEY}" "Publisher" "${INFO_COMPANYNAME}" - WriteRegStr HKLM "${UNINST_KEY}" "DisplayName" "${INFO_PRODUCTNAME}" - WriteRegStr HKLM "${UNINST_KEY}" "DisplayVersion" "${INFO_PRODUCTVERSION}" - WriteRegStr HKLM "${UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PRODUCT_EXECUTABLE}" - WriteRegStr HKLM "${UNINST_KEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\"" - WriteRegStr HKLM "${UNINST_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S" - - ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2 - IntFmt $0 "0x%08X" $0 - WriteRegDWORD HKLM "${UNINST_KEY}" "EstimatedSize" "$0" -!macroend - -!macro wails.deleteUninstaller - Delete "$INSTDIR\uninstall.exe" - - SetRegView 64 - DeleteRegKey HKLM "${UNINST_KEY}" -!macroend - -!macro wails.setShellContext - ${If} ${REQUEST_EXECUTION_LEVEL} == "admin" - SetShellVarContext all - ${else} - SetShellVarContext current - ${EndIf} -!macroend - -# Install webview2 by launching the bootstrapper -# See https://docs.microsoft.com/en-us/microsoft-edge/webview2/concepts/distribution#online-only-deployment -!macro wails.webview2runtime - !ifndef WAILS_INSTALL_WEBVIEW_DETAILPRINT - !define WAILS_INSTALL_WEBVIEW_DETAILPRINT "Installing: WebView2 Runtime" - !endif - - SetRegView 64 - # If the admin key exists and is not empty then webview2 is already installed - ReadRegStr $0 HKLM "SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv" - ${If} $0 != "" - Goto ok - ${EndIf} - - ${If} ${REQUEST_EXECUTION_LEVEL} == "user" - # If the installer is run in user level, check the user specific key exists and is not empty then webview2 is already installed - ReadRegStr $0 HKCU "Software\Microsoft\EdgeUpdate\Clients{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv" - ${If} $0 != "" - Goto ok - ${EndIf} - ${EndIf} - - SetDetailsPrint both - DetailPrint "${WAILS_INSTALL_WEBVIEW_DETAILPRINT}" - SetDetailsPrint listonly - - InitPluginsDir - CreateDirectory "$pluginsdir\webview2bootstrapper" - SetOutPath "$pluginsdir\webview2bootstrapper" - File "tmp\MicrosoftEdgeWebview2Setup.exe" - ExecWait '"$pluginsdir\webview2bootstrapper\MicrosoftEdgeWebview2Setup.exe" /silent /install' - - SetDetailsPrint both - ok: -!macroend - -# Copy of APP_ASSOCIATE and APP_UNASSOCIATE macros from here https://gist.github.com/nikku/281d0ef126dbc215dd58bfd5b3a5cd5b -!macro APP_ASSOCIATE EXT FILECLASS DESCRIPTION ICON COMMANDTEXT COMMAND - ; Backup the previously associated file class - ReadRegStr $R0 SHELL_CONTEXT "Software\Classes\.${EXT}" "" - WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "${FILECLASS}_backup" "$R0" - - WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "" "${FILECLASS}" - - WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}" "" `${DESCRIPTION}` - WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\DefaultIcon" "" `${ICON}` - WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell" "" "open" - WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell\open" "" `${COMMANDTEXT}` - WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell\open\command" "" `${COMMAND}` -!macroend - -!macro APP_UNASSOCIATE EXT FILECLASS - ; Backup the previously associated file class - ReadRegStr $R0 SHELL_CONTEXT "Software\Classes\.${EXT}" `${FILECLASS}_backup` - WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "" "$R0" - - DeleteRegKey SHELL_CONTEXT `Software\Classes\${FILECLASS}` -!macroend - -!macro wails.associateFiles - ; Create file associations - {{range .Info.FileAssociations}} - !insertmacro APP_ASSOCIATE "{{.Ext}}" "{{.Name}}" "{{.Description}}" "$INSTDIR\{{.IconName}}.ico" "Open with ${INFO_PRODUCTNAME}" "$INSTDIR\${PRODUCT_EXECUTABLE} $\"%1$\"" - - File "..\{{.IconName}}.ico" - {{end}} -!macroend - -!macro wails.unassociateFiles - ; Delete app associations - {{range .Info.FileAssociations}} - !insertmacro APP_UNASSOCIATE "{{.Ext}}" "{{.Name}}" - - Delete "$INSTDIR\{{.IconName}}.ico" - {{end}} -!macroend - -!macro CUSTOM_PROTOCOL_ASSOCIATE PROTOCOL DESCRIPTION ICON COMMAND - DeleteRegKey SHELL_CONTEXT "Software\Classes\${PROTOCOL}" - WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}" "" "${DESCRIPTION}" - WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}" "URL Protocol" "" - WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\DefaultIcon" "" "${ICON}" - WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell" "" "" - WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell\open" "" "" - WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell\open\command" "" "${COMMAND}" -!macroend - -!macro CUSTOM_PROTOCOL_UNASSOCIATE PROTOCOL - DeleteRegKey SHELL_CONTEXT "Software\Classes\${PROTOCOL}" -!macroend - -!macro wails.associateCustomProtocols - ; Create custom protocols associations - {{range .Info.Protocols}} - !insertmacro CUSTOM_PROTOCOL_ASSOCIATE "{{.Scheme}}" "{{.Description}}" "$INSTDIR\${PRODUCT_EXECUTABLE},0" "$INSTDIR\${PRODUCT_EXECUTABLE} $\"%1$\"" - - {{end}} -!macroend - -!macro wails.unassociateCustomProtocols - ; Delete app custom protocol associations - {{range .Info.Protocols}} - !insertmacro CUSTOM_PROTOCOL_UNASSOCIATE "{{.Scheme}}" - {{end}} -!macroend diff --git a/v2/examples/dragdrop-test/build/windows/wails.exe.manifest b/v2/examples/dragdrop-test/build/windows/wails.exe.manifest deleted file mode 100644 index 17e1a2387..000000000 --- a/v2/examples/dragdrop-test/build/windows/wails.exe.manifest +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - true/pm - permonitorv2,permonitor - - - \ No newline at end of file diff --git a/v2/examples/dragdrop-test/frontend/index.html b/v2/examples/dragdrop-test/frontend/index.html deleted file mode 100644 index 4010f1be6..000000000 --- a/v2/examples/dragdrop-test/frontend/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - dragdrop-test - - -
- - - diff --git a/v2/examples/dragdrop-test/frontend/package-lock.json b/v2/examples/dragdrop-test/frontend/package-lock.json deleted file mode 100644 index 8eed5313c..000000000 --- a/v2/examples/dragdrop-test/frontend/package-lock.json +++ /dev/null @@ -1,653 +0,0 @@ -{ - "name": "frontend", - "version": "0.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "frontend", - "version": "0.0.0", - "devDependencies": { - "vite": "^3.0.7" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz", - "integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz", - "integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz", - "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/android-arm": "0.15.18", - "@esbuild/linux-loong64": "0.15.18", - "esbuild-android-64": "0.15.18", - "esbuild-android-arm64": "0.15.18", - "esbuild-darwin-64": "0.15.18", - "esbuild-darwin-arm64": "0.15.18", - "esbuild-freebsd-64": "0.15.18", - "esbuild-freebsd-arm64": "0.15.18", - "esbuild-linux-32": "0.15.18", - "esbuild-linux-64": "0.15.18", - "esbuild-linux-arm": "0.15.18", - "esbuild-linux-arm64": "0.15.18", - "esbuild-linux-mips64le": "0.15.18", - "esbuild-linux-ppc64le": "0.15.18", - "esbuild-linux-riscv64": "0.15.18", - "esbuild-linux-s390x": "0.15.18", - "esbuild-netbsd-64": "0.15.18", - "esbuild-openbsd-64": "0.15.18", - "esbuild-sunos-64": "0.15.18", - "esbuild-windows-32": "0.15.18", - "esbuild-windows-64": "0.15.18", - "esbuild-windows-arm64": "0.15.18" - } - }, - "node_modules/esbuild-android-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz", - "integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-android-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz", - "integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-darwin-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz", - "integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-darwin-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz", - "integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-freebsd-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz", - "integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-freebsd-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz", - "integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-32": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz", - "integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz", - "integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-arm": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz", - "integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz", - "integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-mips64le": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz", - "integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-ppc64le": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz", - "integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-riscv64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz", - "integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-s390x": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz", - "integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-netbsd-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz", - "integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-openbsd-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz", - "integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-sunos-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz", - "integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-32": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz", - "integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz", - "integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz", - "integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "license": "MIT" - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/rollup": { - "version": "2.79.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz", - "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", - "dev": true, - "license": "MIT", - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=10.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/vite": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.11.tgz", - "integrity": "sha512-K/jGKL/PgbIgKCiJo5QbASQhFiV02X9Jh+Qq0AKCRCRKZtOTVi4t6wh75FDpGf2N9rYOnzH87OEFQNaFy6pdxQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "^0.15.9", - "postcss": "^8.4.18", - "resolve": "^1.22.1", - "rollup": "^2.79.1" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - }, - "peerDependencies": { - "@types/node": ">= 14", - "less": "*", - "sass": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "sass": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - } - } -} diff --git a/v2/examples/dragdrop-test/frontend/package.json b/v2/examples/dragdrop-test/frontend/package.json deleted file mode 100644 index a1b6f8e1a..000000000 --- a/v2/examples/dragdrop-test/frontend/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "frontend", - "private": true, - "version": "0.0.0", - "scripts": { - "dev": "vite", - "build": "vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^3.0.7" - } -} \ No newline at end of file diff --git a/v2/examples/dragdrop-test/frontend/src/app.css b/v2/examples/dragdrop-test/frontend/src/app.css deleted file mode 100644 index 1d3b595bc..000000000 --- a/v2/examples/dragdrop-test/frontend/src/app.css +++ /dev/null @@ -1,229 +0,0 @@ -/* #app styles are in style.css to avoid conflicts */ - -.compact-container { - display: flex; - gap: 15px; - margin: 15px 0; - justify-content: center; - align-items: flex-start; -} - -.drag-source { - background: white; - border: 2px solid #5c6bc0; - padding: 12px; - min-width: 140px; - border-radius: 6px; - box-shadow: 0 2px 4px rgba(0,0,0,0.1); -} - -.drag-source h4 { - color: #3949ab; - margin: 0 0 8px 0; - font-size: 14px; -} - -.draggable { - background: #f5f5f5; - color: #1a1a1a; - padding: 8px; - margin: 6px 0; - border-radius: 4px; - cursor: move; - text-align: center; - transition: all 0.3s ease; - font-weight: 600; - font-size: 14px; - border: 2px solid #c5cae9; - box-shadow: 0 2px 4px rgba(0,0,0,0.1); -} - -.draggable:hover { - transform: translateY(-2px); - box-shadow: 0 4px 12px rgba(0,0,0,0.15); - background: #e8eaf6; - border-color: #7986cb; -} - -.draggable.dragging { - opacity: 0.5; - transform: scale(0.95); - background: #c5cae9; -} - -.drop-zone { - background: #f8f9fa; - border: 2px dashed #9e9e9e; - padding: 12px; - min-width: 180px; - min-height: 120px; - border-radius: 6px; - transition: all 0.3s ease; -} - -.drop-zone h4 { - color: #5c6bc0; - margin: 0 0 8px 0; - font-size: 14px; -} - -.drop-zone.drag-over { - background: #e3f2fd; - border-color: #2196F3; - transform: scale(1.02); - box-shadow: 0 4px 12px rgba(33, 150, 243, 0.2); -} - -.file-drop-zone { - background: #fff8e1; - border: 2px dashed #ffc107; - padding: 12px; - min-width: 180px; - min-height: 120px; - border-radius: 6px; - transition: all 0.3s ease; -} - -.file-drop-zone h4 { - color: #f57c00; - margin: 0 0 8px 0; - font-size: 14px; -} - -.file-drop-zone.drag-over { - background: #fff3cd; - border-color: #ff9800; - transform: scale(1.02); - box-shadow: 0 4px 12px rgba(255, 152, 0, 0.2); -} - -.dropped-item { - background: linear-gradient(135deg, #42a5f5 0%, #66bb6a 100%); - color: white; - padding: 6px 8px; - margin: 4px 2px; - border-radius: 4px; - text-align: center; - animation: slideIn 0.3s ease; - display: inline-block; - font-weight: 500; - font-size: 13px; -} - -.dropped-file { - background: #fff; - border: 2px solid #ff9800; - color: #333; - padding: 6px 8px; - margin: 4px 0; - border-radius: 4px; - text-align: left; - animation: slideIn 0.3s ease; - box-shadow: 0 2px 4px rgba(0,0,0,0.1); - font-size: 13px; -} - -#dropMessage, #fileDropMessage { - font-size: 12px; - color: #666; - margin: 4px 0; -} - -@keyframes slideIn { - from { - opacity: 0; - transform: translateY(-10px); - } - to { - opacity: 1; - transform: translateY(0); - } -} - -.status { - margin: 15px auto; - max-width: 1000px; - padding: 12px; - background: #2c3e50; - border-radius: 6px; - box-shadow: 0 2px 4px rgba(0,0,0,0.1); -} - -.status h4 { - color: white; - margin: 0 0 8px 0; - font-size: 14px; -} - -#eventLog { - background: #1a1a1a; - padding: 10px; - border-radius: 4px; - max-height: 200px; - overflow-y: auto; - font-family: 'Courier New', monospace; - text-align: left; - font-size: 12px; -} - -.log-entry { - padding: 4px 8px; - font-size: 13px; - margin: 2px 0; - border-radius: 3px; -} - -.log-entry.drag-start { - color: #81c784; - background: rgba(129, 199, 132, 0.1); -} - -.log-entry.drag-over { - color: #64b5f6; - background: rgba(100, 181, 246, 0.1); -} - -.log-entry.drag-enter { - color: #ffb74d; - background: rgba(255, 183, 77, 0.1); -} - -.log-entry.drag-leave { - color: #ba68c8; - background: rgba(186, 104, 200, 0.1); -} - -.log-entry.drop { - color: #e57373; - background: rgba(229, 115, 115, 0.1); - font-weight: bold; -} - -.log-entry.drag-end { - color: #90a4ae; - background: rgba(144, 164, 174, 0.1); -} - -.log-entry.file-drop { - color: #ffc107; - background: rgba(255, 193, 7, 0.1); - font-weight: bold; -} - -.log-entry.page-loaded { - color: #4caf50; - background: rgba(76, 175, 80, 0.1); -} - -.log-entry.wails-status { - color: #00bcd4; - background: rgba(0, 188, 212, 0.1); -} - -h1 { - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - font-size: 1.8em; - margin: 10px 0 8px 0; -} \ No newline at end of file diff --git a/v2/examples/dragdrop-test/frontend/src/assets/fonts/OFL.txt b/v2/examples/dragdrop-test/frontend/src/assets/fonts/OFL.txt deleted file mode 100644 index 9cac04ce8..000000000 --- a/v2/examples/dragdrop-test/frontend/src/assets/fonts/OFL.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com), - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/v2/examples/dragdrop-test/frontend/src/assets/images/logo-universal.png b/v2/examples/dragdrop-test/frontend/src/assets/images/logo-universal.png deleted file mode 100644 index d63303bfa..000000000 Binary files a/v2/examples/dragdrop-test/frontend/src/assets/images/logo-universal.png and /dev/null differ diff --git a/v2/examples/dragdrop-test/frontend/src/main.js b/v2/examples/dragdrop-test/frontend/src/main.js deleted file mode 100644 index 60d76ac0f..000000000 --- a/v2/examples/dragdrop-test/frontend/src/main.js +++ /dev/null @@ -1,231 +0,0 @@ -import './style.css'; -import './app.css'; - -// CRITICAL: Register global handlers IMMEDIATELY to prevent file drops from opening new windows -// This must be done as early as possible, before any other code runs -(function() { - // Helper function to check if drag event contains files - function isFileDrop(e) { - return e.dataTransfer && e.dataTransfer.types && - (e.dataTransfer.types.includes('Files') || - Array.from(e.dataTransfer.types).includes('Files')); - } - - // Global dragover handler - MUST prevent default for file drops - window.addEventListener('dragover', function(e) { - if (isFileDrop(e)) { - e.preventDefault(); - e.dataTransfer.dropEffect = 'copy'; - } - }, true); // Use capture phase to handle before any other handlers - - // Global drop handler - MUST prevent default for file drops - window.addEventListener('drop', function(e) { - if (isFileDrop(e)) { - e.preventDefault(); - console.log('Global handler prevented file drop navigation'); - } - }, true); // Use capture phase to handle before any other handlers - - // Global dragleave handler - window.addEventListener('dragleave', function(e) { - if (isFileDrop(e)) { - e.preventDefault(); - } - }, true); // Use capture phase - - console.log('Global file drop prevention handlers registered'); -})(); - -document.querySelector('#app').innerHTML = ` -

Wails Drag & Drop Test

- -
-
-

HTML5 Source

-
Item 1
-
Item 2
-
Item 3
-
- -
-

HTML5 Drop

-

Drop here

-
- -
-

File Drop

-

Drop files here

-
-
- -
-

Event Log

-
-
-`; - -// Get all draggable items and drop zones -const draggables = document.querySelectorAll('.draggable'); -const dropZone = document.getElementById('dropZone'); -const fileDropZone = document.getElementById('fileDropZone'); -const eventLog = document.getElementById('eventLog'); -const dropMessage = document.getElementById('dropMessage'); -const fileDropMessage = document.getElementById('fileDropMessage'); - -let draggedItem = null; -let eventCounter = 0; - -// Function to log events -function logEvent(eventName, details = '') { - eventCounter++; - const timestamp = new Date().toLocaleTimeString(); - const logEntry = document.createElement('div'); - logEntry.className = `log-entry ${eventName.replace(' ', '-').toLowerCase()}`; - logEntry.textContent = `[${timestamp}] ${eventCounter}. ${eventName} ${details}`; - eventLog.insertBefore(logEntry, eventLog.firstChild); - - // Keep only last 20 events - while (eventLog.children.length > 20) { - eventLog.removeChild(eventLog.lastChild); - } - - console.log(`Event: ${eventName} ${details}`); -} - -// Add event listeners to draggable items -draggables.forEach(item => { - // Drag start - item.addEventListener('dragstart', (e) => { - draggedItem = e.target; - e.target.classList.add('dragging'); - e.dataTransfer.effectAllowed = 'copy'; - e.dataTransfer.setData('text/plain', e.target.dataset.item); - logEvent('drag-start', `- Started dragging: ${e.target.dataset.item}`); - }); - - // Drag end - item.addEventListener('dragend', (e) => { - e.target.classList.remove('dragging'); - logEvent('drag-end', `- Ended dragging: ${e.target.dataset.item}`); - }); -}); - -// Add event listeners to HTML drop zone -dropZone.addEventListener('dragenter', (e) => { - e.preventDefault(); - dropZone.classList.add('drag-over'); - logEvent('drag-enter', '- Entered HTML drop zone'); -}); - -dropZone.addEventListener('dragover', (e) => { - e.preventDefault(); - e.dataTransfer.dropEffect = 'copy'; - // Don't log every dragover to avoid spam -}); - -dropZone.addEventListener('dragleave', (e) => { - if (e.target === dropZone) { - dropZone.classList.remove('drag-over'); - logEvent('drag-leave', '- Left HTML drop zone'); - } -}); - -dropZone.addEventListener('drop', (e) => { - e.preventDefault(); - dropZone.classList.remove('drag-over'); - - const data = e.dataTransfer.getData('text/plain'); - logEvent('drop', `- Dropped in HTML zone: ${data}`); - - if (draggedItem) { - // Create a copy of the dragged item - const droppedElement = document.createElement('div'); - droppedElement.className = 'dropped-item'; - droppedElement.textContent = data; - - // Remove the placeholder message if it exists - if (dropMessage) { - dropMessage.style.display = 'none'; - } - - dropZone.appendChild(droppedElement); - } - - draggedItem = null; -}); - -// Add event listeners to file drop zone -fileDropZone.addEventListener('dragenter', (e) => { - e.preventDefault(); - fileDropZone.classList.add('drag-over'); - logEvent('drag-enter', '- Entered file drop zone'); -}); - -fileDropZone.addEventListener('dragover', (e) => { - e.preventDefault(); - e.dataTransfer.dropEffect = 'copy'; -}); - -fileDropZone.addEventListener('dragleave', (e) => { - if (e.target === fileDropZone) { - fileDropZone.classList.remove('drag-over'); - logEvent('drag-leave', '- Left file drop zone'); - } -}); - -fileDropZone.addEventListener('drop', (e) => { - e.preventDefault(); - fileDropZone.classList.remove('drag-over'); - - const files = [...e.dataTransfer.files]; - if (files.length > 0) { - logEvent('file-drop', `- Dropped ${files.length} file(s)`); - - // Hide the placeholder message - if (fileDropMessage) { - fileDropMessage.style.display = 'none'; - } - - // Display dropped files - files.forEach(file => { - const fileElement = document.createElement('div'); - fileElement.className = 'dropped-file'; - - // Format file size - let size = file.size; - let unit = 'bytes'; - if (size > 1024 * 1024) { - size = (size / (1024 * 1024)).toFixed(2); - unit = 'MB'; - } else if (size > 1024) { - size = (size / 1024).toFixed(2); - unit = 'KB'; - } - - fileElement.textContent = `📄 ${file.name} (${size} ${unit})`; - fileDropZone.appendChild(fileElement); - }); - } -}); - -// Log when page loads -window.addEventListener('DOMContentLoaded', () => { - logEvent('page-loaded', '- Wails drag-and-drop test page ready'); - console.log('Wails Drag and Drop test application loaded'); - - // Check if Wails drag and drop is enabled - if (window.wails && window.wails.flags) { - logEvent('wails-status', `- Wails DnD enabled: ${window.wails.flags.enableWailsDragAndDrop}`); - } - - // IMPORTANT: Register Wails drag-and-drop handlers to prevent browser navigation - // This will ensure external files don't open in new windows when dropped anywhere - if (window.runtime && window.runtime.OnFileDrop) { - window.runtime.OnFileDrop((x, y, paths) => { - logEvent('wails-file-drop', `- Wails received ${paths.length} file(s) at (${x}, ${y})`); - console.log('Wails OnFileDrop:', paths); - }, false); // false = don't require drop target, handle all file drops - logEvent('wails-setup', '- Wails OnFileDrop handlers registered'); - } -}); \ No newline at end of file diff --git a/v2/examples/dragdrop-test/frontend/src/style.css b/v2/examples/dragdrop-test/frontend/src/style.css deleted file mode 100644 index f5d071597..000000000 --- a/v2/examples/dragdrop-test/frontend/src/style.css +++ /dev/null @@ -1,33 +0,0 @@ -html { - background-color: rgba(27, 38, 54, 1); - text-align: center; - color: white; - height: 100%; - overflow: hidden; -} - -body { - margin: 0; - color: white; - font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", - "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", - sans-serif; - height: 100%; - overflow: hidden; -} - -@font-face { - font-family: "Nunito"; - font-style: normal; - font-weight: 400; - src: local(""), - url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2"); -} - -#app { - height: 100vh; - text-align: center; - overflow: hidden; - box-sizing: border-box; - padding: 10px; -} diff --git a/v2/examples/dragdrop-test/frontend/wailsjs/go/main/App.d.ts b/v2/examples/dragdrop-test/frontend/wailsjs/go/main/App.d.ts deleted file mode 100644 index 02a3bb988..000000000 --- a/v2/examples/dragdrop-test/frontend/wailsjs/go/main/App.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Greet(arg1:string):Promise; diff --git a/v2/examples/dragdrop-test/frontend/wailsjs/go/main/App.js b/v2/examples/dragdrop-test/frontend/wailsjs/go/main/App.js deleted file mode 100644 index c71ae77cb..000000000 --- a/v2/examples/dragdrop-test/frontend/wailsjs/go/main/App.js +++ /dev/null @@ -1,7 +0,0 @@ -// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Greet(arg1) { - return window['go']['main']['App']['Greet'](arg1); -} diff --git a/v2/examples/dragdrop-test/frontend/wailsjs/runtime/package.json b/v2/examples/dragdrop-test/frontend/wailsjs/runtime/package.json deleted file mode 100644 index 1e7c8a5d7..000000000 --- a/v2/examples/dragdrop-test/frontend/wailsjs/runtime/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "@wailsapp/runtime", - "version": "2.0.0", - "description": "Wails Javascript runtime library", - "main": "runtime.js", - "types": "runtime.d.ts", - "scripts": { - }, - "repository": { - "type": "git", - "url": "git+https://github.com/wailsapp/wails.git" - }, - "keywords": [ - "Wails", - "Javascript", - "Go" - ], - "author": "Lea Anthony ", - "license": "MIT", - "bugs": { - "url": "https://github.com/wailsapp/wails/issues" - }, - "homepage": "https://github.com/wailsapp/wails#readme" -} diff --git a/v2/examples/dragdrop-test/frontend/wailsjs/runtime/runtime.d.ts b/v2/examples/dragdrop-test/frontend/wailsjs/runtime/runtime.d.ts deleted file mode 100644 index 4445dac21..000000000 --- a/v2/examples/dragdrop-test/frontend/wailsjs/runtime/runtime.d.ts +++ /dev/null @@ -1,249 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export interface Position { - x: number; - y: number; -} - -export interface Size { - w: number; - h: number; -} - -export interface Screen { - isCurrent: boolean; - isPrimary: boolean; - width : number - height : number -} - -// Environment information such as platform, buildtype, ... -export interface EnvironmentInfo { - buildType: string; - platform: string; - arch: string; -} - -// [EventsEmit](https://wails.io/docs/reference/runtime/events#eventsemit) -// emits the given event. Optional data may be passed with the event. -// This will trigger any event listeners. -export function EventsEmit(eventName: string, ...data: any): void; - -// [EventsOn](https://wails.io/docs/reference/runtime/events#eventson) sets up a listener for the given event name. -export function EventsOn(eventName: string, callback: (...data: any) => void): () => void; - -// [EventsOnMultiple](https://wails.io/docs/reference/runtime/events#eventsonmultiple) -// sets up a listener for the given event name, but will only trigger a given number times. -export function EventsOnMultiple(eventName: string, callback: (...data: any) => void, maxCallbacks: number): () => void; - -// [EventsOnce](https://wails.io/docs/reference/runtime/events#eventsonce) -// sets up a listener for the given event name, but will only trigger once. -export function EventsOnce(eventName: string, callback: (...data: any) => void): () => void; - -// [EventsOff](https://wails.io/docs/reference/runtime/events#eventsoff) -// unregisters the listener for the given event name. -export function EventsOff(eventName: string, ...additionalEventNames: string[]): void; - -// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) -// unregisters all listeners. -export function EventsOffAll(): void; - -// [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) -// logs the given message as a raw message -export function LogPrint(message: string): void; - -// [LogTrace](https://wails.io/docs/reference/runtime/log#logtrace) -// logs the given message at the `trace` log level. -export function LogTrace(message: string): void; - -// [LogDebug](https://wails.io/docs/reference/runtime/log#logdebug) -// logs the given message at the `debug` log level. -export function LogDebug(message: string): void; - -// [LogError](https://wails.io/docs/reference/runtime/log#logerror) -// logs the given message at the `error` log level. -export function LogError(message: string): void; - -// [LogFatal](https://wails.io/docs/reference/runtime/log#logfatal) -// logs the given message at the `fatal` log level. -// The application will quit after calling this method. -export function LogFatal(message: string): void; - -// [LogInfo](https://wails.io/docs/reference/runtime/log#loginfo) -// logs the given message at the `info` log level. -export function LogInfo(message: string): void; - -// [LogWarning](https://wails.io/docs/reference/runtime/log#logwarning) -// logs the given message at the `warning` log level. -export function LogWarning(message: string): void; - -// [WindowReload](https://wails.io/docs/reference/runtime/window#windowreload) -// Forces a reload by the main application as well as connected browsers. -export function WindowReload(): void; - -// [WindowReloadApp](https://wails.io/docs/reference/runtime/window#windowreloadapp) -// Reloads the application frontend. -export function WindowReloadApp(): void; - -// [WindowSetAlwaysOnTop](https://wails.io/docs/reference/runtime/window#windowsetalwaysontop) -// Sets the window AlwaysOnTop or not on top. -export function WindowSetAlwaysOnTop(b: boolean): void; - -// [WindowSetSystemDefaultTheme](https://wails.io/docs/next/reference/runtime/window#windowsetsystemdefaulttheme) -// *Windows only* -// Sets window theme to system default (dark/light). -export function WindowSetSystemDefaultTheme(): void; - -// [WindowSetLightTheme](https://wails.io/docs/next/reference/runtime/window#windowsetlighttheme) -// *Windows only* -// Sets window to light theme. -export function WindowSetLightTheme(): void; - -// [WindowSetDarkTheme](https://wails.io/docs/next/reference/runtime/window#windowsetdarktheme) -// *Windows only* -// Sets window to dark theme. -export function WindowSetDarkTheme(): void; - -// [WindowCenter](https://wails.io/docs/reference/runtime/window#windowcenter) -// Centers the window on the monitor the window is currently on. -export function WindowCenter(): void; - -// [WindowSetTitle](https://wails.io/docs/reference/runtime/window#windowsettitle) -// Sets the text in the window title bar. -export function WindowSetTitle(title: string): void; - -// [WindowFullscreen](https://wails.io/docs/reference/runtime/window#windowfullscreen) -// Makes the window full screen. -export function WindowFullscreen(): void; - -// [WindowUnfullscreen](https://wails.io/docs/reference/runtime/window#windowunfullscreen) -// Restores the previous window dimensions and position prior to full screen. -export function WindowUnfullscreen(): void; - -// [WindowIsFullscreen](https://wails.io/docs/reference/runtime/window#windowisfullscreen) -// Returns the state of the window, i.e. whether the window is in full screen mode or not. -export function WindowIsFullscreen(): Promise; - -// [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize) -// Sets the width and height of the window. -export function WindowSetSize(width: number, height: number): void; - -// [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize) -// Gets the width and height of the window. -export function WindowGetSize(): Promise; - -// [WindowSetMaxSize](https://wails.io/docs/reference/runtime/window#windowsetmaxsize) -// Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMaxSize(width: number, height: number): void; - -// [WindowSetMinSize](https://wails.io/docs/reference/runtime/window#windowsetminsize) -// Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMinSize(width: number, height: number): void; - -// [WindowSetPosition](https://wails.io/docs/reference/runtime/window#windowsetposition) -// Sets the window position relative to the monitor the window is currently on. -export function WindowSetPosition(x: number, y: number): void; - -// [WindowGetPosition](https://wails.io/docs/reference/runtime/window#windowgetposition) -// Gets the window position relative to the monitor the window is currently on. -export function WindowGetPosition(): Promise; - -// [WindowHide](https://wails.io/docs/reference/runtime/window#windowhide) -// Hides the window. -export function WindowHide(): void; - -// [WindowShow](https://wails.io/docs/reference/runtime/window#windowshow) -// Shows the window, if it is currently hidden. -export function WindowShow(): void; - -// [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise) -// Maximises the window to fill the screen. -export function WindowMaximise(): void; - -// [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise) -// Toggles between Maximised and UnMaximised. -export function WindowToggleMaximise(): void; - -// [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise) -// Restores the window to the dimensions and position prior to maximising. -export function WindowUnmaximise(): void; - -// [WindowIsMaximised](https://wails.io/docs/reference/runtime/window#windowismaximised) -// Returns the state of the window, i.e. whether the window is maximised or not. -export function WindowIsMaximised(): Promise; - -// [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise) -// Minimises the window. -export function WindowMinimise(): void; - -// [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise) -// Restores the window to the dimensions and position prior to minimising. -export function WindowUnminimise(): void; - -// [WindowIsMinimised](https://wails.io/docs/reference/runtime/window#windowisminimised) -// Returns the state of the window, i.e. whether the window is minimised or not. -export function WindowIsMinimised(): Promise; - -// [WindowIsNormal](https://wails.io/docs/reference/runtime/window#windowisnormal) -// Returns the state of the window, i.e. whether the window is normal or not. -export function WindowIsNormal(): Promise; - -// [WindowSetBackgroundColour](https://wails.io/docs/reference/runtime/window#windowsetbackgroundcolour) -// Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels. -export function WindowSetBackgroundColour(R: number, G: number, B: number, A: number): void; - -// [ScreenGetAll](https://wails.io/docs/reference/runtime/window#screengetall) -// Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system. -export function ScreenGetAll(): Promise; - -// [BrowserOpenURL](https://wails.io/docs/reference/runtime/browser#browseropenurl) -// Opens the given URL in the system browser. -export function BrowserOpenURL(url: string): void; - -// [Environment](https://wails.io/docs/reference/runtime/intro#environment) -// Returns information about the environment -export function Environment(): Promise; - -// [Quit](https://wails.io/docs/reference/runtime/intro#quit) -// Quits the application. -export function Quit(): void; - -// [Hide](https://wails.io/docs/reference/runtime/intro#hide) -// Hides the application. -export function Hide(): void; - -// [Show](https://wails.io/docs/reference/runtime/intro#show) -// Shows the application. -export function Show(): void; - -// [ClipboardGetText](https://wails.io/docs/reference/runtime/clipboard#clipboardgettext) -// Returns the current text stored on clipboard -export function ClipboardGetText(): Promise; - -// [ClipboardSetText](https://wails.io/docs/reference/runtime/clipboard#clipboardsettext) -// Sets a text on the clipboard -export function ClipboardSetText(text: string): Promise; - -// [OnFileDrop](https://wails.io/docs/reference/runtime/draganddrop#onfiledrop) -// OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings. -export function OnFileDrop(callback: (x: number, y: number ,paths: string[]) => void, useDropTarget: boolean) :void - -// [OnFileDropOff](https://wails.io/docs/reference/runtime/draganddrop#dragandddropoff) -// OnFileDropOff removes the drag and drop listeners and handlers. -export function OnFileDropOff() :void - -// Check if the file path resolver is available -export function CanResolveFilePaths(): boolean; - -// Resolves file paths for an array of files -export function ResolveFilePaths(files: File[]): void \ No newline at end of file diff --git a/v2/examples/dragdrop-test/frontend/wailsjs/runtime/runtime.js b/v2/examples/dragdrop-test/frontend/wailsjs/runtime/runtime.js deleted file mode 100644 index 7cb89d750..000000000 --- a/v2/examples/dragdrop-test/frontend/wailsjs/runtime/runtime.js +++ /dev/null @@ -1,242 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export function LogPrint(message) { - window.runtime.LogPrint(message); -} - -export function LogTrace(message) { - window.runtime.LogTrace(message); -} - -export function LogDebug(message) { - window.runtime.LogDebug(message); -} - -export function LogInfo(message) { - window.runtime.LogInfo(message); -} - -export function LogWarning(message) { - window.runtime.LogWarning(message); -} - -export function LogError(message) { - window.runtime.LogError(message); -} - -export function LogFatal(message) { - window.runtime.LogFatal(message); -} - -export function EventsOnMultiple(eventName, callback, maxCallbacks) { - return window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks); -} - -export function EventsOn(eventName, callback) { - return EventsOnMultiple(eventName, callback, -1); -} - -export function EventsOff(eventName, ...additionalEventNames) { - return window.runtime.EventsOff(eventName, ...additionalEventNames); -} - -export function EventsOffAll() { - return window.runtime.EventsOffAll(); -} - -export function EventsOnce(eventName, callback) { - return EventsOnMultiple(eventName, callback, 1); -} - -export function EventsEmit(eventName) { - let args = [eventName].slice.call(arguments); - return window.runtime.EventsEmit.apply(null, args); -} - -export function WindowReload() { - window.runtime.WindowReload(); -} - -export function WindowReloadApp() { - window.runtime.WindowReloadApp(); -} - -export function WindowSetAlwaysOnTop(b) { - window.runtime.WindowSetAlwaysOnTop(b); -} - -export function WindowSetSystemDefaultTheme() { - window.runtime.WindowSetSystemDefaultTheme(); -} - -export function WindowSetLightTheme() { - window.runtime.WindowSetLightTheme(); -} - -export function WindowSetDarkTheme() { - window.runtime.WindowSetDarkTheme(); -} - -export function WindowCenter() { - window.runtime.WindowCenter(); -} - -export function WindowSetTitle(title) { - window.runtime.WindowSetTitle(title); -} - -export function WindowFullscreen() { - window.runtime.WindowFullscreen(); -} - -export function WindowUnfullscreen() { - window.runtime.WindowUnfullscreen(); -} - -export function WindowIsFullscreen() { - return window.runtime.WindowIsFullscreen(); -} - -export function WindowGetSize() { - return window.runtime.WindowGetSize(); -} - -export function WindowSetSize(width, height) { - window.runtime.WindowSetSize(width, height); -} - -export function WindowSetMaxSize(width, height) { - window.runtime.WindowSetMaxSize(width, height); -} - -export function WindowSetMinSize(width, height) { - window.runtime.WindowSetMinSize(width, height); -} - -export function WindowSetPosition(x, y) { - window.runtime.WindowSetPosition(x, y); -} - -export function WindowGetPosition() { - return window.runtime.WindowGetPosition(); -} - -export function WindowHide() { - window.runtime.WindowHide(); -} - -export function WindowShow() { - window.runtime.WindowShow(); -} - -export function WindowMaximise() { - window.runtime.WindowMaximise(); -} - -export function WindowToggleMaximise() { - window.runtime.WindowToggleMaximise(); -} - -export function WindowUnmaximise() { - window.runtime.WindowUnmaximise(); -} - -export function WindowIsMaximised() { - return window.runtime.WindowIsMaximised(); -} - -export function WindowMinimise() { - window.runtime.WindowMinimise(); -} - -export function WindowUnminimise() { - window.runtime.WindowUnminimise(); -} - -export function WindowSetBackgroundColour(R, G, B, A) { - window.runtime.WindowSetBackgroundColour(R, G, B, A); -} - -export function ScreenGetAll() { - return window.runtime.ScreenGetAll(); -} - -export function WindowIsMinimised() { - return window.runtime.WindowIsMinimised(); -} - -export function WindowIsNormal() { - return window.runtime.WindowIsNormal(); -} - -export function BrowserOpenURL(url) { - window.runtime.BrowserOpenURL(url); -} - -export function Environment() { - return window.runtime.Environment(); -} - -export function Quit() { - window.runtime.Quit(); -} - -export function Hide() { - window.runtime.Hide(); -} - -export function Show() { - window.runtime.Show(); -} - -export function ClipboardGetText() { - return window.runtime.ClipboardGetText(); -} - -export function ClipboardSetText(text) { - return window.runtime.ClipboardSetText(text); -} - -/** - * Callback for OnFileDrop returns a slice of file path strings when a drop is finished. - * - * @export - * @callback OnFileDropCallback - * @param {number} x - x coordinate of the drop - * @param {number} y - y coordinate of the drop - * @param {string[]} paths - A list of file paths. - */ - -/** - * OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings. - * - * @export - * @param {OnFileDropCallback} callback - Callback for OnFileDrop returns a slice of file path strings when a drop is finished. - * @param {boolean} [useDropTarget=true] - Only call the callback when the drop finished on an element that has the drop target style. (--wails-drop-target) - */ -export function OnFileDrop(callback, useDropTarget) { - return window.runtime.OnFileDrop(callback, useDropTarget); -} - -/** - * OnFileDropOff removes the drag and drop listeners and handlers. - */ -export function OnFileDropOff() { - return window.runtime.OnFileDropOff(); -} - -export function CanResolveFilePaths() { - return window.runtime.CanResolveFilePaths(); -} - -export function ResolveFilePaths(files) { - return window.runtime.ResolveFilePaths(files); -} \ No newline at end of file diff --git a/v2/examples/dragdrop-test/go.mod b/v2/examples/dragdrop-test/go.mod deleted file mode 100644 index be13aac19..000000000 --- a/v2/examples/dragdrop-test/go.mod +++ /dev/null @@ -1,37 +0,0 @@ -module dragdrop-test - -go 1.23 - -require github.com/wailsapp/wails/v2 v2.10.1 - -require ( - github.com/bep/debounce v1.2.1 // indirect - github.com/go-ole/go-ole v1.3.0 // indirect - github.com/godbus/dbus/v5 v5.1.0 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/gorilla/websocket v1.5.3 // indirect - github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect - github.com/labstack/echo/v4 v4.13.3 // indirect - github.com/labstack/gommon v0.4.2 // indirect - github.com/leaanthony/go-ansi-parser v1.6.1 // indirect - github.com/leaanthony/gosod v1.0.4 // indirect - github.com/leaanthony/slicer v1.6.0 // indirect - github.com/leaanthony/u v1.1.1 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect - github.com/pkg/errors v0.9.1 // indirect - github.com/rivo/uniseg v0.4.7 // indirect - github.com/samber/lo v1.49.1 // indirect - github.com/tkrajina/go-reflector v0.5.8 // indirect - github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasttemplate v1.2.2 // indirect - github.com/wailsapp/go-webview2 v1.0.22 // indirect - github.com/wailsapp/mimetype v1.4.1 // indirect - golang.org/x/crypto v0.33.0 // indirect - golang.org/x/net v0.35.0 // indirect - golang.org/x/sys v0.30.0 // indirect - golang.org/x/text v0.22.0 // indirect -) - -replace github.com/wailsapp/wails/v2 => E:/releases/wails/v2 diff --git a/v2/examples/dragdrop-test/go.sum b/v2/examples/dragdrop-test/go.sum deleted file mode 100644 index 10d4a9b18..000000000 --- a/v2/examples/dragdrop-test/go.sum +++ /dev/null @@ -1,79 +0,0 @@ -github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY= -github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= -github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= -github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= -github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= -github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck= -github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs= -github.com/labstack/echo/v4 v4.13.3 h1:pwhpCPrTl5qry5HRdM5FwdXnhXSLSY+WE+YQSeCaafY= -github.com/labstack/echo/v4 v4.13.3/go.mod h1:o90YNEeQWjDozo584l7AwhJMHN0bOC4tAfg+Xox9q5g= -github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= -github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= -github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc= -github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA= -github.com/leaanthony/go-ansi-parser v1.6.1 h1:xd8bzARK3dErqkPFtoF9F3/HgN8UQk0ed1YDKpEz01A= -github.com/leaanthony/go-ansi-parser v1.6.1/go.mod h1:+vva/2y4alzVmmIEpk9QDhA7vLC5zKDTRwfZGOp3IWU= -github.com/leaanthony/gosod v1.0.4 h1:YLAbVyd591MRffDgxUOU1NwLhT9T1/YiwjKZpkNFeaI= -github.com/leaanthony/gosod v1.0.4/go.mod h1:GKuIL0zzPj3O1SdWQOdgURSuhkF+Urizzxh26t9f1cw= -github.com/leaanthony/slicer v1.6.0 h1:1RFP5uiPJvT93TAHi+ipd3NACobkW53yUiBqZheE/Js= -github.com/leaanthony/slicer v1.6.0/go.mod h1:o/Iz29g7LN0GqH3aMjWAe90381nyZlDNquK+mtH2Fj8= -github.com/leaanthony/u v1.1.1 h1:TUFjwDGlNX+WuwVEzDqQwC2lOv0P4uhTQw7CMFdiK7M= -github.com/leaanthony/u v1.1.1/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQcaRfI= -github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= -github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ= -github.com/matryer/is v1.4.1/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= -github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= -github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/samber/lo v1.49.1 h1:4BIFyVfuQSEpluc7Fua+j1NolZHiEHEpaSEKdsH0tew= -github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/tkrajina/go-reflector v0.5.8 h1:yPADHrwmUbMq4RGEyaOUpz2H90sRsETNVpjzo3DLVQQ= -github.com/tkrajina/go-reflector v0.5.8/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4= -github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= -github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -github.com/wailsapp/go-webview2 v1.0.22 h1:YT61F5lj+GGaat5OB96Aa3b4QA+mybD0Ggq6NZijQ58= -github.com/wailsapp/go-webview2 v1.0.22/go.mod h1:qJmWAmAmaniuKGZPWwne+uor3AHMB5PFhqiK0Bbj8kc= -github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs= -github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o= -golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= -golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= -golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= -golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/v2/examples/dragdrop-test/main.go b/v2/examples/dragdrop-test/main.go deleted file mode 100644 index 64a0c2734..000000000 --- a/v2/examples/dragdrop-test/main.go +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import ( - "embed" - - "github.com/wailsapp/wails/v2" - "github.com/wailsapp/wails/v2/pkg/options" - "github.com/wailsapp/wails/v2/pkg/options/assetserver" -) - -//go:embed all:frontend/dist -var assets embed.FS - -func main() { - // Create an instance of the app structure - app := NewApp() - - // Create application with options - err := wails.Run(&options.App{ - Title: "Wails Drag & Drop Test", - Width: 800, - Height: 600, - AssetServer: &assetserver.Options{ - Assets: assets, - }, - BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, - OnStartup: app.startup, - Bind: []interface{}{ - app, - }, - }) - - if err != nil { - println("Error:", err.Error()) - } -} diff --git a/v2/examples/dragdrop-test/wails.json b/v2/examples/dragdrop-test/wails.json deleted file mode 100644 index 7970ea4ca..000000000 --- a/v2/examples/dragdrop-test/wails.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "$schema": "https://wails.io/schemas/config.v2.json", - "name": "dragdrop-test", - "outputfilename": "dragdrop-test", - "frontend:install": "npm install", - "frontend:build": "npm run build", - "frontend:dev:watcher": "npm run dev", - "frontend:dev:serverUrl": "auto", - "author": { - "name": "Lea Anthony", - "email": "lea.anthony@gmail.com" - } -} diff --git a/v2/examples/panic-recovery-test/README.md b/v2/examples/panic-recovery-test/README.md deleted file mode 100644 index c0a6a7e5a..000000000 --- a/v2/examples/panic-recovery-test/README.md +++ /dev/null @@ -1,76 +0,0 @@ -# Panic Recovery Test - -This example demonstrates the Linux signal handler issue (#3965) and verifies the fix using `runtime.ResetSignalHandlers()`. - -## The Problem - -On Linux, WebKit installs signal handlers without the `SA_ONSTACK` flag, which prevents Go from recovering panics caused by nil pointer dereferences (SIGSEGV). Without the fix, the application crashes with: - -``` -signal 11 received but handler not on signal stack -fatal error: non-Go code set up signal handler without SA_ONSTACK flag -``` - -## The Solution - -Call `runtime.ResetSignalHandlers()` immediately before code that might panic: - -```go -import "github.com/wailsapp/wails/v2/pkg/runtime" - -go func() { - defer func() { - if err := recover(); err != nil { - log.Printf("Recovered: %v", err) - } - }() - runtime.ResetSignalHandlers() - // Code that might panic... -}() -``` - -## How to Reproduce - -### Prerequisites - -- Linux with WebKit2GTK 4.1 installed -- Go 1.21+ -- Wails CLI - -### Steps - -1. Build the example: - ```bash - cd v2/examples/panic-recovery-test - wails build -tags webkit2_41 - ``` - -2. Run the application: - ```bash - ./build/bin/panic-recovery-test - ``` - -3. Wait ~10 seconds (the app auto-calls `Greet` after 5s, then waits another 5s before the nil pointer dereference) - -### Expected Result (with fix) - -The panic is recovered and you see: -``` -------------------------------"invalid memory address or nil pointer dereference" -``` - -The application continues running. - -### Without the fix - -Comment out the `runtime.ResetSignalHandlers()` call in `app.go` and rebuild. The application will crash with a fatal signal 11 error. - -## Files - -- `app.go` - Contains the `Greet` function that demonstrates panic recovery -- `frontend/src/main.js` - Auto-calls `Greet` after 5 seconds to trigger the test - -## Related - -- Issue: https://github.com/wailsapp/wails/issues/3965 -- Original fix PR: https://github.com/wailsapp/wails/pull/2152 diff --git a/v2/examples/panic-recovery-test/app.go b/v2/examples/panic-recovery-test/app.go deleted file mode 100644 index ceb46e8d5..000000000 --- a/v2/examples/panic-recovery-test/app.go +++ /dev/null @@ -1,44 +0,0 @@ -package main - -import ( - "context" - "fmt" - "time" - - "github.com/wailsapp/wails/v2/pkg/runtime" -) - -// App struct -type App struct { - ctx context.Context -} - -// NewApp creates a new App application struct -func NewApp() *App { - return &App{} -} - -// startup is called when the app starts. The context is saved -// so we can call the runtime methods -func (a *App) startup(ctx context.Context) { - a.ctx = ctx -} - -// Greet returns a greeting for the given name -func (a *App) Greet(name string) string { - go func() { - defer func() { - if err := recover(); err != nil { - fmt.Printf("------------------------------%#v\n", err) - } - }() - time.Sleep(5 * time.Second) - // Fix signal handlers right before potential panic using the Wails runtime - runtime.ResetSignalHandlers() - // Nil pointer dereference - causes SIGSEGV - var t *time.Time - fmt.Println(t.Unix()) - }() - - return fmt.Sprintf("Hello %s, It's show time!", name) -} diff --git a/v2/examples/panic-recovery-test/frontend/index.html b/v2/examples/panic-recovery-test/frontend/index.html deleted file mode 100644 index d7aa4e942..000000000 --- a/v2/examples/panic-recovery-test/frontend/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - panic-test - - -
- - - diff --git a/v2/examples/panic-recovery-test/frontend/package.json b/v2/examples/panic-recovery-test/frontend/package.json deleted file mode 100644 index a1b6f8e1a..000000000 --- a/v2/examples/panic-recovery-test/frontend/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "frontend", - "private": true, - "version": "0.0.0", - "scripts": { - "dev": "vite", - "build": "vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^3.0.7" - } -} \ No newline at end of file diff --git a/v2/examples/panic-recovery-test/frontend/src/app.css b/v2/examples/panic-recovery-test/frontend/src/app.css deleted file mode 100644 index 59d06f692..000000000 --- a/v2/examples/panic-recovery-test/frontend/src/app.css +++ /dev/null @@ -1,54 +0,0 @@ -#logo { - display: block; - width: 50%; - height: 50%; - margin: auto; - padding: 10% 0 0; - background-position: center; - background-repeat: no-repeat; - background-size: 100% 100%; - background-origin: content-box; -} - -.result { - height: 20px; - line-height: 20px; - margin: 1.5rem auto; -} - -.input-box .btn { - width: 60px; - height: 30px; - line-height: 30px; - border-radius: 3px; - border: none; - margin: 0 0 0 20px; - padding: 0 8px; - cursor: pointer; -} - -.input-box .btn:hover { - background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%); - color: #333333; -} - -.input-box .input { - border: none; - border-radius: 3px; - outline: none; - height: 30px; - line-height: 30px; - padding: 0 10px; - background-color: rgba(240, 240, 240, 1); - -webkit-font-smoothing: antialiased; -} - -.input-box .input:hover { - border: none; - background-color: rgba(255, 255, 255, 1); -} - -.input-box .input:focus { - border: none; - background-color: rgba(255, 255, 255, 1); -} \ No newline at end of file diff --git a/v2/examples/panic-recovery-test/frontend/src/assets/fonts/OFL.txt b/v2/examples/panic-recovery-test/frontend/src/assets/fonts/OFL.txt deleted file mode 100644 index 9cac04ce8..000000000 --- a/v2/examples/panic-recovery-test/frontend/src/assets/fonts/OFL.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com), - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/v2/examples/panic-recovery-test/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 b/v2/examples/panic-recovery-test/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 deleted file mode 100644 index 2f9cc5964..000000000 Binary files a/v2/examples/panic-recovery-test/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 and /dev/null differ diff --git a/v2/examples/panic-recovery-test/frontend/src/assets/images/logo-universal.png b/v2/examples/panic-recovery-test/frontend/src/assets/images/logo-universal.png deleted file mode 100644 index d63303bfa..000000000 Binary files a/v2/examples/panic-recovery-test/frontend/src/assets/images/logo-universal.png and /dev/null differ diff --git a/v2/examples/panic-recovery-test/frontend/src/main.js b/v2/examples/panic-recovery-test/frontend/src/main.js deleted file mode 100644 index ea5e74fc6..000000000 --- a/v2/examples/panic-recovery-test/frontend/src/main.js +++ /dev/null @@ -1,55 +0,0 @@ -import './style.css'; -import './app.css'; - -import logo from './assets/images/logo-universal.png'; -import {Greet} from '../wailsjs/go/main/App'; - -document.querySelector('#app').innerHTML = ` - -
Please enter your name below 👇
-
- - -
- -`; -document.getElementById('logo').src = logo; - -let nameElement = document.getElementById("name"); -nameElement.focus(); -let resultElement = document.getElementById("result"); - -// Setup the greet function -window.greet = function () { - // Get name - let name = nameElement.value; - - // Check if the input is empty - if (name === "") return; - - // Call App.Greet(name) - try { - Greet(name) - .then((result) => { - // Update result with data back from App.Greet() - resultElement.innerText = result; - }) - .catch((err) => { - console.error(err); - }); - } catch (err) { - console.error(err); - } -}; - -// Auto-call Greet after 5 seconds to trigger the panic test -setTimeout(() => { - console.log("Auto-calling Greet to trigger panic test..."); - Greet("PanicTest") - .then((result) => { - resultElement.innerText = result + " (auto-called - panic will occur in 5s)"; - }) - .catch((err) => { - console.error("Error:", err); - }); -}, 5000); diff --git a/v2/examples/panic-recovery-test/frontend/src/style.css b/v2/examples/panic-recovery-test/frontend/src/style.css deleted file mode 100644 index 3940d6c63..000000000 --- a/v2/examples/panic-recovery-test/frontend/src/style.css +++ /dev/null @@ -1,26 +0,0 @@ -html { - background-color: rgba(27, 38, 54, 1); - text-align: center; - color: white; -} - -body { - margin: 0; - color: white; - font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", - "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", - sans-serif; -} - -@font-face { - font-family: "Nunito"; - font-style: normal; - font-weight: 400; - src: local(""), - url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2"); -} - -#app { - height: 100vh; - text-align: center; -} diff --git a/v2/examples/panic-recovery-test/frontend/wailsjs/go/main/App.d.ts b/v2/examples/panic-recovery-test/frontend/wailsjs/go/main/App.d.ts deleted file mode 100755 index 02a3bb988..000000000 --- a/v2/examples/panic-recovery-test/frontend/wailsjs/go/main/App.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Greet(arg1:string):Promise; diff --git a/v2/examples/panic-recovery-test/frontend/wailsjs/go/main/App.js b/v2/examples/panic-recovery-test/frontend/wailsjs/go/main/App.js deleted file mode 100755 index c71ae77cb..000000000 --- a/v2/examples/panic-recovery-test/frontend/wailsjs/go/main/App.js +++ /dev/null @@ -1,7 +0,0 @@ -// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Greet(arg1) { - return window['go']['main']['App']['Greet'](arg1); -} diff --git a/v2/examples/panic-recovery-test/frontend/wailsjs/runtime/package.json b/v2/examples/panic-recovery-test/frontend/wailsjs/runtime/package.json deleted file mode 100644 index 1e7c8a5d7..000000000 --- a/v2/examples/panic-recovery-test/frontend/wailsjs/runtime/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "@wailsapp/runtime", - "version": "2.0.0", - "description": "Wails Javascript runtime library", - "main": "runtime.js", - "types": "runtime.d.ts", - "scripts": { - }, - "repository": { - "type": "git", - "url": "git+https://github.com/wailsapp/wails.git" - }, - "keywords": [ - "Wails", - "Javascript", - "Go" - ], - "author": "Lea Anthony ", - "license": "MIT", - "bugs": { - "url": "https://github.com/wailsapp/wails/issues" - }, - "homepage": "https://github.com/wailsapp/wails#readme" -} diff --git a/v2/examples/panic-recovery-test/frontend/wailsjs/runtime/runtime.d.ts b/v2/examples/panic-recovery-test/frontend/wailsjs/runtime/runtime.d.ts deleted file mode 100644 index 4445dac21..000000000 --- a/v2/examples/panic-recovery-test/frontend/wailsjs/runtime/runtime.d.ts +++ /dev/null @@ -1,249 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export interface Position { - x: number; - y: number; -} - -export interface Size { - w: number; - h: number; -} - -export interface Screen { - isCurrent: boolean; - isPrimary: boolean; - width : number - height : number -} - -// Environment information such as platform, buildtype, ... -export interface EnvironmentInfo { - buildType: string; - platform: string; - arch: string; -} - -// [EventsEmit](https://wails.io/docs/reference/runtime/events#eventsemit) -// emits the given event. Optional data may be passed with the event. -// This will trigger any event listeners. -export function EventsEmit(eventName: string, ...data: any): void; - -// [EventsOn](https://wails.io/docs/reference/runtime/events#eventson) sets up a listener for the given event name. -export function EventsOn(eventName: string, callback: (...data: any) => void): () => void; - -// [EventsOnMultiple](https://wails.io/docs/reference/runtime/events#eventsonmultiple) -// sets up a listener for the given event name, but will only trigger a given number times. -export function EventsOnMultiple(eventName: string, callback: (...data: any) => void, maxCallbacks: number): () => void; - -// [EventsOnce](https://wails.io/docs/reference/runtime/events#eventsonce) -// sets up a listener for the given event name, but will only trigger once. -export function EventsOnce(eventName: string, callback: (...data: any) => void): () => void; - -// [EventsOff](https://wails.io/docs/reference/runtime/events#eventsoff) -// unregisters the listener for the given event name. -export function EventsOff(eventName: string, ...additionalEventNames: string[]): void; - -// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) -// unregisters all listeners. -export function EventsOffAll(): void; - -// [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) -// logs the given message as a raw message -export function LogPrint(message: string): void; - -// [LogTrace](https://wails.io/docs/reference/runtime/log#logtrace) -// logs the given message at the `trace` log level. -export function LogTrace(message: string): void; - -// [LogDebug](https://wails.io/docs/reference/runtime/log#logdebug) -// logs the given message at the `debug` log level. -export function LogDebug(message: string): void; - -// [LogError](https://wails.io/docs/reference/runtime/log#logerror) -// logs the given message at the `error` log level. -export function LogError(message: string): void; - -// [LogFatal](https://wails.io/docs/reference/runtime/log#logfatal) -// logs the given message at the `fatal` log level. -// The application will quit after calling this method. -export function LogFatal(message: string): void; - -// [LogInfo](https://wails.io/docs/reference/runtime/log#loginfo) -// logs the given message at the `info` log level. -export function LogInfo(message: string): void; - -// [LogWarning](https://wails.io/docs/reference/runtime/log#logwarning) -// logs the given message at the `warning` log level. -export function LogWarning(message: string): void; - -// [WindowReload](https://wails.io/docs/reference/runtime/window#windowreload) -// Forces a reload by the main application as well as connected browsers. -export function WindowReload(): void; - -// [WindowReloadApp](https://wails.io/docs/reference/runtime/window#windowreloadapp) -// Reloads the application frontend. -export function WindowReloadApp(): void; - -// [WindowSetAlwaysOnTop](https://wails.io/docs/reference/runtime/window#windowsetalwaysontop) -// Sets the window AlwaysOnTop or not on top. -export function WindowSetAlwaysOnTop(b: boolean): void; - -// [WindowSetSystemDefaultTheme](https://wails.io/docs/next/reference/runtime/window#windowsetsystemdefaulttheme) -// *Windows only* -// Sets window theme to system default (dark/light). -export function WindowSetSystemDefaultTheme(): void; - -// [WindowSetLightTheme](https://wails.io/docs/next/reference/runtime/window#windowsetlighttheme) -// *Windows only* -// Sets window to light theme. -export function WindowSetLightTheme(): void; - -// [WindowSetDarkTheme](https://wails.io/docs/next/reference/runtime/window#windowsetdarktheme) -// *Windows only* -// Sets window to dark theme. -export function WindowSetDarkTheme(): void; - -// [WindowCenter](https://wails.io/docs/reference/runtime/window#windowcenter) -// Centers the window on the monitor the window is currently on. -export function WindowCenter(): void; - -// [WindowSetTitle](https://wails.io/docs/reference/runtime/window#windowsettitle) -// Sets the text in the window title bar. -export function WindowSetTitle(title: string): void; - -// [WindowFullscreen](https://wails.io/docs/reference/runtime/window#windowfullscreen) -// Makes the window full screen. -export function WindowFullscreen(): void; - -// [WindowUnfullscreen](https://wails.io/docs/reference/runtime/window#windowunfullscreen) -// Restores the previous window dimensions and position prior to full screen. -export function WindowUnfullscreen(): void; - -// [WindowIsFullscreen](https://wails.io/docs/reference/runtime/window#windowisfullscreen) -// Returns the state of the window, i.e. whether the window is in full screen mode or not. -export function WindowIsFullscreen(): Promise; - -// [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize) -// Sets the width and height of the window. -export function WindowSetSize(width: number, height: number): void; - -// [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize) -// Gets the width and height of the window. -export function WindowGetSize(): Promise; - -// [WindowSetMaxSize](https://wails.io/docs/reference/runtime/window#windowsetmaxsize) -// Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMaxSize(width: number, height: number): void; - -// [WindowSetMinSize](https://wails.io/docs/reference/runtime/window#windowsetminsize) -// Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMinSize(width: number, height: number): void; - -// [WindowSetPosition](https://wails.io/docs/reference/runtime/window#windowsetposition) -// Sets the window position relative to the monitor the window is currently on. -export function WindowSetPosition(x: number, y: number): void; - -// [WindowGetPosition](https://wails.io/docs/reference/runtime/window#windowgetposition) -// Gets the window position relative to the monitor the window is currently on. -export function WindowGetPosition(): Promise; - -// [WindowHide](https://wails.io/docs/reference/runtime/window#windowhide) -// Hides the window. -export function WindowHide(): void; - -// [WindowShow](https://wails.io/docs/reference/runtime/window#windowshow) -// Shows the window, if it is currently hidden. -export function WindowShow(): void; - -// [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise) -// Maximises the window to fill the screen. -export function WindowMaximise(): void; - -// [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise) -// Toggles between Maximised and UnMaximised. -export function WindowToggleMaximise(): void; - -// [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise) -// Restores the window to the dimensions and position prior to maximising. -export function WindowUnmaximise(): void; - -// [WindowIsMaximised](https://wails.io/docs/reference/runtime/window#windowismaximised) -// Returns the state of the window, i.e. whether the window is maximised or not. -export function WindowIsMaximised(): Promise; - -// [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise) -// Minimises the window. -export function WindowMinimise(): void; - -// [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise) -// Restores the window to the dimensions and position prior to minimising. -export function WindowUnminimise(): void; - -// [WindowIsMinimised](https://wails.io/docs/reference/runtime/window#windowisminimised) -// Returns the state of the window, i.e. whether the window is minimised or not. -export function WindowIsMinimised(): Promise; - -// [WindowIsNormal](https://wails.io/docs/reference/runtime/window#windowisnormal) -// Returns the state of the window, i.e. whether the window is normal or not. -export function WindowIsNormal(): Promise; - -// [WindowSetBackgroundColour](https://wails.io/docs/reference/runtime/window#windowsetbackgroundcolour) -// Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels. -export function WindowSetBackgroundColour(R: number, G: number, B: number, A: number): void; - -// [ScreenGetAll](https://wails.io/docs/reference/runtime/window#screengetall) -// Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system. -export function ScreenGetAll(): Promise; - -// [BrowserOpenURL](https://wails.io/docs/reference/runtime/browser#browseropenurl) -// Opens the given URL in the system browser. -export function BrowserOpenURL(url: string): void; - -// [Environment](https://wails.io/docs/reference/runtime/intro#environment) -// Returns information about the environment -export function Environment(): Promise; - -// [Quit](https://wails.io/docs/reference/runtime/intro#quit) -// Quits the application. -export function Quit(): void; - -// [Hide](https://wails.io/docs/reference/runtime/intro#hide) -// Hides the application. -export function Hide(): void; - -// [Show](https://wails.io/docs/reference/runtime/intro#show) -// Shows the application. -export function Show(): void; - -// [ClipboardGetText](https://wails.io/docs/reference/runtime/clipboard#clipboardgettext) -// Returns the current text stored on clipboard -export function ClipboardGetText(): Promise; - -// [ClipboardSetText](https://wails.io/docs/reference/runtime/clipboard#clipboardsettext) -// Sets a text on the clipboard -export function ClipboardSetText(text: string): Promise; - -// [OnFileDrop](https://wails.io/docs/reference/runtime/draganddrop#onfiledrop) -// OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings. -export function OnFileDrop(callback: (x: number, y: number ,paths: string[]) => void, useDropTarget: boolean) :void - -// [OnFileDropOff](https://wails.io/docs/reference/runtime/draganddrop#dragandddropoff) -// OnFileDropOff removes the drag and drop listeners and handlers. -export function OnFileDropOff() :void - -// Check if the file path resolver is available -export function CanResolveFilePaths(): boolean; - -// Resolves file paths for an array of files -export function ResolveFilePaths(files: File[]): void \ No newline at end of file diff --git a/v2/examples/panic-recovery-test/frontend/wailsjs/runtime/runtime.js b/v2/examples/panic-recovery-test/frontend/wailsjs/runtime/runtime.js deleted file mode 100644 index 7cb89d750..000000000 --- a/v2/examples/panic-recovery-test/frontend/wailsjs/runtime/runtime.js +++ /dev/null @@ -1,242 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export function LogPrint(message) { - window.runtime.LogPrint(message); -} - -export function LogTrace(message) { - window.runtime.LogTrace(message); -} - -export function LogDebug(message) { - window.runtime.LogDebug(message); -} - -export function LogInfo(message) { - window.runtime.LogInfo(message); -} - -export function LogWarning(message) { - window.runtime.LogWarning(message); -} - -export function LogError(message) { - window.runtime.LogError(message); -} - -export function LogFatal(message) { - window.runtime.LogFatal(message); -} - -export function EventsOnMultiple(eventName, callback, maxCallbacks) { - return window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks); -} - -export function EventsOn(eventName, callback) { - return EventsOnMultiple(eventName, callback, -1); -} - -export function EventsOff(eventName, ...additionalEventNames) { - return window.runtime.EventsOff(eventName, ...additionalEventNames); -} - -export function EventsOffAll() { - return window.runtime.EventsOffAll(); -} - -export function EventsOnce(eventName, callback) { - return EventsOnMultiple(eventName, callback, 1); -} - -export function EventsEmit(eventName) { - let args = [eventName].slice.call(arguments); - return window.runtime.EventsEmit.apply(null, args); -} - -export function WindowReload() { - window.runtime.WindowReload(); -} - -export function WindowReloadApp() { - window.runtime.WindowReloadApp(); -} - -export function WindowSetAlwaysOnTop(b) { - window.runtime.WindowSetAlwaysOnTop(b); -} - -export function WindowSetSystemDefaultTheme() { - window.runtime.WindowSetSystemDefaultTheme(); -} - -export function WindowSetLightTheme() { - window.runtime.WindowSetLightTheme(); -} - -export function WindowSetDarkTheme() { - window.runtime.WindowSetDarkTheme(); -} - -export function WindowCenter() { - window.runtime.WindowCenter(); -} - -export function WindowSetTitle(title) { - window.runtime.WindowSetTitle(title); -} - -export function WindowFullscreen() { - window.runtime.WindowFullscreen(); -} - -export function WindowUnfullscreen() { - window.runtime.WindowUnfullscreen(); -} - -export function WindowIsFullscreen() { - return window.runtime.WindowIsFullscreen(); -} - -export function WindowGetSize() { - return window.runtime.WindowGetSize(); -} - -export function WindowSetSize(width, height) { - window.runtime.WindowSetSize(width, height); -} - -export function WindowSetMaxSize(width, height) { - window.runtime.WindowSetMaxSize(width, height); -} - -export function WindowSetMinSize(width, height) { - window.runtime.WindowSetMinSize(width, height); -} - -export function WindowSetPosition(x, y) { - window.runtime.WindowSetPosition(x, y); -} - -export function WindowGetPosition() { - return window.runtime.WindowGetPosition(); -} - -export function WindowHide() { - window.runtime.WindowHide(); -} - -export function WindowShow() { - window.runtime.WindowShow(); -} - -export function WindowMaximise() { - window.runtime.WindowMaximise(); -} - -export function WindowToggleMaximise() { - window.runtime.WindowToggleMaximise(); -} - -export function WindowUnmaximise() { - window.runtime.WindowUnmaximise(); -} - -export function WindowIsMaximised() { - return window.runtime.WindowIsMaximised(); -} - -export function WindowMinimise() { - window.runtime.WindowMinimise(); -} - -export function WindowUnminimise() { - window.runtime.WindowUnminimise(); -} - -export function WindowSetBackgroundColour(R, G, B, A) { - window.runtime.WindowSetBackgroundColour(R, G, B, A); -} - -export function ScreenGetAll() { - return window.runtime.ScreenGetAll(); -} - -export function WindowIsMinimised() { - return window.runtime.WindowIsMinimised(); -} - -export function WindowIsNormal() { - return window.runtime.WindowIsNormal(); -} - -export function BrowserOpenURL(url) { - window.runtime.BrowserOpenURL(url); -} - -export function Environment() { - return window.runtime.Environment(); -} - -export function Quit() { - window.runtime.Quit(); -} - -export function Hide() { - window.runtime.Hide(); -} - -export function Show() { - window.runtime.Show(); -} - -export function ClipboardGetText() { - return window.runtime.ClipboardGetText(); -} - -export function ClipboardSetText(text) { - return window.runtime.ClipboardSetText(text); -} - -/** - * Callback for OnFileDrop returns a slice of file path strings when a drop is finished. - * - * @export - * @callback OnFileDropCallback - * @param {number} x - x coordinate of the drop - * @param {number} y - y coordinate of the drop - * @param {string[]} paths - A list of file paths. - */ - -/** - * OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings. - * - * @export - * @param {OnFileDropCallback} callback - Callback for OnFileDrop returns a slice of file path strings when a drop is finished. - * @param {boolean} [useDropTarget=true] - Only call the callback when the drop finished on an element that has the drop target style. (--wails-drop-target) - */ -export function OnFileDrop(callback, useDropTarget) { - return window.runtime.OnFileDrop(callback, useDropTarget); -} - -/** - * OnFileDropOff removes the drag and drop listeners and handlers. - */ -export function OnFileDropOff() { - return window.runtime.OnFileDropOff(); -} - -export function CanResolveFilePaths() { - return window.runtime.CanResolveFilePaths(); -} - -export function ResolveFilePaths(files) { - return window.runtime.ResolveFilePaths(files); -} \ No newline at end of file diff --git a/v2/examples/panic-recovery-test/go.mod b/v2/examples/panic-recovery-test/go.mod deleted file mode 100644 index 026042cbf..000000000 --- a/v2/examples/panic-recovery-test/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module panic-recovery-test - -go 1.21 - -require github.com/wailsapp/wails/v2 v2.11.0 diff --git a/v2/examples/panic-recovery-test/main.go b/v2/examples/panic-recovery-test/main.go deleted file mode 100644 index f6a38e86c..000000000 --- a/v2/examples/panic-recovery-test/main.go +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import ( - "embed" - - "github.com/wailsapp/wails/v2" - "github.com/wailsapp/wails/v2/pkg/options" - "github.com/wailsapp/wails/v2/pkg/options/assetserver" -) - -//go:embed all:frontend/dist -var assets embed.FS - -func main() { - // Create an instance of the app structure - app := NewApp() - - // Create application with options - err := wails.Run(&options.App{ - Title: "panic-test", - Width: 1024, - Height: 768, - AssetServer: &assetserver.Options{ - Assets: assets, - }, - BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, - OnStartup: app.startup, - Bind: []interface{}{ - app, - }, - }) - - if err != nil { - println("Error:", err.Error()) - } -} diff --git a/v2/examples/panic-recovery-test/wails.json b/v2/examples/panic-recovery-test/wails.json deleted file mode 100644 index 56770f091..000000000 --- a/v2/examples/panic-recovery-test/wails.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "$schema": "https://wails.io/schemas/config.v2.json", - "name": "panic-recovery-test", - "outputfilename": "panic-recovery-test", - "frontend:install": "npm install", - "frontend:build": "npm run build", - "frontend:dev:watcher": "npm run dev", - "frontend:dev:serverUrl": "auto", - "author": { - "name": "Lea Anthony", - "email": "lea.anthony@gmail.com" - } -} diff --git a/v2/go.mod b/v2/go.mod index 2eb753ee2..d0058db4b 100644 --- a/v2/go.mod +++ b/v2/go.mod @@ -1,112 +1,82 @@ module github.com/wailsapp/wails/v2 -go 1.22.0 +go 1.17 require ( github.com/Masterminds/semver v1.5.0 - github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d - github.com/bep/debounce v1.2.1 - github.com/bitfield/script v0.24.0 - github.com/charmbracelet/glamour v0.8.0 - github.com/flytam/filenamify v1.2.0 - github.com/fsnotify/fsnotify v1.9.0 - github.com/go-git/go-git/v5 v5.13.2 - github.com/go-ole/go-ole v1.3.0 - github.com/godbus/dbus/v5 v5.1.0 - github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 - github.com/google/uuid v1.6.0 - github.com/gorilla/websocket v1.5.3 + github.com/fatih/structtag v1.2.0 + github.com/flytam/filenamify v1.0.0 + github.com/fsnotify/fsnotify v1.4.9 + github.com/gabriel-vasile/mimetype v1.3.1 + github.com/go-git/go-billy/v5 v5.2.0 // indirect + github.com/go-git/go-git/v5 v5.3.0 + github.com/gofiber/fiber/v2 v2.17.0 + github.com/gofiber/websocket/v2 v2.0.8 + github.com/golang/protobuf v1.5.2 // indirect + github.com/google/uuid v1.1.2 // indirect + github.com/gorilla/websocket v1.4.1 + github.com/imdario/mergo v0.3.12 github.com/jackmordaunt/icns v1.0.0 - github.com/jaypipes/ghw v0.21.3 - github.com/labstack/echo/v4 v4.13.3 - github.com/labstack/gommon v0.4.2 - github.com/leaanthony/clir v1.3.0 + github.com/leaanthony/clir v1.0.4 github.com/leaanthony/debme v1.2.1 - github.com/leaanthony/go-ansi-parser v1.6.1 - github.com/leaanthony/gosod v1.0.4 - github.com/leaanthony/slicer v1.6.0 - github.com/leaanthony/u v1.1.1 + github.com/leaanthony/go-ansi-parser v1.0.1 + github.com/leaanthony/go-common-file-dialog v1.0.3 + github.com/leaanthony/go-webview2 v0.0.0-20211022194343-1e4c8d4226f3 + github.com/leaanthony/gosod v1.0.3 + github.com/leaanthony/idgen v1.0.0 + github.com/leaanthony/slicer v1.5.0 + github.com/leaanthony/typescriptify-golang-structs v0.1.7 + github.com/leaanthony/webview2runtime v1.1.0 + github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 github.com/leaanthony/winicon v1.0.0 - github.com/matryer/is v1.4.1 - github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c + github.com/matryer/is v1.4.0 + github.com/olekukonko/tablewriter v0.0.4 + github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 github.com/pkg/errors v0.9.1 - github.com/pterm/pterm v0.12.80 - github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 - github.com/samber/lo v1.49.1 - github.com/stretchr/testify v1.10.0 - github.com/tc-hib/winres v0.3.1 - github.com/tidwall/sjson v1.2.5 - github.com/tkrajina/go-reflector v0.5.8 - github.com/wailsapp/go-webview2 v1.0.22 - github.com/wailsapp/mimetype v1.4.1 + github.com/tc-hib/winres v0.1.5 + github.com/tdewolff/minify v2.3.6+incompatible + github.com/tdewolff/parse v2.3.4+incompatible // indirect + github.com/tdewolff/test v1.0.6 // indirect + github.com/tidwall/sjson v1.1.7 github.com/wzshiming/ctc v1.2.3 - golang.org/x/mod v0.23.0 - golang.org/x/net v0.35.0 - golang.org/x/sys v0.30.0 - golang.org/x/tools v0.30.0 + github.com/xyproto/xpm v1.2.1 + github.com/ztrue/tracerr v0.3.0 + golang.org/x/mod v0.4.1 + golang.org/x/net v0.0.0-20210510120150-4163338589ed + golang.org/x/sys v0.0.0-20211020174200-9d6173849985 + golang.org/x/tools v0.1.0 + nhooyr.io/websocket v1.8.6 ) require ( - atomicgo.dev/cursor v0.2.0 // indirect - atomicgo.dev/keyboard v0.2.9 // indirect - atomicgo.dev/schedule v0.1.0 // indirect - dario.cat/mergo v1.0.0 // indirect - github.com/Microsoft/go-winio v0.6.1 // indirect - github.com/ProtonMail/go-crypto v1.1.5 // indirect - github.com/alecthomas/chroma/v2 v2.14.0 // indirect - github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect - github.com/aymerick/douceur v0.2.0 // indirect - github.com/charmbracelet/lipgloss v0.12.1 // indirect - github.com/charmbracelet/x/ansi v0.1.4 // indirect - github.com/cloudflare/circl v1.3.7 // indirect - github.com/containerd/console v1.0.3 // indirect - github.com/cyphar/filepath-securejoin v0.3.6 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dlclark/regexp2 v1.11.0 // indirect - github.com/emirpasic/gods v1.18.1 // indirect - github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect - github.com/go-git/go-billy/v5 v5.6.2 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/gookit/color v1.5.4 // indirect - github.com/gorilla/css v1.0.1 // indirect - github.com/itchyny/gojq v0.12.13 // indirect - github.com/itchyny/timefmt-go v0.1.5 // indirect - github.com/jaypipes/pcidb v1.1.1 // indirect + github.com/Microsoft/go-winio v0.4.16 // indirect + github.com/andybalholm/brotli v1.0.2 // indirect + github.com/emirpasic/gods v1.12.0 // indirect + github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect + github.com/go-git/gcfg v1.5.0 // indirect + github.com/go-ole/go-ole v1.2.5 // indirect + github.com/google/go-cmp v0.5.5 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect - github.com/kevinburke/ssh_config v1.2.0 // indirect - github.com/lithammer/fuzzysearch v1.1.8 // indirect - github.com/lucasb-eyer/go-colorful v1.2.0 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.16 // indirect - github.com/microcosm-cc/bluemonday v1.0.27 // indirect - github.com/muesli/reflow v0.3.0 // indirect - github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a // indirect + github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect + github.com/klauspost/compress v1.12.2 // indirect + github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e // indirect + github.com/mattn/go-runewidth v0.0.7 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect - github.com/pjbgf/sha1cd v0.3.2 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/rivo/uniseg v0.4.7 // indirect - github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect - github.com/skeema/knownhosts v1.3.0 // indirect - github.com/tidwall/gjson v1.14.2 // indirect - github.com/tidwall/match v1.1.1 // indirect - github.com/tidwall/pretty v1.2.0 // indirect + github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect + github.com/sergi/go-diff v1.1.0 // indirect + github.com/tidwall/gjson v1.8.0 // indirect + github.com/tidwall/match v1.0.3 // indirect + github.com/tidwall/pretty v1.1.0 // indirect + github.com/tkrajina/go-reflector v0.5.5 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasttemplate v1.2.2 // indirect + github.com/valyala/fasthttp v1.28.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect github.com/wzshiming/winseq v0.0.0-20200112104235-db357dc107ae // indirect - github.com/xanzy/ssh-agent v0.3.3 // indirect - github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect - github.com/yuin/goldmark v1.7.4 // indirect - github.com/yuin/goldmark-emoji v1.0.3 // indirect - github.com/yusufpapurcu/wmi v1.2.4 // indirect - golang.org/x/crypto v0.33.0 // indirect - golang.org/x/image v0.12.0 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/term v0.29.0 // indirect - golang.org/x/text v0.22.0 // indirect + github.com/xanzy/ssh-agent v0.3.0 // indirect + golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a // indirect + golang.org/x/image v0.0.0-20201208152932-35266b937fa6 // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect - howett.net/plist v1.0.2-0.20250314012144-ee69052608d9 // indirect - mvdan.cc/sh/v3 v3.7.0 // indirect ) diff --git a/v2/go.sum b/v2/go.sum index f6df3507e..592545177 100644 --- a/v2/go.sum +++ b/v2/go.sum @@ -1,351 +1,297 @@ -atomicgo.dev/assert v0.0.2 h1:FiKeMiZSgRrZsPo9qn/7vmr7mCsh5SZyXY4YGYiYwrg= -atomicgo.dev/assert v0.0.2/go.mod h1:ut4NcI3QDdJtlmAxQULOmA13Gz6e2DWbSAS8RUOmNYQ= -atomicgo.dev/cursor v0.2.0 h1:H6XN5alUJ52FZZUkI7AlJbUc1aW38GWZalpYRPpoPOw= -atomicgo.dev/cursor v0.2.0/go.mod h1:Lr4ZJB3U7DfPPOkbH7/6TOtJ4vFGHlgj1nc+n900IpU= -atomicgo.dev/keyboard v0.2.9 h1:tOsIid3nlPLZ3lwgG8KZMp/SFmr7P0ssEN5JUsm78K8= -atomicgo.dev/keyboard v0.2.9/go.mod h1:BC4w9g00XkxH/f1HXhW2sXmJFOCWbKn9xrOunSFtExQ= -atomicgo.dev/schedule v0.1.0 h1:nTthAbhZS5YZmgYbb2+DH8uQIZcTlIrd4eYr3UQxEjs= -atomicgo.dev/schedule v0.1.0/go.mod h1:xeUa3oAkiuHYh8bKiQBRojqAMq3PXXbJujjb0hw8pEU= -dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= -dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= -github.com/MarvinJWendt/testza v0.1.0/go.mod h1:7AxNvlfeHP7Z/hDQ5JtE3OKYT3XFUeLCDE2DQninSqs= -github.com/MarvinJWendt/testza v0.2.1/go.mod h1:God7bhG8n6uQxwdScay+gjm9/LnO4D3kkcZX4hv9Rp8= -github.com/MarvinJWendt/testza v0.2.8/go.mod h1:nwIcjmr0Zz+Rcwfh3/4UhBp7ePKVhuBExvZqnKYWlII= -github.com/MarvinJWendt/testza v0.2.10/go.mod h1:pd+VWsoGUiFtq+hRKSU1Bktnn+DMCSrDrXDpX2bG66k= -github.com/MarvinJWendt/testza v0.2.12/go.mod h1:JOIegYyV7rX+7VZ9r77L/eH6CfJHHzXjB69adAhzZkI= -github.com/MarvinJWendt/testza v0.3.0/go.mod h1:eFcL4I0idjtIx8P9C6KkAuLgATNKpX4/2oUqKc6bF2c= -github.com/MarvinJWendt/testza v0.4.2/go.mod h1:mSdhXiKH8sg/gQehJ63bINcCKp7RtYewEjXsvsVUPbE= -github.com/MarvinJWendt/testza v0.5.2 h1:53KDo64C1z/h/d/stCYCPY69bt/OSwjq5KpFNwi+zB4= -github.com/MarvinJWendt/testza v0.5.2/go.mod h1:xu53QFE5sCdjtMCKk8YMQ2MnymimEctc4n3EjyIYvEY= github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/ProtonMail/go-crypto v1.1.5 h1:eoAQfK2dwL+tFSFpr7TbOaPNUbPiJj4fLYwwGE1FQO4= -github.com/ProtonMail/go-crypto v1.1.5/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= -github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= -github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= -github.com/alecthomas/assert/v2 v2.7.0 h1:QtqSACNS3tF7oasA8CU6A6sXZSBDqnm7RfpLl9bZqbE= -github.com/alecthomas/assert/v2 v2.7.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= -github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E= -github.com/alecthomas/chroma/v2 v2.14.0/go.mod h1:QolEbTfmUHIMVpBqxeDnNBj2uoeI4EbYP4i6n68SG4I= -github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= -github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= -github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= -github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk= +github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= +github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= +github.com/andybalholm/brotli v1.0.2 h1:JKnhI/XQ75uFBTiuzXpzFrUriDPiZjlOSzh6wXogP0E= +github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk= -github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= -github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= -github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8= -github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA= -github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= -github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= -github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY= -github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0= -github.com/bitfield/script v0.24.0 h1:ic0Tbx+2AgRtkGGIcUyr+Un60vu4WXvqFrCSumf+T7M= -github.com/bitfield/script v0.24.0/go.mod h1:fv+6x4OzVsRs6qAlc7wiGq8fq1b5orhtQdtW0dwjUHI= -github.com/charmbracelet/glamour v0.8.0 h1:tPrjL3aRcQbn++7t18wOpgLyl8wrOHUEDS7IZ68QtZs= -github.com/charmbracelet/glamour v0.8.0/go.mod h1:ViRgmKkf3u5S7uakt2czJ272WSg2ZenlYEZXT2x7Bjw= -github.com/charmbracelet/lipgloss v0.12.1 h1:/gmzszl+pedQpjCOH+wFkZr/N90Snz40J/NR7A0zQcs= -github.com/charmbracelet/lipgloss v0.12.1/go.mod h1:V2CiwIuhx9S1S1ZlADfOj9HmxeMAORuz5izHb0zGbB8= -github.com/charmbracelet/x/ansi v0.1.4 h1:IEU3D6+dWwPSgZ6HBH+v6oUuZ/nVawMiWj5831KfiLM= -github.com/charmbracelet/x/ansi v0.1.4/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= -github.com/charmbracelet/x/exp/golden v0.0.0-20240715153702-9ba8adf781c4 h1:6KzMkQeAF56rggw2NZu1L+TH7j9+DM1/2Kmh7KUxg1I= -github.com/charmbracelet/x/exp/golden v0.0.0-20240715153702-9ba8adf781c4/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= -github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= -github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= -github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= -github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= -github.com/cyphar/filepath-securejoin v0.3.6 h1:4d9N5ykBnSp5Xn2JkhocYDkOpURL/18CYMpo6xB9uWM= -github.com/cyphar/filepath-securejoin v0.3.6/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= -github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/elazarl/goproxy v1.4.0 h1:4GyuSbFa+s26+3rmYNSuUVsx+HgPrV1bk1jXI0l9wjM= -github.com/elazarl/goproxy v1.4.0/go.mod h1:X/5W/t+gzDyLfHW4DrMdpjqYjpXsURlBt9lpBDxZZZQ= -github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= -github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= -github.com/flytam/filenamify v1.2.0 h1:7RiSqXYR4cJftDQ5NuvljKMfd/ubKnW/j9C6iekChgI= -github.com/flytam/filenamify v1.2.0/go.mod h1:Dzf9kVycwcsBlr2ATg6uxjqiFgKGH+5SKFuhdeP5zu8= -github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA= -github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= -github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= -github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= -github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= -github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= -github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= -github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM= -github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU= -github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= -github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= -github.com/go-git/go-git/v5 v5.13.2 h1:7O7xvsK7K+rZPKW6AQR1YyNhfywkv7B8/FsP3ki6Zv0= -github.com/go-git/go-git/v5 v5.13.2/go.mod h1:hWdW5P4YZRjmpGHwRH2v3zkWcNl6HeXaXQEMGb3NJ9A= -github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= -github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= -github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= -github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ= -github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo= -github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0= -github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w= -github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8= -github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0= -github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= -github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= -github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= -github.com/itchyny/gojq v0.12.13 h1:IxyYlHYIlspQHHTE0f3cJF0NKDMfajxViuhBLnHd/QU= -github.com/itchyny/gojq v0.12.13/go.mod h1:JzwzAqenfhrPUuwbmEz3nu3JQmFLlQTQMUcOdnu/Sf4= -github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE= -github.com/itchyny/timefmt-go v0.1.5/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8= +github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= +github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab h1:9e2joQGp642wHGFP5m86SDptAavrdGBe8/x9DGEEAaI= +github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab/go.mod h1:smsv/h4PBEBaU0XDTY5UwJTpZv69fQ0FfcLJr21mA6Y= +github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= +github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/flytam/filenamify v1.0.0 h1:ewx6BY2dj7U6h2zGPJmt33q/BjkSf/YsY/woQvnUNIs= +github.com/flytam/filenamify v1.0.0/go.mod h1:Dzf9kVycwcsBlr2ATg6uxjqiFgKGH+5SKFuhdeP5zu8= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/gabriel-vasile/mimetype v1.3.1 h1:qevA6c2MtE1RorlScnixeG0VA1H4xrXyhyX3oWBynNQ= +github.com/gabriel-vasile/mimetype v1.3.1/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= +github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= +github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= +github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= +github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= +github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-billy/v5 v5.1.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-billy/v5 v5.2.0 h1:GcoouCP9J+5slw2uXAocL70z8ml4A8B/H8nEPt6CLPk= +github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12 h1:PbKy9zOy4aAKrJ5pibIRpVO2BXnK1Tlcg+caKI7Ox5M= +github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= +github.com/go-git/go-git/v5 v5.3.0 h1:8WKMtJR2j8RntEXR/uvTKagfEt4GYlwQ7mntE4+0GWc= +github.com/go-git/go-git/v5 v5.3.0/go.mod h1:xdX4bWJ48aOrdhnl2XqHYstHbbp6+LFS4r4X+lNVprw= +github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= +github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY= +github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= +github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= +github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/gofiber/fiber/v2 v2.17.0 h1:qP3PkGUbBB0i9iQh5E057XI1yO5CZigUxZhyUFYAFoM= +github.com/gofiber/fiber/v2 v2.17.0/go.mod h1:iftruuHGkRYGEXVISmdD7HTYWyfS2Bh+Dkfq4n/1Owg= +github.com/gofiber/websocket/v2 v2.0.8 h1:Hb4y6IxYZVMO0segROODXJiXVgVD3a6i7wnfot8kM6k= +github.com/gofiber/websocket/v2 v2.0.8/go.mod h1:fv8HSGQX09sauNv9g5Xq8GeGAaahLFYQKKb4ZdT0x2w= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/jackmordaunt/icns v1.0.0 h1:RYSxplerf/l/DUd09AHtITwckkv/mqjVv4DjYdPmAMQ= github.com/jackmordaunt/icns v1.0.0/go.mod h1:7TTQVEuGzVVfOPPlLNHJIkzA6CoV7aH1Dv9dW351oOo= -github.com/jaypipes/ghw v0.21.3 h1:v5mUHM+RN854Vqmk49Uh213jyUA4+8uqaRajlYESsh8= -github.com/jaypipes/ghw v0.21.3/go.mod h1:GPrvwbtPoxYUenr74+nAnWbardIZq600vJDD5HnPsPE= -github.com/jaypipes/pcidb v1.1.1 h1:QmPhpsbmmnCwZmHeYAATxEaoRuiMAJusKYkUncMC0ro= -github.com/jaypipes/pcidb v1.1.1/go.mod h1:x27LT2krrUgjf875KxQXKB0Ha/YXLdZRVmw6hH0G7g8= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs= github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck= github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= -github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= -github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= -github.com/klauspost/cpuid/v2 v2.2.3 h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y70BU= -github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= +github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck= +github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.12.2 h1:2KCfW3I9M7nSc5wOqXAlW2v2U6v+w6cbjvbfp+OykW8= +github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/labstack/echo/v4 v4.13.3 h1:pwhpCPrTl5qry5HRdM5FwdXnhXSLSY+WE+YQSeCaafY= -github.com/labstack/echo/v4 v4.13.3/go.mod h1:o90YNEeQWjDozo584l7AwhJMHN0bOC4tAfg+Xox9q5g= -github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= -github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= +github.com/leaanthony/clir v1.0.4 h1:Dov2y9zWJmZr7CjaCe86lKa4b5CSxskGAt2yBkoDyiU= github.com/leaanthony/clir v1.0.4/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0= -github.com/leaanthony/clir v1.3.0 h1:L9nPDWrmc/qU9UWZZvRaFajWYuO0np9V5p+5gxyYno0= -github.com/leaanthony/clir v1.3.0/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0= github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc= github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA= -github.com/leaanthony/go-ansi-parser v1.6.1 h1:xd8bzARK3dErqkPFtoF9F3/HgN8UQk0ed1YDKpEz01A= -github.com/leaanthony/go-ansi-parser v1.6.1/go.mod h1:+vva/2y4alzVmmIEpk9QDhA7vLC5zKDTRwfZGOp3IWU= -github.com/leaanthony/gosod v1.0.4 h1:YLAbVyd591MRffDgxUOU1NwLhT9T1/YiwjKZpkNFeaI= -github.com/leaanthony/gosod v1.0.4/go.mod h1:GKuIL0zzPj3O1SdWQOdgURSuhkF+Urizzxh26t9f1cw= +github.com/leaanthony/go-ansi-parser v1.0.1 h1:97v6c5kYppVsbScf4r/VZdXyQ21KQIfeQOk2DgKxGG4= +github.com/leaanthony/go-ansi-parser v1.0.1/go.mod h1:7arTzgVI47srICYhvgUV4CGd063sGEeoSlych5yeSPM= +github.com/leaanthony/go-common-file-dialog v1.0.3 h1:O0uGjKnWtdEADGrkg+TyAAbZylykMwwx/MNEXn9fp+Y= +github.com/leaanthony/go-common-file-dialog v1.0.3/go.mod h1:TGhEc9eSJgRsupZ+iH1ZgAOnEo9zp05cRH2j08RPrF0= +github.com/leaanthony/go-webview2 v0.0.0-20211022194343-1e4c8d4226f3 h1:qhgrg3MhFRAIvtaqoqI+SrT+0wDYpxDMp9e3cvcxMpI= +github.com/leaanthony/go-webview2 v0.0.0-20211022194343-1e4c8d4226f3/go.mod h1:lS5ds4bruPk9d7lzdF/OH31Z0YCerI6MmHNFGsWoUnM= +github.com/leaanthony/gosod v1.0.3 h1:Fnt+/B6NjQOVuCWOKYRREZnjGyvg+mEhd1nkkA04aTQ= +github.com/leaanthony/gosod v1.0.3/go.mod h1:BJ2J+oHsQIyIQpnLPjnqFGTMnOZXDbvWtRCSG7jGxs4= +github.com/leaanthony/idgen v1.0.0 h1:IZreR+JGEzFV4yeVuBZA25gM0keUoFy+RDUldncQ+Jw= +github.com/leaanthony/idgen v1.0.0/go.mod h1:4nBZnt8ml/f/ic/EVQuLxuj817RccT2fyrUaZFxrcVA= +github.com/leaanthony/slicer v1.5.0 h1:aHYTN8xbCCLxJmkNKiLB6tgcMARl4eWmH9/F+S/0HtY= github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY= -github.com/leaanthony/slicer v1.6.0 h1:1RFP5uiPJvT93TAHi+ipd3NACobkW53yUiBqZheE/Js= -github.com/leaanthony/slicer v1.6.0/go.mod h1:o/Iz29g7LN0GqH3aMjWAe90381nyZlDNquK+mtH2Fj8= -github.com/leaanthony/u v1.1.1 h1:TUFjwDGlNX+WuwVEzDqQwC2lOv0P4uhTQw7CMFdiK7M= -github.com/leaanthony/u v1.1.1/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQcaRfI= +github.com/leaanthony/typescriptify-golang-structs v0.1.7 h1:yoznzWzyxkO/iWdlpq+aPcuJ5Y/hpjq/lmgMFmpjwl0= +github.com/leaanthony/typescriptify-golang-structs v0.1.7/go.mod h1:cWtOkiVhMF77e6phAXUcfNwYmMwCJ67Sij24lfvi9Js= +github.com/leaanthony/webview2runtime v1.1.0 h1:N0pv55ift8XtqozIp4PNOtRCJ/Qdd/qzx80lUpalS4c= +github.com/leaanthony/webview2runtime v1.1.0/go.mod h1:hH9GnWCve3DYzNaPOcPbhHQ7fodXR1QJNsnwixid4Tk= +github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 h1:5iOd93PZbpH4Iir8QkC4coFD+zEQEZSIRcjwjTFZkr0= +github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18/go.mod h1:KEbMsKoznsebyGHwLk5LqkFOxL5uXSRdvpP4+avmAMs= github.com/leaanthony/winicon v1.0.0 h1:ZNt5U5dY71oEoKZ97UVwJRT4e+5xo5o/ieKuHuk8NqQ= github.com/leaanthony/winicon v1.0.0/go.mod h1:en5xhijl92aphrJdmRPlh4NI1L6wq3gEm0LpXAPghjU= -github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4= -github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4= -github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= -github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e h1:9MlwzLdW7QSDrhDjFlsEYmxpFyIoXmYRon3dt0io31k= +github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= +github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= -github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ= -github.com/matryer/is v1.4.1/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= -github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= -github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= -github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA= -github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= -github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= -github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a h1:2MaM6YC3mGu54x+RKAA6JiFFHlHDY1UbkxqppT7wYOg= -github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a/go.mod h1:hxSnBBYLK21Vtq/PHd0S2FYCxBXzBua8ov5s1RobyRQ= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54= +github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= -github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= -github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= -github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4= -github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A= -github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= -github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8= +github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= +github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 h1:acNfDZXmm28D2Yg/c3ALnZStzNaZMSagpbr96vY6Zjc= +github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pterm/pterm v0.12.27/go.mod h1:PhQ89w4i95rhgE+xedAoqous6K9X+r6aSOI2eFF7DZI= -github.com/pterm/pterm v0.12.29/go.mod h1:WI3qxgvoQFFGKGjGnJR849gU0TsEOvKn5Q8LlY1U7lg= -github.com/pterm/pterm v0.12.30/go.mod h1:MOqLIyMOgmTDz9yorcYbcw+HsgoZo3BQfg2wtl3HEFE= -github.com/pterm/pterm v0.12.31/go.mod h1:32ZAWZVXD7ZfG0s8qqHXePte42kdz8ECtRyEejaWgXU= -github.com/pterm/pterm v0.12.33/go.mod h1:x+h2uL+n7CP/rel9+bImHD5lF3nM9vJj80k9ybiiTTE= -github.com/pterm/pterm v0.12.36/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5bUw8T8= -github.com/pterm/pterm v0.12.40/go.mod h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s= -github.com/pterm/pterm v0.12.80 h1:mM55B+GnKUnLMUSqhdINe4s6tOuVQIetQ3my8JGyAIg= -github.com/pterm/pterm v0.12.80/go.mod h1:c6DeF9bSnOSeFPZlfs4ZRAFcf5SCoTwvwQ5xaKGQlHo= -github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= -github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 h1:OkMGxebDjyw0ULyrTYWeN0UNCCkmCWfjPnIA2W6oviI= -github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06/go.mod h1:+ePHsJ1keEjQtpvf9HHw0f4ZeJ0TLRsxhunSI2hYJSs= -github.com/samber/lo v1.49.1 h1:4BIFyVfuQSEpluc7Fua+j1NolZHiEHEpaSEKdsH0tew= -github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o= -github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= -github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY= -github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M= +github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f h1:PgA+Olipyj258EIEYnpFFONrrCcAIWNUNoFhUfMqAGY= +github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f/go.mod h1:lHhJedqxCoHN+zMtwGNTXWmF0u9Jt363FYRhV6g0CdY= +github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/tc-hib/winres v0.3.1 h1:CwRjEGrKdbi5CvZ4ID+iyVhgyfatxFoizjPhzez9Io4= -github.com/tc-hib/winres v0.3.1/go.mod h1:C/JaNhH3KBvhNKVbvdlDWkbMDO9H4fKKDaN7/07SSuk= -github.com/tidwall/gjson v1.14.2 h1:6BBkirS0rAHjumnjHF6qgy5d2YAJ1TLIaFE2lzfOLqo= -github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= -github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= -github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= -github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= -github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= -github.com/tkrajina/go-reflector v0.5.8 h1:yPADHrwmUbMq4RGEyaOUpz2H90sRsETNVpjzo3DLVQQ= -github.com/tkrajina/go-reflector v0.5.8/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4= +github.com/tc-hib/winres v0.1.5 h1:2dA5yfjdoEA3UyRaOC92HNMt3jap66pLzoW4MjpC/0M= +github.com/tc-hib/winres v0.1.5/go.mod h1:pe6dOR40VOrGz8PkzreVKNvEKnlE8t4yR8A8naL+t7A= +github.com/tdewolff/minify v2.3.6+incompatible h1:2hw5/9ZvxhWLvBUnHE06gElGYz+Jv9R4Eys0XUzItYo= +github.com/tdewolff/minify v2.3.6+incompatible/go.mod h1:9Ov578KJUmAWpS6NeZwRZyT56Uf6o3Mcz9CEsg8USYs= +github.com/tdewolff/parse v2.3.4+incompatible h1:x05/cnGwIMf4ceLuDMBOdQ1qGniMoxpP46ghf0Qzh38= +github.com/tdewolff/parse v2.3.4+incompatible/go.mod h1:8oBwCsVmUkgHO8M5iCzSIDtpzXOT0WXX9cWhz+bIzJQ= +github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4= +github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= +github.com/tidwall/gjson v1.8.0 h1:Qt+orfosKn0rbNTZqHYDqBrmm3UDA4KRkv70fDzG+PQ= +github.com/tidwall/gjson v1.8.0/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk= +github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE= +github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.1.0 h1:K3hMW5epkdAVwibsQEfR/7Zj0Qgt4DxtNumTq/VloO8= +github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/sjson v1.1.7 h1:sgVPwu/yygHJ2m1pJDLgGM/h+1F5odx5Q9ljG3imRm8= +github.com/tidwall/sjson v1.1.7/go.mod h1:w/yG+ezBeTdUxiKs5NcPicO9diP38nk96QBAbIIGeFs= +github.com/tkrajina/go-reflector v0.5.5 h1:gwoQFNye30Kk7NrExj8zm3zFtrGPqOkzFMLuQZg1DtQ= +github.com/tkrajina/go-reflector v0.5.5/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4= +github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= -github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -github.com/wailsapp/go-webview2 v1.0.22 h1:YT61F5lj+GGaat5OB96Aa3b4QA+mybD0Ggq6NZijQ58= -github.com/wailsapp/go-webview2 v1.0.22/go.mod h1:qJmWAmAmaniuKGZPWwne+uor3AHMB5PFhqiK0Bbj8kc= -github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs= -github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o= +github.com/valyala/fasthttp v1.9.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= +github.com/valyala/fasthttp v1.26.0/go.mod h1:cmWIqlu99AO/RKcp1HWaViTqc57FswJOfYYdPJBl8BA= +github.com/valyala/fasthttp v1.28.0 h1:ruVmTmZaBR5i67NqnjvvH5gEv0zwHfWtbjoyW98iho4= +github.com/valyala/fasthttp v1.28.0/go.mod h1:cmWIqlu99AO/RKcp1HWaViTqc57FswJOfYYdPJBl8BA= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= +github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/wzshiming/ctc v1.2.3 h1:q+hW3IQNsjIlOFBTGZZZeIXTElFM4grF4spW/errh/c= github.com/wzshiming/ctc v1.2.3/go.mod h1:2tVAtIY7SUyraSk0JxvwmONNPFL4ARavPuEsg5+KA28= github.com/wzshiming/winseq v0.0.0-20200112104235-db357dc107ae h1:tpXvBXC3hpQBDCc9OojJZCQMVRAbT3TTdUMP8WguXkY= github.com/wzshiming/winseq v0.0.0-20200112104235-db357dc107ae/go.mod h1:VTAq37rkGeV+WOybvZwjXiJOicICdpLCN8ifpISjK20= -github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= -github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= -github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= -github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= -github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= -github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -github.com/yuin/goldmark-emoji v1.0.3 h1:aLRkLHOuBR2czCY4R8olwMjID+tENfhyFDMCRhbIQY4= -github.com/yuin/goldmark-emoji v1.0.3/go.mod h1:tTkZEbwu5wkPmgTcitqddVxY9osFZiavD+r4AzQrh1U= -github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= -github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI= +github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= +github.com/xyproto/xpm v1.2.1 h1:trdvGjjWBsOOKzBBUPT6JvaIQM3acJEEYfbxN7M96wg= +github.com/xyproto/xpm v1.2.1/go.mod h1:cMnesLsD0PBXLgjDfTDEaKr8XyTFsnP1QycSqRw7BiY= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/ztrue/tracerr v0.3.0 h1:lDi6EgEYhPYPnKcjsYzmWw4EkFEoA/gfe+I9Y5f+h6Y= +github.com/ztrue/tracerr v0.3.0/go.mod h1:qEalzze4VN9O8tnhBXScfCrmoJo10o8TN5ciKjm6Mww= +golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= -golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.12.0 h1:w13vZbU4o5rKOFFR8y7M+c4A5jXDC0uXTdHYRP8X2DQ= -golang.org/x/image v0.12.0/go.mod h1:Lu90jvHG7GfemOIcldsh9A2hS01ocl6oNO7ype5mEnk= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= -golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/image v0.0.0-20201208152932-35266b937fa6 h1:nfeHNc1nAqecKCy2FCy4HY+soOOe5sDLJ/gZLbx6GYI= +golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1 h1:Kvvh58BN8Y9/lBi7hTekvtMpm07eUZ0ck5pRHpsMWrY= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= +golang.org/x/net v0.0.0-20210510120150-4163338589ed h1:p9UgmWI9wKpfYmgaV/IZKGdXc5qEK45tDwwwDyjS26I= +golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210611083646-a4fc73990273/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211020174200-9d6173849985 h1:LOlKVhfDyahgmqa97awczplwkjzNaELFg3zRIJ13RYo= +golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= -golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= -golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= +golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -howett.net/plist v1.0.2-0.20250314012144-ee69052608d9 h1:eeH1AIcPvSc0Z25ThsYF+Xoqbn0CI/YnXVYoTLFdGQw= -howett.net/plist v1.0.2-0.20250314012144-ee69052608d9/go.mod h1:fyFX5Hj5tP1Mpk8obqA9MZgXT416Q5711SDT7dQLTLk= -mvdan.cc/sh/v3 v3.7.0 h1:lSTjdP/1xsddtaKfGg7Myu7DnlHItd3/M2tomOcNNBg= -mvdan.cc/sh/v3 v3.7.0/go.mod h1:K2gwkaesF/D7av7Kxl0HbF5kGOd2ArupNTX3X44+8l8= +nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= +nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= diff --git a/v2/init.go b/v2/init.go new file mode 100644 index 000000000..50dc23fdb --- /dev/null +++ b/v2/init.go @@ -0,0 +1,7 @@ +// +build !windows + +package wails + +func Init() error { + return nil +} diff --git a/v2/init_windows.go b/v2/init_windows.go new file mode 100644 index 000000000..173da0a89 --- /dev/null +++ b/v2/init_windows.go @@ -0,0 +1,15 @@ +package wails + +import ( + "fmt" + "syscall" +) + +// Init is called at the start of the application +func Init() error { + status, r, err := syscall.NewLazyDLL("user32.dll").NewProc("SetProcessDPIAware").Call() + if status == 0 { + return fmt.Errorf("exit status %d: %v %v", status, r, err) + } + return nil +} diff --git a/v2/internal/app/app.go b/v2/internal/app/app.go deleted file mode 100644 index 0cd6bf614..000000000 --- a/v2/internal/app/app.go +++ /dev/null @@ -1,45 +0,0 @@ -package app - -import ( - "context" - - "github.com/wailsapp/wails/v2/internal/frontend" - "github.com/wailsapp/wails/v2/internal/logger" - "github.com/wailsapp/wails/v2/internal/menumanager" - "github.com/wailsapp/wails/v2/pkg/menu" - "github.com/wailsapp/wails/v2/pkg/options" -) - -// App defines a Wails application structure -type App struct { - frontend frontend.Frontend - logger *logger.Logger - options *options.App - - menuManager *menumanager.Manager - - // Indicates if the app is in debug mode - debug bool - - // Indicates if the devtools is enabled - devtoolsEnabled bool - - // OnStartup/OnShutdown - startupCallback func(ctx context.Context) - shutdownCallback func(ctx context.Context) - ctx context.Context -} - -// Shutdown the application -func (a *App) Shutdown() { - if a.frontend != nil { - a.frontend.Quit() - } -} - -// SetApplicationMenu sets the application menu -func (a *App) SetApplicationMenu(menu *menu.Menu) { - if a.frontend != nil { - a.frontend.MenuSetApplicationMenu(menu) - } -} diff --git a/v2/internal/app/app_bindings.go b/v2/internal/app/app_bindings.go deleted file mode 100644 index be031819c..000000000 --- a/v2/internal/app/app_bindings.go +++ /dev/null @@ -1,124 +0,0 @@ -//go:build bindings - -package app - -import ( - "flag" - "os" - "path/filepath" - - "github.com/leaanthony/gosod" - "github.com/wailsapp/wails/v2/internal/binding" - "github.com/wailsapp/wails/v2/internal/frontend/runtime/wrapper" - "github.com/wailsapp/wails/v2/internal/fs" - "github.com/wailsapp/wails/v2/internal/logger" - "github.com/wailsapp/wails/v2/internal/project" - "github.com/wailsapp/wails/v2/pkg/options" -) - -func (a *App) Run() error { - - // Create binding exemptions - Ugly hack. There must be a better way - bindingExemptions := []interface{}{ - a.options.OnStartup, - a.options.OnShutdown, - a.options.OnDomReady, - a.options.OnBeforeClose, - } - - // Check for CLI Flags - bindingFlags := flag.NewFlagSet("bindings", flag.ContinueOnError) - - var tsPrefixFlag *string - var tsPostfixFlag *string - var tsOutputTypeFlag *string - - tsPrefix := os.Getenv("tsprefix") - if tsPrefix == "" { - tsPrefixFlag = bindingFlags.String("tsprefix", "", "Prefix for generated typescript entities") - } - - tsSuffix := os.Getenv("tssuffix") - if tsSuffix == "" { - tsPostfixFlag = bindingFlags.String("tssuffix", "", "Suffix for generated typescript entities") - } - - tsOutputType := os.Getenv("tsoutputtype") - if tsOutputType == "" { - tsOutputTypeFlag = bindingFlags.String("tsoutputtype", "", "Output type for generated typescript entities (classes|interfaces)") - } - - _ = bindingFlags.Parse(os.Args[1:]) - if tsPrefixFlag != nil { - tsPrefix = *tsPrefixFlag - } - if tsPostfixFlag != nil { - tsSuffix = *tsPostfixFlag - } - if tsOutputTypeFlag != nil { - tsOutputType = *tsOutputTypeFlag - } - - appBindings := binding.NewBindings(a.logger, a.options.Bind, bindingExemptions, IsObfuscated(), a.options.EnumBind) - - appBindings.SetTsPrefix(tsPrefix) - appBindings.SetTsSuffix(tsSuffix) - appBindings.SetOutputType(tsOutputType) - - err := generateBindings(appBindings) - if err != nil { - return err - } - return nil -} - -// CreateApp creates the app! -func CreateApp(appoptions *options.App) (*App, error) { - // Set up logger - myLogger := logger.New(appoptions.Logger) - myLogger.SetLogLevel(appoptions.LogLevel) - - result := &App{ - logger: myLogger, - options: appoptions, - } - - return result, nil - -} - -func generateBindings(bindings *binding.Bindings) error { - - cwd, err := os.Getwd() - if err != nil { - return err - } - projectConfig, err := project.Load(cwd) - if err != nil { - return err - } - - wailsjsbasedir := filepath.Join(projectConfig.GetWailsJSDir(), "wailsjs") - - runtimeDir := filepath.Join(wailsjsbasedir, "runtime") - _ = os.RemoveAll(runtimeDir) - extractor := gosod.New(wrapper.RuntimeWrapper) - err = extractor.Extract(runtimeDir, nil) - if err != nil { - return err - } - - goBindingsDir := filepath.Join(wailsjsbasedir, "go") - err = os.RemoveAll(goBindingsDir) - if err != nil { - return err - } - _ = fs.MkDirs(goBindingsDir) - - err = bindings.GenerateGoBindings(goBindingsDir) - if err != nil { - return err - } - - return fs.SetPermissions(wailsjsbasedir, 0755) -} diff --git a/v2/internal/app/app_debug.go b/v2/internal/app/app_debug.go deleted file mode 100644 index c14bedec1..000000000 --- a/v2/internal/app/app_debug.go +++ /dev/null @@ -1,7 +0,0 @@ -//go:build debug - -package app - -func IsDebug() bool { - return true -} diff --git a/v2/internal/app/app_debug_not.go b/v2/internal/app/app_debug_not.go deleted file mode 100644 index 04f841ede..000000000 --- a/v2/internal/app/app_debug_not.go +++ /dev/null @@ -1,7 +0,0 @@ -//go:build !debug - -package app - -func IsDebug() bool { - return false -} diff --git a/v2/internal/app/app_default_unix.go b/v2/internal/app/app_default_unix.go deleted file mode 100644 index 10d801285..000000000 --- a/v2/internal/app/app_default_unix.go +++ /dev/null @@ -1,18 +0,0 @@ -//go:build !dev && !production && !bindings && (linux || darwin) - -package app - -import ( - "fmt" - - "github.com/wailsapp/wails/v2/pkg/options" -) - -func (a *App) Run() error { - return nil -} - -// CreateApp creates the app! -func CreateApp(_ *options.App) (*App, error) { - return nil, fmt.Errorf(`Wails applications will not build without the correct build tags.`) -} diff --git a/v2/internal/app/app_dev.go b/v2/internal/app/app_dev.go deleted file mode 100644 index 6de845f96..000000000 --- a/v2/internal/app/app_dev.go +++ /dev/null @@ -1,298 +0,0 @@ -//go:build dev - -package app - -import ( - "context" - "embed" - "flag" - "fmt" - iofs "io/fs" - "net" - "net/url" - "os" - "path/filepath" - "time" - - "github.com/wailsapp/wails/v2/pkg/assetserver" - - "github.com/wailsapp/wails/v2/internal/binding" - "github.com/wailsapp/wails/v2/internal/frontend/desktop" - "github.com/wailsapp/wails/v2/internal/frontend/devserver" - "github.com/wailsapp/wails/v2/internal/frontend/dispatcher" - "github.com/wailsapp/wails/v2/internal/frontend/runtime" - "github.com/wailsapp/wails/v2/internal/fs" - "github.com/wailsapp/wails/v2/internal/logger" - "github.com/wailsapp/wails/v2/internal/menumanager" - pkglogger "github.com/wailsapp/wails/v2/pkg/logger" - "github.com/wailsapp/wails/v2/pkg/options" -) - -func (a *App) Run() error { - err := a.frontend.Run(a.ctx) - a.frontend.RunMainLoop() - a.frontend.WindowClose() - if a.shutdownCallback != nil { - a.shutdownCallback(a.ctx) - } - return err -} - -// CreateApp creates the app! -func CreateApp(appoptions *options.App) (*App, error) { - var err error - - ctx := context.Background() - ctx = context.WithValue(ctx, "debug", true) - ctx = context.WithValue(ctx, "devtoolsEnabled", true) - - // Set up logger if the appoptions.LogLevel is an invalid value, set it to the default log level - appoptions.LogLevel, err = pkglogger.StringToLogLevel(appoptions.LogLevel.String()) - if err != nil { - return nil, err - } - - myLogger := logger.New(appoptions.Logger) - myLogger.SetLogLevel(appoptions.LogLevel) - - // Check for CLI Flags - devFlags := flag.NewFlagSet("dev", flag.ContinueOnError) - - var assetdirFlag *string - var devServerFlag *string - var frontendDevServerURLFlag *string - var loglevelFlag *string - - assetdir := os.Getenv("assetdir") - if assetdir == "" { - assetdirFlag = devFlags.String("assetdir", "", "Directory to serve assets") - } - - devServer := os.Getenv("devserver") - if devServer == "" { - devServerFlag = devFlags.String("devserver", "", "Address to bind the wails dev server to") - } - - frontendDevServerURL := os.Getenv("frontenddevserverurl") - if frontendDevServerURL == "" { - frontendDevServerURLFlag = devFlags.String("frontenddevserverurl", "", "URL of the external frontend dev server") - } - - loglevel := os.Getenv("loglevel") - appLogLevel := appoptions.LogLevel.String() - if loglevel != "" { - appLogLevel = loglevel - } - loglevelFlag = devFlags.String("loglevel", appLogLevel, "Loglevel to use - Trace, Debug, Info, Warning, Error") - - // If we weren't given the assetdir in the environment variables - if assetdir == "" { - // Parse args but ignore errors in case -appargs was used to pass in args for the app. - _ = devFlags.Parse(os.Args[1:]) - if assetdirFlag != nil { - assetdir = *assetdirFlag - } - if devServerFlag != nil { - devServer = *devServerFlag - } - if frontendDevServerURLFlag != nil { - frontendDevServerURL = *frontendDevServerURLFlag - } - if loglevelFlag != nil { - loglevel = *loglevelFlag - } - } - - assetConfig, err := assetserver.BuildAssetServerConfig(appoptions) - if err != nil { - return nil, err - } - - if assetConfig.Assets == nil && frontendDevServerURL != "" { - myLogger.Warning("No AssetServer.Assets has been defined but a frontend DevServer, the frontend DevServer will not be used.") - frontendDevServerURL = "" - assetdir = "" - } - - if frontendDevServerURL != "" { - _, port, err := net.SplitHostPort(devServer) - if err != nil { - return nil, fmt.Errorf("unable to determine port of DevServer: %s", err) - } - - ctx = context.WithValue(ctx, "assetserverport", port) - - ctx = context.WithValue(ctx, "frontenddevserverurl", frontendDevServerURL) - - externalURL, err := url.Parse(frontendDevServerURL) - if err != nil { - return nil, err - } - - if externalURL.Host == "" { - return nil, fmt.Errorf("Invalid frontend:dev:serverUrl missing protocol scheme?") - } - - waitCb := func() { myLogger.Debug("Waiting for frontend DevServer '%s' to be ready", externalURL) } - if !checkPortIsOpen(externalURL.Host, time.Minute, waitCb) { - myLogger.Error("Timeout waiting for frontend DevServer") - } - - handler := assetserver.NewExternalAssetsHandler(myLogger, assetConfig, externalURL) - assetConfig.Assets = nil - assetConfig.Handler = handler - assetConfig.Middleware = nil - - myLogger.Info("Serving assets from frontend DevServer URL: %s", frontendDevServerURL) - } else { - if assetdir == "" { - // If no assetdir has been defined, let's try to infer it from the project root and the asset FS. - assetdir, err = tryInferAssetDirFromFS(assetConfig.Assets) - if err != nil { - return nil, fmt.Errorf("unable to infer the AssetDir from your Assets fs.FS: %w", err) - } - } - - if assetdir != "" { - // Let's override the assets to serve from on disk, if needed - absdir, err := filepath.Abs(assetdir) - if err != nil { - return nil, err - } - - myLogger.Info("Serving assets from disk: %s", absdir) - assetConfig.Assets = os.DirFS(absdir) - - ctx = context.WithValue(ctx, "assetdir", assetdir) - } - } - - // Migrate deprecated options to the new AssetServer option - appoptions.Assets = nil - appoptions.AssetsHandler = nil - appoptions.AssetServer = &assetConfig - - if devServer != "" { - ctx = context.WithValue(ctx, "devserver", devServer) - } - - if loglevel != "" { - level, err := pkglogger.StringToLogLevel(loglevel) - if err != nil { - return nil, err - } - // Only set the log level if it's different from the appoptions.LogLevel - if level != appoptions.LogLevel { - myLogger.SetLogLevel(level) - } - } - - // Attach logger to context - ctx = context.WithValue(ctx, "logger", myLogger) - ctx = context.WithValue(ctx, "buildtype", "dev") - - // Preflight checks - err = PreflightChecks(appoptions, myLogger) - if err != nil { - return nil, err - } - - // Merge default options - options.MergeDefaults(appoptions) - - var menuManager *menumanager.Manager - - // Process the application menu - if appoptions.Menu != nil { - // Create the menu manager - menuManager = menumanager.NewManager() - err = menuManager.SetApplicationMenu(appoptions.Menu) - if err != nil { - return nil, err - } - } - - // Create binding exemptions - Ugly hack. There must be a better way - bindingExemptions := []interface{}{ - appoptions.OnStartup, - appoptions.OnShutdown, - appoptions.OnDomReady, - appoptions.OnBeforeClose, - } - appBindings := binding.NewBindings(myLogger, appoptions.Bind, bindingExemptions, false, appoptions.EnumBind) - - eventHandler := runtime.NewEvents(myLogger) - ctx = context.WithValue(ctx, "events", eventHandler) - messageDispatcher := dispatcher.NewDispatcher(ctx, myLogger, appBindings, eventHandler, appoptions.ErrorFormatter, appoptions.DisablePanicRecovery) - - // Create the frontends and register to event handler - desktopFrontend := desktop.NewFrontend(ctx, appoptions, myLogger, appBindings, messageDispatcher) - appFrontend := devserver.NewFrontend(ctx, appoptions, myLogger, appBindings, messageDispatcher, menuManager, desktopFrontend) - eventHandler.AddFrontend(appFrontend) - eventHandler.AddFrontend(desktopFrontend) - - ctx = context.WithValue(ctx, "frontend", appFrontend) - result := &App{ - ctx: ctx, - frontend: appFrontend, - logger: myLogger, - menuManager: menuManager, - startupCallback: appoptions.OnStartup, - shutdownCallback: appoptions.OnShutdown, - debug: true, - devtoolsEnabled: true, - } - - result.options = appoptions - - return result, nil - -} - -func tryInferAssetDirFromFS(assets iofs.FS) (string, error) { - if _, isEmbedFs := assets.(embed.FS); !isEmbedFs { - // We only infer the assetdir for embed.FS assets - return "", nil - } - - path, err := fs.FindPathToFile(assets, "index.html") - if err != nil { - return "", err - } - - path, err = filepath.Abs(path) - if err != nil { - return "", err - } - - if _, err := os.Stat(filepath.Join(path, "index.html")); err != nil { - if os.IsNotExist(err) { - err = fmt.Errorf( - "inferred assetdir '%s' does not exist or does not contain an 'index.html' file, "+ - "please specify it with -assetdir or set it in wails.json", - path) - } - return "", err - } - - return path, nil -} - -func checkPortIsOpen(host string, timeout time.Duration, waitCB func()) (ret bool) { - if timeout == 0 { - timeout = time.Minute - } - - deadline := time.Now().Add(timeout) - for time.Now().Before(deadline) { - conn, _ := net.DialTimeout("tcp", host, 2*time.Second) - if conn != nil { - conn.Close() - return true - } - - waitCB() - time.Sleep(1 * time.Second) - } - return false -} diff --git a/v2/internal/app/app_devtools.go b/v2/internal/app/app_devtools.go deleted file mode 100644 index 60b221094..000000000 --- a/v2/internal/app/app_devtools.go +++ /dev/null @@ -1,8 +0,0 @@ -//go:build devtools - -package app - -// Note: devtools flag is also added in debug builds -func IsDevtoolsEnabled() bool { - return true -} diff --git a/v2/internal/app/app_devtools_not.go b/v2/internal/app/app_devtools_not.go deleted file mode 100644 index 912672048..000000000 --- a/v2/internal/app/app_devtools_not.go +++ /dev/null @@ -1,9 +0,0 @@ -//go:build !devtools - -package app - -// IsDevtoolsEnabled returns true if devtools should be enabled -// Note: devtools flag is also added in debug builds -func IsDevtoolsEnabled() bool { - return false -} diff --git a/v2/internal/app/app_obfuscated.go b/v2/internal/app/app_obfuscated.go deleted file mode 100644 index c78c10b87..000000000 --- a/v2/internal/app/app_obfuscated.go +++ /dev/null @@ -1,8 +0,0 @@ -//go:build obfuscated - -package app - -// IsObfuscated returns true if the obfuscated build tag is set -func IsObfuscated() bool { - return true -} diff --git a/v2/internal/app/app_obfuscated_not.go b/v2/internal/app/app_obfuscated_not.go deleted file mode 100644 index 90cc8559f..000000000 --- a/v2/internal/app/app_obfuscated_not.go +++ /dev/null @@ -1,8 +0,0 @@ -//go:build !obfuscated - -package app - -// IsObfuscated returns false if the obfuscated build tag is not set -func IsObfuscated() bool { - return false -} diff --git a/v2/internal/app/app_preflight_unix.go b/v2/internal/app/app_preflight_unix.go deleted file mode 100644 index f554df740..000000000 --- a/v2/internal/app/app_preflight_unix.go +++ /dev/null @@ -1,12 +0,0 @@ -//go:build (linux || darwin) && !bindings - -package app - -import ( - "github.com/wailsapp/wails/v2/internal/logger" - "github.com/wailsapp/wails/v2/pkg/options" -) - -func PreflightChecks(_ *options.App, _ *logger.Logger) error { - return nil -} diff --git a/v2/internal/app/app_preflight_windows.go b/v2/internal/app/app_preflight_windows.go deleted file mode 100644 index 1b71b8b19..000000000 --- a/v2/internal/app/app_preflight_windows.go +++ /dev/null @@ -1,27 +0,0 @@ -//go:build windows && !bindings - -package app - -import ( - "github.com/wailsapp/wails/v2/internal/logger" - "github.com/wailsapp/wails/v2/internal/wv2installer" - "github.com/wailsapp/wails/v2/pkg/options" -) - -func PreflightChecks(options *options.App, logger *logger.Logger) error { - - _ = options - - // Process the webview2 runtime situation. We can pass a strategy in via the `webview2` flag for `wails build`. - // This will determine how wv2runtime.Process will handle a lack of valid runtime. - installedVersion, err := wv2installer.Process(options) - if installedVersion != "" { - logger.Debug("WebView2 Runtime Version '%s' installed. Minimum version required: %s.", - installedVersion, wv2installer.MinimumRuntimeVersion) - } - if err != nil { - return err - } - - return nil -} diff --git a/v2/internal/app/app_production.go b/v2/internal/app/app_production.go deleted file mode 100644 index 9eb0e5a66..000000000 --- a/v2/internal/app/app_production.go +++ /dev/null @@ -1,104 +0,0 @@ -//go:build production - -package app - -import ( - "context" - - "github.com/wailsapp/wails/v2/internal/binding" - "github.com/wailsapp/wails/v2/internal/frontend/desktop" - "github.com/wailsapp/wails/v2/internal/frontend/dispatcher" - "github.com/wailsapp/wails/v2/internal/frontend/runtime" - "github.com/wailsapp/wails/v2/internal/logger" - "github.com/wailsapp/wails/v2/internal/menumanager" - "github.com/wailsapp/wails/v2/pkg/options" -) - -func (a *App) Run() error { - err := a.frontend.Run(a.ctx) - a.frontend.RunMainLoop() - a.frontend.WindowClose() - if a.shutdownCallback != nil { - a.shutdownCallback(a.ctx) - } - return err -} - -// CreateApp creates the app! -func CreateApp(appoptions *options.App) (*App, error) { - var err error - - ctx := context.Background() - - // Merge default options - options.MergeDefaults(appoptions) - - debug := IsDebug() - devtoolsEnabled := IsDevtoolsEnabled() - ctx = context.WithValue(ctx, "debug", debug) - ctx = context.WithValue(ctx, "devtoolsEnabled", devtoolsEnabled) - - // Set up logger - myLogger := logger.New(appoptions.Logger) - if IsDebug() { - myLogger.SetLogLevel(appoptions.LogLevel) - } else { - myLogger.SetLogLevel(appoptions.LogLevelProduction) - } - ctx = context.WithValue(ctx, "logger", myLogger) - ctx = context.WithValue(ctx, "obfuscated", IsObfuscated()) - - // Preflight Checks - err = PreflightChecks(appoptions, myLogger) - if err != nil { - return nil, err - } - - // Create the menu manager - menuManager := menumanager.NewManager() - - // Process the application menu - if appoptions.Menu != nil { - err = menuManager.SetApplicationMenu(appoptions.Menu) - if err != nil { - return nil, err - } - } - - // Create binding exemptions - Ugly hack. There must be a better way - bindingExemptions := []interface{}{ - appoptions.OnStartup, - appoptions.OnShutdown, - appoptions.OnDomReady, - appoptions.OnBeforeClose, - } - appBindings := binding.NewBindings(myLogger, appoptions.Bind, bindingExemptions, IsObfuscated(), appoptions.EnumBind) - eventHandler := runtime.NewEvents(myLogger) - ctx = context.WithValue(ctx, "events", eventHandler) - // Attach logger to context - if debug { - ctx = context.WithValue(ctx, "buildtype", "debug") - } else { - ctx = context.WithValue(ctx, "buildtype", "production") - } - - messageDispatcher := dispatcher.NewDispatcher(ctx, myLogger, appBindings, eventHandler, appoptions.ErrorFormatter, appoptions.DisablePanicRecovery) - appFrontend := desktop.NewFrontend(ctx, appoptions, myLogger, appBindings, messageDispatcher) - eventHandler.AddFrontend(appFrontend) - - ctx = context.WithValue(ctx, "frontend", appFrontend) - result := &App{ - ctx: ctx, - frontend: appFrontend, - logger: myLogger, - menuManager: menuManager, - startupCallback: appoptions.OnStartup, - shutdownCallback: appoptions.OnShutdown, - debug: debug, - devtoolsEnabled: devtoolsEnabled, - options: appoptions, - } - - return result, nil - -} diff --git a/v2/internal/app/debug.go b/v2/internal/app/debug.go new file mode 100644 index 000000000..3a6a6916f --- /dev/null +++ b/v2/internal/app/debug.go @@ -0,0 +1,37 @@ +//go:build dev +// +build dev + +package app + +import ( + "flag" + "strings" + + "github.com/wailsapp/wails/v2/pkg/logger" +) + +// Init initialises the application for a debug environment +func (a *App) Init() error { + // Indicate debug mode + a.debug = true + + // Set log levels + loglevel := flag.String("loglevel", "debug", "Loglevel to use - Trace, Debug, Info, Warning, Error") + flag.Parse() + if len(*loglevel) > 0 { + switch strings.ToLower(*loglevel) { + case "trace": + a.logger.SetLogLevel(logger.TRACE) + case "info": + a.logger.SetLogLevel(logger.INFO) + case "warning": + a.logger.SetLogLevel(logger.WARNING) + case "error": + a.logger.SetLogLevel(logger.ERROR) + default: + a.logger.SetLogLevel(logger.DEBUG) + } + } + + return nil +} diff --git a/v2/internal/app/default.go b/v2/internal/app/default.go new file mode 100644 index 000000000..380c251be --- /dev/null +++ b/v2/internal/app/default.go @@ -0,0 +1,41 @@ +// +build !desktop,!hybrid,!server,!dev + +package app + +// This is the default application that will get run if the user compiles using `go build`. +// The reason we want to prevent that is that the `wails build` command does a lot of behind +// the scenes work such as asset compilation. If we allow `go build`, the state of these assets +// will be unknown and the application will not work as expected. + +import ( + "os" + + "github.com/wailsapp/wails/v2/internal/logger" + + "github.com/wailsapp/wails/v2/pkg/options" +) + +// App defines a Wails application structure +type App struct { + Title string + Width int + Height int + Resizable bool + + // Indicates if the app is running in debug mode + debug bool + + logger *logger.Logger +} + +// CreateApp returns a null application +func CreateApp(_ *options.App) (*App, error) { + return &App{}, nil +} + +// Run the application +func (a *App) Run() error { + println(`FATAL: This application was built using "go build". This is unsupported. Please compile using "wails build".`) + os.Exit(1) + return nil +} diff --git a/v2/internal/app/desktop.go b/v2/internal/app/desktop.go new file mode 100644 index 000000000..b27f92919 --- /dev/null +++ b/v2/internal/app/desktop.go @@ -0,0 +1,256 @@ +//go:build desktop && !server +// +build desktop,!server + +package app + +import ( + "context" + "sync" + + "github.com/wailsapp/wails/v2/internal/binding" + "github.com/wailsapp/wails/v2/internal/ffenestri" + "github.com/wailsapp/wails/v2/internal/logger" + "github.com/wailsapp/wails/v2/internal/menumanager" + "github.com/wailsapp/wails/v2/internal/messagedispatcher" + "github.com/wailsapp/wails/v2/internal/servicebus" + "github.com/wailsapp/wails/v2/internal/signal" + "github.com/wailsapp/wails/v2/internal/subsystem" + "github.com/wailsapp/wails/v2/pkg/options" +) + +// App defines a Wails application structure +type App struct { + appType string + + window *ffenestri.Application + servicebus *servicebus.ServiceBus + logger *logger.Logger + signal *signal.Manager + options *options.App + + // Subsystems + log *subsystem.Log + runtime *subsystem.Runtime + event *subsystem.Event + //binding *subsystem.Binding + call *subsystem.Call + menu *subsystem.Menu + url *subsystem.URL + dispatcher *messagedispatcher.Dispatcher + + menuManager *menumanager.Manager + + // Indicates if the app is in debug mode + debug bool + + // This is our binding DB + bindings *binding.Bindings + + // OnStartup/OnShutdown + startupCallback func(ctx context.Context) + shutdownCallback func() +} + +// Create App +func CreateApp(appoptions *options.App) (*App, error) { + + // Merge default options + options.MergeDefaults(appoptions) + + // Set up logger + myLogger := logger.New(appoptions.Logger) + myLogger.SetLogLevel(appoptions.LogLevel) + + // Create the menu manager + menuManager := menumanager.NewManager() + + // Process the application menu + appMenu := options.GetApplicationMenu(appoptions) + menuManager.SetApplicationMenu(appMenu) + + // Process context menus + contextMenus := options.GetContextMenus(appoptions) + for _, contextMenu := range contextMenus { + menuManager.AddContextMenu(contextMenu) + } + + // Process tray menus + trayMenus := options.GetTrayMenus(appoptions) + for _, trayMenu := range trayMenus { + menuManager.AddTrayMenu(trayMenu) + } + + window := ffenestri.NewApplicationWithConfig(appoptions, myLogger, menuManager) + + // Create binding exemptions - Ugly hack. There must be a better way + bindingExemptions := []interface{}{appoptions.OnStartup, appoptions.OnShutdown, appoptions.OnDomReady} + + result := &App{ + appType: "desktop", + window: window, + servicebus: servicebus.New(myLogger), + logger: myLogger, + bindings: binding.NewBindings(myLogger, appoptions.Bind, bindingExemptions), + menuManager: menuManager, + startupCallback: appoptions.OnStartup, + shutdownCallback: appoptions.OnShutdown, + } + + result.options = appoptions + + // Initialise the app + err := result.Init() + if err != nil { + return nil, err + } + + // Preflight Checks + err = result.PreflightChecks(appoptions) + if err != nil { + return nil, err + } + + return result, nil + +} + +// Run the application +func (a *App) Run() error { + + var err error + + // Setup a context + var subsystemWaitGroup sync.WaitGroup + parentContext := context.WithValue(context.Background(), "waitgroup", &subsystemWaitGroup) + ctx, cancel := context.WithCancel(parentContext) + + // Start the service bus + a.servicebus.Debug() + err = a.servicebus.Start() + if err != nil { + return err + } + + runtimesubsystem, err := subsystem.NewRuntime(ctx, a.servicebus, a.logger, a.startupCallback) + if err != nil { + return err + } + a.runtime = runtimesubsystem + err = a.runtime.Start() + if err != nil { + return err + } + + // Start the logging subsystem + log, err := subsystem.NewLog(a.servicebus, a.logger) + if err != nil { + return err + } + a.log = log + err = a.log.Start() + if err != nil { + return err + } + + // create the dispatcher + dispatcher, err := messagedispatcher.New(a.servicebus, a.logger) + if err != nil { + return err + } + a.dispatcher = dispatcher + err = dispatcher.Start() + if err != nil { + return err + } + + if a.options.Mac.URLHandlers != nil { + // Start the url handler subsystem + url, err := subsystem.NewURL(a.servicebus, a.logger, a.options.Mac.URLHandlers) + if err != nil { + return err + } + a.url = url + err = a.url.Start() + if err != nil { + return err + } + } + + // Start the eventing subsystem + eventsubsystem, err := subsystem.NewEvent(ctx, a.servicebus, a.logger) + if err != nil { + return err + } + a.event = eventsubsystem + err = a.event.Start() + if err != nil { + return err + } + + // Start the menu subsystem + menusubsystem, err := subsystem.NewMenu(ctx, a.servicebus, a.logger, a.menuManager) + if err != nil { + return err + } + a.menu = menusubsystem + err = a.menu.Start() + if err != nil { + return err + } + + // Start the call subsystem + callSubsystem, err := subsystem.NewCall(ctx, a.servicebus, a.logger, a.bindings.DB()) + if err != nil { + return err + } + a.call = callSubsystem + err = a.call.Start() + if err != nil { + return err + } + + // Dump bindings as a debug + bindingDump, err := a.bindings.ToJSON() + if err != nil { + return err + } + + // Setup signal handler + signalsubsystem, err := signal.NewManager(ctx, cancel, a.servicebus, a.logger) + if err != nil { + return err + } + a.signal = signalsubsystem + a.signal.Start() + + err = a.window.Run(dispatcher, bindingDump, a.debug) + a.logger.Trace("Ffenestri.Run() exited") + if err != nil { + return err + } + + // Close down all the subsystems + a.logger.Trace("Cancelling subsystems") + cancel() + subsystemWaitGroup.Wait() + + a.logger.Trace("Cancelling dispatcher") + dispatcher.Close() + + // Close log + a.logger.Trace("Stopping log") + log.Close() + + a.logger.Trace("Stopping Service bus") + err = a.servicebus.Stop() + if err != nil { + return err + } + + // OnShutdown callback + if a.shutdownCallback != nil { + a.shutdownCallback() + } + + return nil +} diff --git a/v2/internal/app/dev.go b/v2/internal/app/dev.go new file mode 100644 index 000000000..3b7be059f --- /dev/null +++ b/v2/internal/app/dev.go @@ -0,0 +1,249 @@ +//go:build dev +// +build dev + +package app + +/* +import ( + "context" + "sync" + + "github.com/wailsapp/wails/runtime" + + "github.com/wailsapp/wails/v2/internal/bridge" + "github.com/wailsapp/wails/v2/internal/menumanager" + + "github.com/wailsapp/wails/v2/pkg/options" + + "github.com/wailsapp/wails/v2/internal/binding" + "github.com/wailsapp/wails/v2/internal/logger" + "github.com/wailsapp/wails/v2/internal/messagedispatcher" + "github.com/wailsapp/wails/v2/internal/servicebus" + "github.com/wailsapp/wails/v2/internal/signal" + "github.com/wailsapp/wails/v2/internal/subsystem" +) + +// App defines a Wails application structure +type App struct { + appType string + + servicebus *servicebus.ServiceBus + logger *logger.Logger + signal *signal.Manager + options *options.App + + // Subsystems + log *subsystem.Log + runtime *subsystem.Runtime + event *subsystem.Event + //binding *subsystem.Binding + call *subsystem.Call + menu *subsystem.Menu + dispatcher *messagedispatcher.Dispatcher + + menuManager *menumanager.Manager + + // Indicates if the app is in debug mode + debug bool + + // This is our binding DB + bindings *binding.Bindings + + // Application Stores + loglevelStore *runtime.Store + appconfigStore *runtime.Store + + // OnStartup/OnShutdown + startupCallback func(*runtime.Runtime) + shutdownCallback func() + + // Bridge + bridge *bridge.Bridge +} + +// Create App +func CreateApp(appoptions *options.App) (*App, error) { + + // Merge default options + options.MergeDefaults(appoptions) + + // Set up logger + myLogger := logger.New(appoptions.Logger) + + // Create the menu manager + menuManager := menumanager.NewManager() + + // Process the application menu + menuManager.SetApplicationMenu(options.GetApplicationMenu(appoptions)) + + // Process context menus + contextMenus := options.GetContextMenus(appoptions) + for _, contextMenu := range contextMenus { + menuManager.AddContextMenu(contextMenu) + } + + // Process tray menus + trayMenus := options.GetTrayMenus(appoptions) + for _, trayMenu := range trayMenus { + menuManager.AddTrayMenu(trayMenu) + } + + // Create binding exemptions - Ugly hack. There must be a better way + bindingExemptions := []interface{}{appoptions.OnStartup, appoptions.OnShutdown, appoptions.OnDomReady} + + result := &App{ + appType: "dev", + bindings: binding.NewBindings(myLogger, appoptions.Bind, bindingExemptions), + logger: myLogger, + servicebus: servicebus.New(myLogger), + startupCallback: appoptions.OnStartup, + shutdownCallback: appoptions.OnShutdown, + bridge: bridge.NewBridge(myLogger), + menuManager: menuManager, + } + + result.options = appoptions + + // Initialise the app + err := result.Init() + + return result, err + +} + +// Run the application +func (a *App) Run() error { + + var err error + + // Setup a context + var subsystemWaitGroup sync.WaitGroup + parentContext := context.WithValue(context.Background(), "waitgroup", &subsystemWaitGroup) + ctx, cancel := context.WithCancel(parentContext) + defer cancel() + + // Start the service bus + a.servicebus.Debug() + err = a.servicebus.Start() + if err != nil { + return err + } + + runtimesubsystem, err := subsystem.NewRuntime(ctx, a.servicebus, a.logger, a.startupCallback) + if err != nil { + return err + } + a.runtime = runtimesubsystem + err = a.runtime.Start() + if err != nil { + return err + } + + // Application Stores + a.loglevelStore = a.runtime.GoRuntime().Store.New("wails:loglevel", a.options.LogLevel) + a.appconfigStore = a.runtime.GoRuntime().Store.New("wails:appconfig", a.options) + + // Start the logging subsystem + log, err := subsystem.NewLog(a.servicebus, a.logger, a.loglevelStore) + if err != nil { + return err + } + a.log = log + err = a.log.Start() + if err != nil { + return err + } + + // create the dispatcher + dispatcher, err := messagedispatcher.New(a.servicebus, a.logger) + if err != nil { + return err + } + a.dispatcher = dispatcher + err = dispatcher.Start() + if err != nil { + return err + } + + // Start the eventing subsystem + eventsubsystem, err := subsystem.NewEvent(ctx, a.servicebus, a.logger) + if err != nil { + return err + } + a.event = eventsubsystem + err = a.event.Start() + if err != nil { + return err + } + + // Start the menu subsystem + menusubsystem, err := subsystem.NewMenu(ctx, a.servicebus, a.logger, a.menuManager) + if err != nil { + return err + } + a.menu = menusubsystem + err = a.menu.Start() + if err != nil { + return err + } + + // Start the call subsystem + callSubsystem, err := subsystem.NewCall(ctx, a.servicebus, a.logger, a.bindings.DB()) + if err != nil { + return err + } + a.call = callSubsystem + err = a.call.Start() + if err != nil { + return err + } + + // Dump bindings as a debug + bindingDump, err := a.bindings.ToJSON() + if err != nil { + return err + } + + // Generate backend.js + a.bindings.GenerateBackendJS() + + // Setup signal handler + signalsubsystem, err := signal.NewManager(ctx, cancel, a.servicebus, a.logger) + if err != nil { + return err + } + a.signal = signalsubsystem + a.signal.Start() + + err = a.bridge.Run(dispatcher, a.menuManager, bindingDump, a.debug) + a.logger.Trace("Bridge.Run() exited") + if err != nil { + return err + } + + // Close down all the subsystems + a.logger.Trace("Cancelling subsystems") + cancel() + subsystemWaitGroup.Wait() + + a.logger.Trace("Cancelling dispatcher") + dispatcher.Close() + + // Close log + a.logger.Trace("Stopping log") + log.Close() + + a.logger.Trace("Stopping Service bus") + err = a.servicebus.Stop() + if err != nil { + return err + } + + // OnShutdown callback + if a.shutdownCallback != nil { + a.shutdownCallback() + } + return nil + +} +*/ diff --git a/v2/internal/app/hybrid.go b/v2/internal/app/hybrid.go new file mode 100644 index 000000000..8c95c2879 --- /dev/null +++ b/v2/internal/app/hybrid.go @@ -0,0 +1,194 @@ +// +build !server,!desktop,hybrid + +package app + +import ( + "os" + "path/filepath" + + "github.com/leaanthony/clir" + "github.com/wailsapp/wails/v2/internal/binding" + "github.com/wailsapp/wails/v2/internal/ffenestri" + "github.com/wailsapp/wails/v2/internal/logger" + "github.com/wailsapp/wails/v2/internal/messagedispatcher" + "github.com/wailsapp/wails/v2/internal/servicebus" + "github.com/wailsapp/wails/v2/internal/subsystem" + "github.com/wailsapp/wails/v2/internal/webserver" +) + +// Config defines the Application's configuration +type Config struct { + Title string // Title is the value to be displayed in the title bar + Width int // Width is the desired window width + Height int // Height is the desired window height + DevTools bool // DevTools enables or disables the browser development tools + Resizable bool // Resizable when False prevents window resizing + ServerEnabled bool // ServerEnabled when True allows remote connections +} + +// App defines a Wails application structure +type App struct { + config Config + window *ffenestri.Application + webserver *webserver.WebServer + binding *subsystem.Binding + call *subsystem.Call + event *subsystem.Event + log *subsystem.Log + runtime *subsystem.Runtime + + bindings *binding.Bindings + logger *logger.Logger + dispatcher *messagedispatcher.Dispatcher + servicebus *servicebus.ServiceBus + + debug bool +} + +// Create App +func CreateApp(options *Options) *App { + + // Merge default options + options.mergeDefaults() + + // Set up logger + myLogger := logger.New(os.Stdout) + myLogger.SetLogLevel(logger.INFO) + + window := ffenestri.NewApplicationWithConfig(&ffenestri.Config{ + Title: options.Title, + Width: options.Width, + Height: options.Height, + MinWidth: options.MinWidth, + MinHeight: options.MinHeight, + MaxWidth: options.MaxWidth, + MaxHeight: options.MaxHeight, + StartHidden: options.StartHidden, + DevTools: options.DevTools, + + Resizable: !options.DisableResize, + Fullscreen: options.Fullscreen, + }, myLogger) + + app := &App{ + window: window, + webserver: webserver.NewWebServer(myLogger), + servicebus: servicebus.New(myLogger), + logger: myLogger, + bindings: binding.NewBindings(myLogger, options.Bind), + } + + // Initialise the app + app.Init() + + return app +} + +// Run the application +func (a *App) Run() error { + + // Default app options + var port = 8080 + var ip = "localhost" + var suppressLogging = false + + // Create CLI + cli := clir.NewCli(filepath.Base(os.Args[0]), "Desktop/Server Build", "") + + // Setup flags + cli.IntFlag("p", "Port to serve on", &port) + cli.StringFlag("i", "IP to serve on", &ip) + cli.BoolFlag("q", "Suppress logging", &suppressLogging) + + // Setup main action + cli.Action(func() error { + + // Set IP + Port + a.webserver.SetPort(port) + a.webserver.SetIP(ip) + a.webserver.SetBindings(a.bindings) + // Log information (if we aren't suppressing it) + if !suppressLogging { + cli.PrintBanner() + a.logger.Info("Running server at %s", a.webserver.URL()) + } + + a.servicebus.Start() + log, err := subsystem.NewLog(a.servicebus, a.logger) + if err != nil { + return err + } + a.log = log + a.log.Start() + dispatcher, err := messagedispatcher.New(a.servicebus, a.logger) + if err != nil { + return err + } + a.dispatcher = dispatcher + a.dispatcher.Start() + + // Start the runtime + runtime, err := subsystem.NewRuntime(a.servicebus, a.logger) + if err != nil { + return err + } + a.runtime = runtime + a.runtime.Start() + + // Start the binding subsystem + binding, err := subsystem.NewBinding(a.servicebus, a.logger, a.bindings, runtime.GoRuntime()) + if err != nil { + return err + } + a.binding = binding + a.binding.Start() + + // Start the eventing subsystem + event, err := subsystem.NewEvent(a.servicebus, a.logger) + if err != nil { + return err + } + a.event = event + a.event.Start() + + // Start the call subsystem + call, err := subsystem.NewCall(a.servicebus, a.logger, a.bindings.DB()) + if err != nil { + return err + } + a.call = call + a.call.Start() + + // Required so that the WailsInit functions are fired! + runtime.GoRuntime().Events.Emit("wails:loaded") + + // Set IP + Port + a.webserver.SetPort(port) + a.webserver.SetIP(ip) + + // Log information (if we aren't suppressing it) + if !suppressLogging { + cli.PrintBanner() + println("Running server at " + a.webserver.URL()) + } + + // Dump bindings as a debug + bindingDump, err := a.bindings.ToJSON() + if err != nil { + return err + } + + go func() { + if err := a.webserver.Start(dispatcher, event); err != nil { + a.logger.Error("Webserver failed to start %s", err) + } + }() + + result := a.window.Run(dispatcher, bindingDump) + a.servicebus.Stop() + + return result + }) + + return cli.Run() +} diff --git a/v2/internal/app/preflight_default.go b/v2/internal/app/preflight_default.go new file mode 100644 index 000000000..5508a7748 --- /dev/null +++ b/v2/internal/app/preflight_default.go @@ -0,0 +1,9 @@ +//+build !windows + +package app + +import "github.com/wailsapp/wails/v2/pkg/options" + +func (a *App) PreflightChecks(options *options.App) error { + return nil +} diff --git a/v2/internal/app/preflight_windows.go b/v2/internal/app/preflight_windows.go new file mode 100644 index 000000000..29bbb7a74 --- /dev/null +++ b/v2/internal/app/preflight_windows.go @@ -0,0 +1,26 @@ +//+build windows + +package app + +import ( + "github.com/wailsapp/wails/v2/internal/ffenestri/windows/wv2runtime" + "github.com/wailsapp/wails/v2/pkg/options" +) + +func (a *App) PreflightChecks(options *options.App) error { + + _ = options + + // Process the webview2 runtime situation. We can pass a strategy in via the `webview2` flag for `wails build`. + // This will determine how wv2runtime.Process will handle a lack of valid runtime. + installedVersion, err := wv2runtime.Process() + if installedVersion != nil { + a.logger.Debug("WebView2 Runtime installed: Name: '%s' Version:'%s' Location:'%s'. Minimum version required: %s.", + installedVersion.Name, installedVersion.Version, installedVersion.Location, wv2runtime.MinimumRuntimeVersion) + } + if err != nil { + return err + } + + return nil +} diff --git a/v2/internal/app/production.go b/v2/internal/app/production.go new file mode 100644 index 000000000..9a2554826 --- /dev/null +++ b/v2/internal/app/production.go @@ -0,0 +1,12 @@ +//go:build production +// +build production + +package app + +import "github.com/wailsapp/wails/v2/pkg/logger" + +// Init initialises the application for a production environment +func (a *App) Init() error { + a.logger.SetLogLevel(logger.ERROR) + return nil +} diff --git a/v2/internal/app/server.go b/v2/internal/app/server.go new file mode 100644 index 000000000..06734f0ad --- /dev/null +++ b/v2/internal/app/server.go @@ -0,0 +1,165 @@ +//go:build server && !desktop +// +build server,!desktop + +package app + +import ( + "context" + "os" + "path/filepath" + + "github.com/wailsapp/wails/v2/pkg/options" + + "github.com/leaanthony/clir" + "github.com/wailsapp/wails/v2/internal/binding" + "github.com/wailsapp/wails/v2/internal/logger" + "github.com/wailsapp/wails/v2/internal/messagedispatcher" + "github.com/wailsapp/wails/v2/internal/servicebus" + "github.com/wailsapp/wails/v2/internal/subsystem" + "github.com/wailsapp/wails/v2/internal/webserver" +) + +// App defines a Wails application structure +type App struct { + appType string + + binding *subsystem.Binding + call *subsystem.Call + event *subsystem.Event + log *subsystem.Log + + options *options.App + + bindings *binding.Bindings + logger *logger.Logger + dispatcher *messagedispatcher.Dispatcher + servicebus *servicebus.ServiceBus + webserver *webserver.WebServer + + debug bool + + // OnStartup/OnShutdown + startupCallback func(ctx context.Context) + shutdownCallback func() +} + +// Create App +func CreateApp(appoptions *options.App) (*App, error) { + + // Merge default options + options.MergeDefaults(appoptions) + + // Set up logger + myLogger := logger.New(appoptions.Logger) + myLogger.SetLogLevel(appoptions.LogLevel) + + result := &App{ + appType: "server", + bindings: binding.NewBindings(myLogger, options.Bind), + logger: myLogger, + servicebus: servicebus.New(myLogger), + webserver: webserver.NewWebServer(myLogger), + startupCallback: appoptions.OnStartup, + shutdownCallback: appoptions.OnShutdown, + } + + // Initialise app + result.Init() + + return result, nil +} + +// Run the application +func (a *App) Run() error { + + // Default app options + var port = 8080 + var ip = "localhost" + var SuppressLogging = false + var debugMode = false + + // Create CLI + cli := clir.NewCli(filepath.Base(os.Args[0]), "Server Build", "") + + // Setup flags + cli.IntFlag("p", "Port to serve on", &port) + cli.StringFlag("i", "IP to serve on", &ip) + cli.BoolFlag("d", "Debug mode", &debugMode) + cli.BoolFlag("q", "Suppress logging", &SuppressLogging) + + // Setup main action + cli.Action(func() error { + + // Set IP + Port + a.webserver.SetPort(port) + a.webserver.SetIP(ip) + a.webserver.SetBindings(a.bindings) + // Log information (if we aren't Suppressing it) + if !SuppressLogging { + cli.PrintBanner() + a.logger.Info("Running server at %s", a.webserver.URL()) + } + + if debugMode { + a.servicebus.Debug() + } + + // Start the runtime + runtime, err := subsystem.NewRuntime(a.servicebus, a.logger, a.startupCallback) + if err != nil { + return err + } + a.runtime = runtime + a.runtime.Start() + + a.servicebus.Start() + log, err := subsystem.NewLog(a.servicebus, a.logger) + if err != nil { + return err + } + a.log = log + a.log.Start() + dispatcher, err := messagedispatcher.New(a.servicebus, a.logger) + if err != nil { + return err + } + a.dispatcher = dispatcher + a.dispatcher.Start() + + // Start the binding subsystem + binding, err := subsystem.NewBinding(a.servicebus, a.logger, a.bindings) + if err != nil { + return err + } + a.binding = binding + a.binding.Start() + + // Start the eventing subsystem + event, err := subsystem.NewEvent(a.servicebus, a.logger) + if err != nil { + return err + } + a.event = event + a.event.Start() + + // Start the call subsystem + call, err := subsystem.NewCall(a.servicebus, a.logger, a.bindings.DB(), a.runtime.GoRuntime()) + if err != nil { + return err + } + a.call = call + a.call.Start() + + // Required so that the WailsInit functions are fired! + runtime.GoRuntime().Events.Emit("wails:loaded") + + if err := a.webserver.Start(dispatcher, event); err != nil { + a.logger.Error("Webserver failed to start %s", err) + return err + } + + return nil + }) + + return cli.Run() +} diff --git a/v2/internal/appng/app_bindings.go b/v2/internal/appng/app_bindings.go new file mode 100644 index 000000000..e314802c9 --- /dev/null +++ b/v2/internal/appng/app_bindings.go @@ -0,0 +1,105 @@ +//go:build bindings +// +build bindings + +package appng + +import ( + "github.com/leaanthony/gosod" + "github.com/wailsapp/wails/v2/internal/binding" + wailsRuntime "github.com/wailsapp/wails/v2/internal/frontend/runtime" + "github.com/wailsapp/wails/v2/internal/frontend/runtime/wrapper" + "github.com/wailsapp/wails/v2/internal/fs" + "github.com/wailsapp/wails/v2/internal/logger" + "github.com/wailsapp/wails/v2/internal/project" + "github.com/wailsapp/wails/v2/pkg/options" + "os" + "path/filepath" +) + +// App defines a Wails application structure +type App struct { + logger *logger.Logger + appoptions *options.App +} + +func (a *App) Run() error { + + // Create binding exemptions - Ugly hack. There must be a better way + bindingExemptions := []interface{}{a.appoptions.OnStartup, a.appoptions.OnShutdown, a.appoptions.OnDomReady} + appBindings := binding.NewBindings(a.logger, a.appoptions.Bind, bindingExemptions) + + err := generateBindings(appBindings) + if err != nil { + return err + } + return nil +} + +// CreateApp creates the app! +func CreateApp(appoptions *options.App) (*App, error) { + // Set up logger + myLogger := logger.New(appoptions.Logger) + myLogger.SetLogLevel(appoptions.LogLevel) + + result := &App{ + logger: myLogger, + appoptions: appoptions, + } + + return result, nil + +} + +func generateBindings(bindings *binding.Bindings) error { + + cwd, err := os.Getwd() + if err != nil { + return err + } + projectConfig, err := project.Load(cwd) + if err != nil { + return err + } + + wrapperDir := filepath.Join(projectConfig.WailsJSDir, "wailsjs", "runtime") + _ = os.RemoveAll(wrapperDir) + extractor := gosod.New(wrapper.RuntimeWrapper) + err = extractor.Extract(wrapperDir, nil) + if err != nil { + return err + } + + //ipcdev.js + err = os.WriteFile(filepath.Join(wrapperDir, "ipcdev.js"), wailsRuntime.DesktopIPC, 0755) + if err != nil { + return err + } + //runtimedev.js + err = os.WriteFile(filepath.Join(wrapperDir, "runtimedev.js"), wailsRuntime.RuntimeDesktopJS, 0755) + if err != nil { + return err + } + + targetDir := filepath.Join(projectConfig.WailsJSDir, "wailsjs", "go") + err = os.RemoveAll(targetDir) + if err != nil { + return err + } + _ = fs.MkDirs(targetDir) + + modelsFile := filepath.Join(targetDir, "models.ts") + err = bindings.WriteTS(modelsFile) + if err != nil { + return err + } + + // Write backend method wrappers + bindingsFilename := filepath.Join(targetDir, "bindings.js") + err = bindings.GenerateBackendJS(bindingsFilename, true) + if err != nil { + return err + } + + return nil + +} diff --git a/v2/internal/appng/app_darwin.go b/v2/internal/appng/app_darwin.go new file mode 100644 index 000000000..b6f5a16a4 --- /dev/null +++ b/v2/internal/appng/app_darwin.go @@ -0,0 +1,15 @@ +//go:build darwin && !bindings + +package appng + +import ( + "github.com/wailsapp/wails/v2/internal/logger" + "github.com/wailsapp/wails/v2/pkg/options" +) + +func PreflightChecks(options *options.App, logger *logger.Logger) error { + + _ = options + + return nil +} diff --git a/v2/internal/appng/app_default_darwin.go b/v2/internal/appng/app_default_darwin.go new file mode 100644 index 000000000..f0971f864 --- /dev/null +++ b/v2/internal/appng/app_default_darwin.go @@ -0,0 +1,32 @@ +//go:build !dev && !production && !bindings && darwin + +package appng + +import ( + "fmt" + + "github.com/wailsapp/wails/v2/pkg/options" +) + +// App defines a Wails application structure +type App struct{} + +func (a *App) Run() error { + return nil +} + +// CreateApp creates the app! +func CreateApp(_ *options.App) (*App, error) { + // result := w32.MessageBox(0, + // `Wails applications will not build without the correct build tags. + //Please use "wails build" or press "OK" to open the documentation on how to use "go build"`, + // "Error", + // w32.MB_ICONERROR|w32.MB_OKCANCEL) + // if result == 1 { + // exec.Command("rundll32", "url.dll,FileProtocolHandler", "https://wails.io").Start() + // } + + err := fmt.Errorf(`Wails applications will not build without the correct build tags.`) + + return nil, err +} diff --git a/v2/internal/app/app_default_windows.go b/v2/internal/appng/app_default_windows.go similarity index 85% rename from v2/internal/app/app_default_windows.go rename to v2/internal/appng/app_default_windows.go index b1b66a081..64ac79aa7 100644 --- a/v2/internal/app/app_default_windows.go +++ b/v2/internal/appng/app_default_windows.go @@ -1,14 +1,17 @@ //go:build !dev && !production && !bindings && windows -package app +package appng import ( "os/exec" - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" + "github.com/leaanthony/winc/w32" "github.com/wailsapp/wails/v2/pkg/options" ) +// App defines a Wails application structure +type App struct{} + func (a *App) Run() error { return nil } diff --git a/v2/internal/appng/app_dev.go b/v2/internal/appng/app_dev.go new file mode 100644 index 000000000..cc463bb88 --- /dev/null +++ b/v2/internal/appng/app_dev.go @@ -0,0 +1,171 @@ +//go:build dev +// +build dev + +package appng + +import ( + "context" + "flag" + "github.com/wailsapp/wails/v2/internal/binding" + "github.com/wailsapp/wails/v2/internal/frontend" + "github.com/wailsapp/wails/v2/internal/frontend/desktop" + "github.com/wailsapp/wails/v2/internal/frontend/devserver" + "github.com/wailsapp/wails/v2/internal/frontend/dispatcher" + "github.com/wailsapp/wails/v2/internal/frontend/runtime" + "github.com/wailsapp/wails/v2/internal/fs" + "github.com/wailsapp/wails/v2/internal/logger" + "github.com/wailsapp/wails/v2/internal/menumanager" + "github.com/wailsapp/wails/v2/internal/project" + "github.com/wailsapp/wails/v2/internal/signal" + pkglogger "github.com/wailsapp/wails/v2/pkg/logger" + "github.com/wailsapp/wails/v2/pkg/options" + "os" + "path/filepath" +) + +// App defines a Wails application structure +type App struct { + frontend frontend.Frontend + logger *logger.Logger + signal *signal.Manager + options *options.App + + menuManager *menumanager.Manager + + // Indicates if the app is in debug mode + debug bool + + // OnStartup/OnShutdown + startupCallback func(ctx context.Context) + shutdownCallback func(ctx context.Context) + ctx context.Context +} + +func (a *App) Run() error { + err := a.frontend.Run(a.ctx) + if a.shutdownCallback != nil { + a.shutdownCallback(a.ctx) + } + return err +} + +// CreateApp creates the app! +func CreateApp(appoptions *options.App) (*App, error) { + var err error + + ctx := context.WithValue(context.Background(), "debug", true) + + // Set up logger + myLogger := logger.New(appoptions.Logger) + myLogger.SetLogLevel(appoptions.LogLevel) + + // Check for CLI Flags + assetdir := flag.String("assetdir", "", "Directory to serve assets") + devServerURL := flag.String("devserverurl", "", "URL of development server") + loglevel := flag.String("loglevel", "debug", "Loglevel to use - Trace, Debug, Info, Warning, Error") + flag.Parse() + if devServerURL != nil && *devServerURL != "" { + ctx = context.WithValue(ctx, "devserverurl", *devServerURL) + } + if assetdir != nil && *assetdir != "" { + ctx = context.WithValue(ctx, "assetdir", *assetdir) + } + + if loglevel != nil && *loglevel != "" { + level, err := pkglogger.StringToLogLevel(*loglevel) + if err != nil { + return nil, err + } + myLogger.SetLogLevel(level) + } + + // Attach logger to context + ctx = context.WithValue(ctx, "logger", myLogger) + + // Preflight checks + err = PreflightChecks(appoptions, myLogger) + if err != nil { + return nil, err + } + + // Merge default options + options.MergeDefaults(appoptions) + + var menuManager *menumanager.Manager + + // Process the application menu + if appoptions.Menu != nil { + // Create the menu manager + menuManager = menumanager.NewManager() + err = menuManager.SetApplicationMenu(appoptions.Menu) + if err != nil { + return nil, err + } + } + + // Create binding exemptions - Ugly hack. There must be a better way + bindingExemptions := []interface{}{appoptions.OnStartup, appoptions.OnShutdown, appoptions.OnDomReady} + appBindings := binding.NewBindings(myLogger, appoptions.Bind, bindingExemptions) + + err = generateBindings(appBindings) + if err != nil { + return nil, err + } + eventHandler := runtime.NewEvents(myLogger) + ctx = context.WithValue(ctx, "events", eventHandler) + messageDispatcher := dispatcher.NewDispatcher(myLogger, appBindings, eventHandler) + + // Create the frontends and register to event handler + desktopFrontend := desktop.NewFrontend(ctx, appoptions, myLogger, appBindings, messageDispatcher) + appFrontend := devserver.NewFrontend(ctx, appoptions, myLogger, appBindings, messageDispatcher, menuManager, desktopFrontend) + eventHandler.AddFrontend(appFrontend) + eventHandler.AddFrontend(desktopFrontend) + + result := &App{ + ctx: ctx, + frontend: appFrontend, + logger: myLogger, + menuManager: menuManager, + startupCallback: appoptions.OnStartup, + shutdownCallback: appoptions.OnShutdown, + debug: true, + } + + result.options = appoptions + + return result, nil + +} + +func generateBindings(bindings *binding.Bindings) error { + + cwd, err := os.Getwd() + if err != nil { + return err + } + projectConfig, err := project.Load(cwd) + if err != nil { + return err + } + + targetDir := filepath.Join(projectConfig.WailsJSDir, "wailsjs", "go") + err = os.RemoveAll(targetDir) + if err != nil { + return err + } + _ = fs.MkDirs(targetDir) + modelsFile := filepath.Join(targetDir, "models.ts") + err = bindings.WriteTS(modelsFile) + if err != nil { + return err + } + + // Write backend method wrappers + bindingsFilename := filepath.Join(targetDir, "bindings.js") + err = bindings.GenerateBackendJS(bindingsFilename, false) + if err != nil { + return err + } + return nil + +} diff --git a/v2/internal/appng/app_production.go b/v2/internal/appng/app_production.go new file mode 100644 index 000000000..7e404d359 --- /dev/null +++ b/v2/internal/appng/app_production.go @@ -0,0 +1,101 @@ +//go:build production +// +build production + +package appng + +import ( + "context" + "github.com/wailsapp/wails/v2/internal/binding" + "github.com/wailsapp/wails/v2/internal/frontend" + "github.com/wailsapp/wails/v2/internal/frontend/desktop" + "github.com/wailsapp/wails/v2/internal/frontend/dispatcher" + "github.com/wailsapp/wails/v2/internal/frontend/runtime" + "github.com/wailsapp/wails/v2/internal/logger" + "github.com/wailsapp/wails/v2/internal/menumanager" + "github.com/wailsapp/wails/v2/internal/signal" + "github.com/wailsapp/wails/v2/pkg/options" +) + +// App defines a Wails application structure +type App struct { + frontend frontend.Frontend + logger *logger.Logger + signal *signal.Manager + options *options.App + + menuManager *menumanager.Manager + + // Indicates if the app is in debug mode + debug bool + + // OnStartup/OnShutdown + startupCallback func(ctx context.Context) + shutdownCallback func(ctx context.Context) + ctx context.Context +} + +func (a *App) Run() error { + err := a.frontend.Run(a.ctx) + if a.shutdownCallback != nil { + a.shutdownCallback(a.ctx) + } + return err +} + +// CreateApp creates the app! +func CreateApp(appoptions *options.App) (*App, error) { + var err error + + ctx := context.Background() + + // Merge default options + options.MergeDefaults(appoptions) + + // Set up logger + myLogger := logger.New(appoptions.Logger) + myLogger.SetLogLevel(appoptions.LogLevel) + + // Preflight Checks + err = PreflightChecks(appoptions, myLogger) + if err != nil { + return nil, err + } + + // Create the menu manager + menuManager := menumanager.NewManager() + + // Process the application menu + if appoptions.Menu != nil { + err = menuManager.SetApplicationMenu(appoptions.Menu) + if err != nil { + return nil, err + } + } + + // Create binding exemptions - Ugly hack. There must be a better way + bindingExemptions := []interface{}{appoptions.OnStartup, appoptions.OnShutdown, appoptions.OnDomReady} + appBindings := binding.NewBindings(myLogger, appoptions.Bind, bindingExemptions) + eventHandler := runtime.NewEvents(myLogger) + ctx = context.WithValue(ctx, "events", eventHandler) + messageDispatcher := dispatcher.NewDispatcher(myLogger, appBindings, eventHandler) + + appFrontend := desktop.NewFrontend(ctx, appoptions, myLogger, appBindings, messageDispatcher) + eventHandler.AddFrontend(appFrontend) + + result := &App{ + ctx: ctx, + frontend: appFrontend, + logger: myLogger, + menuManager: menuManager, + startupCallback: appoptions.OnStartup, + shutdownCallback: appoptions.OnShutdown, + debug: false, + } + + result.options = appoptions + + result.ctx = context.WithValue(result.ctx, "debug", result.debug) + + return result, nil + +} diff --git a/v2/internal/appng/app_windows.go b/v2/internal/appng/app_windows.go new file mode 100644 index 000000000..644cd728e --- /dev/null +++ b/v2/internal/appng/app_windows.go @@ -0,0 +1,27 @@ +//go:build windows && !bindings + +package appng + +import ( + "github.com/wailsapp/wails/v2/internal/ffenestri/windows/wv2runtime" + "github.com/wailsapp/wails/v2/internal/logger" + "github.com/wailsapp/wails/v2/pkg/options" +) + +func PreflightChecks(options *options.App, logger *logger.Logger) error { + + _ = options + + // Process the webview2 runtime situation. We can pass a strategy in via the `webview2` flag for `wails build`. + // This will determine how wv2runtime.Process will handle a lack of valid runtime. + installedVersion, err := wv2runtime.Process() + if installedVersion != nil { + logger.Debug("WebView2 Runtime installed: Name: '%s' Version:'%s' Location:'%s'. Minimum version required: %s.", + installedVersion.Name, installedVersion.Version, installedVersion.Location, wv2runtime.MinimumRuntimeVersion) + } + if err != nil { + return err + } + + return nil +} diff --git a/v2/internal/assetdb/assetdb.go b/v2/internal/assetdb/assetdb.go new file mode 100644 index 000000000..54892952e --- /dev/null +++ b/v2/internal/assetdb/assetdb.go @@ -0,0 +1,112 @@ +package assetdb + +import ( + "fmt" + "strings" + "unsafe" +) + +// AssetDB is a database for assets encoded as byte slices +type AssetDB struct { + db map[string][]byte +} + +// NewAssetDB creates a new AssetDB and initialises a blank db +func NewAssetDB() *AssetDB { + return &AssetDB{ + db: make(map[string][]byte), + } +} + +// AddAsset saves the given byte slice under the given name +func (a *AssetDB) AddAsset(name string, data []byte) { + a.db[name] = data +} + +// Remove removes the named asset +func (a *AssetDB) Remove(name string) { + delete(a.db, name) +} + +// Asset retrieves the byte slice for the given name +func (a *AssetDB) Read(name string) ([]byte, error) { + result := a.db[name] + if result == nil { + return nil, fmt.Errorf("asset '%s' not found", name) + } + return result, nil +} + +// AssetAsString returns the asset as a string. +// It also returns a boolean indicating whether the asset existed or not. +func (a *AssetDB) String(name string) (string, error) { + asset, err := a.Read(name) + if err != nil { + return "", err + } + return *(*string)(unsafe.Pointer(&asset)), nil +} + +func (a *AssetDB) Dump() { + fmt.Printf("Assets:\n") + for k, _ := range a.db { + fmt.Println(k) + } +} + +// Serialize converts the entire database to a file that when compiled will +// reconstruct the AssetDB during init() +// name: name of the asset.AssetDB instance +// pkg: package name placed at the top of the file +func (a *AssetDB) Serialize(name, pkg string) string { + var cdata strings.Builder + // Set buffer size to 4k + cdata.Grow(4096) + + // Write header + header := `// DO NOT EDIT - Generated automatically +package %s + +import "github.com/wailsapp/wails/v2/internal/assetdb" + +var ( + %s *assetdb.AssetDB = assetdb.NewAssetDB() +) + +// AssetsDB is a clean interface to the assetdb.AssetDB struct +type AssetsDB interface { + Read(string) ([]byte, error) + String(string) (string, error) +} + +// Assets returns the asset database +func Assets() AssetsDB { + return %s +} + +func init() { +` + cdata.WriteString(fmt.Sprintf(header, pkg, name, name)) + + for aname, bytes := range a.db { + cdata.WriteString(fmt.Sprintf("\t%s.AddAsset(\"%s\", []byte{", + name, + aname)) + + l := len(bytes) + if l == 0 { + cdata.WriteString("0x00})\n") + continue + } + + // Convert each byte to hex + for _, b := range bytes[:l-1] { + cdata.WriteString(fmt.Sprintf("0x%x, ", b)) + } + cdata.WriteString(fmt.Sprintf("0x%x})\n", bytes[l-1])) + } + + cdata.WriteString(`}`) + + return cdata.String() +} diff --git a/v2/internal/assetdb/assetdb_test.go b/v2/internal/assetdb/assetdb_test.go new file mode 100644 index 000000000..b3f34b9fd --- /dev/null +++ b/v2/internal/assetdb/assetdb_test.go @@ -0,0 +1,70 @@ +package assetdb + +import "testing" +import "github.com/matryer/is" + +func TestExistsAsBytes(t *testing.T) { + + is := is.New(t) + + var helloworld = []byte{72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33} + + db := NewAssetDB() + db.AddAsset("hello", helloworld) + + result, err := db.Read("hello") + + is.True(err == nil) + is.Equal(result, helloworld) +} + +func TestNotExistsAsBytes(t *testing.T) { + + is := is.New(t) + + var helloworld = []byte{72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33} + + db := NewAssetDB() + db.AddAsset("hello4", helloworld) + + result, err := db.Read("hello") + + is.True(err != nil) + is.True(result == nil) +} + +func TestExistsAsString(t *testing.T) { + + is := is.New(t) + + var helloworld = []byte{72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33} + + db := NewAssetDB() + db.AddAsset("hello", helloworld) + + result, err := db.String("hello") + + // Ensure it exists + is.True(err == nil) + + // Ensure the string is the same as the byte slice + is.Equal(result, "Hello, World!") +} + +func TestNotExistsAsString(t *testing.T) { + + is := is.New(t) + + var helloworld = []byte{72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33} + + db := NewAssetDB() + db.AddAsset("hello", helloworld) + + result, err := db.String("help") + + // Ensure it doesn't exist + is.True(err != nil) + + // Ensure the string is blank + is.Equal(result, "") +} diff --git a/v2/internal/assetdb/filesystem.go b/v2/internal/assetdb/filesystem.go new file mode 100644 index 000000000..48acb713f --- /dev/null +++ b/v2/internal/assetdb/filesystem.go @@ -0,0 +1,176 @@ +// +build !desktop +package assetdb + +import ( + "errors" + "io" + "net/http" + "os" + "path" + "sort" + "strings" + "time" +) + +var errWhence = errors.New("Seek: invalid whence") +var errOffset = errors.New("Seek: invalid offset") + +// Open implements the http.FileSystem interface for the AssetDB +func (a *AssetDB) Open(name string) (http.File, error) { + if name == "/" || name == "" { + return &Entry{name: "/", dir: true, db: a}, nil + } + + if data, ok := a.db[name]; ok { + return &Entry{name: name, data: data, size: len(data)}, nil + } else { + for n, _ := range a.db { + if strings.HasPrefix(n, name+"/") { + return &Entry{name: name, db: a, dir: true}, nil + } + } + } + return &Entry{}, os.ErrNotExist +} + +// readdir returns the directory entries for the requested directory +func (a *AssetDB) readdir(name string) ([]os.FileInfo, error) { + dir := name + var ents []string + + fim := make(map[string]os.FileInfo) + for fn, data := range a.db { + if strings.HasPrefix(fn, dir) { + pieces := strings.Split(fn[len(dir)+1:], "/") + if len(pieces) == 1 { + fim[pieces[0]] = FI{name: pieces[0], dir: false, size: len(data)} + ents = append(ents, pieces[0]) + } else { + fim[pieces[0]] = FI{name: pieces[0], dir: true, size: -1} + ents = append(ents, pieces[0]) + } + } + } + + if len(ents) == 0 { + return nil, os.ErrNotExist + } + + sort.Strings(ents) + var list []os.FileInfo + for _, dir := range ents { + list = append(list, fim[dir]) + } + return list, nil +} + +// Entry implements the http.File interface to allow for +// use in the http.FileSystem implementation of AssetDB +type Entry struct { + name string + data []byte + dir bool + size int + db *AssetDB + off int +} + +// Close is a noop +func (e Entry) Close() error { + return nil +} + +// Read fills the slice provided returning how many bytes were written +// and any errors encountered +func (e *Entry) Read(p []byte) (n int, err error) { + if e.off >= e.size { + return 0, io.EOF + } + numout := len(p) + if numout > e.size { + numout = e.size + } + for i := 0; i < numout; i++ { + p[i] = e.data[e.off+i] + } + e.off += numout + n = int(numout) + err = nil + return +} + +// Seek seeks to the specified offset from the location specified by whence +func (e *Entry) Seek(offset int64, whence int) (int64, error) { + switch whence { + default: + return 0, errWhence + case io.SeekStart: + offset += 0 + case io.SeekCurrent: + offset += int64(e.off) + case io.SeekEnd: + offset += int64(e.size) + } + + if offset < 0 { + return 0, errOffset + } + e.off = int(offset) + return offset, nil +} + +// Readdir returns the directory entries inside this entry if it is a directory +func (e Entry) Readdir(count int) ([]os.FileInfo, error) { + ents := []os.FileInfo{} + if !e.dir { + return ents, errors.New("Not a directory") + } + return e.db.readdir(e.name) +} + +// Stat returns information about this directory entry +func (e Entry) Stat() (os.FileInfo, error) { + return FI{e.name, e.size, e.dir}, nil +} + +// FI is the AssetDB implementation of os.FileInfo. +type FI struct { + name string + size int + dir bool +} + +// IsDir returns true if this is a directory +func (fi FI) IsDir() bool { + return fi.dir +} + +// ModTime always returns now +func (fi FI) ModTime() time.Time { + return time.Time{} +} + +// Mode returns the file as readonly and directories +// as world writeable and executable +func (fi FI) Mode() os.FileMode { + if fi.IsDir() { + return 0755 | os.ModeDir + } + return 0444 +} + +// Name returns the name of this object without +// any leading slashes +func (fi FI) Name() string { + return path.Base(fi.name) +} + +// Size returns the size of this item +func (fi FI) Size() int64 { + return int64(fi.size) +} + +// Sys returns nil +func (fi FI) Sys() interface{} { + return nil +} diff --git a/v2/internal/assetdb/filesystem_test.go b/v2/internal/assetdb/filesystem_test.go new file mode 100644 index 000000000..1c2ed94a4 --- /dev/null +++ b/v2/internal/assetdb/filesystem_test.go @@ -0,0 +1,108 @@ +package assetdb + +import ( + "fmt" + "os" + "testing" + + "github.com/matryer/is" +) + +func TestOpenLeadingSlash(t *testing.T) { + is := is.New(t) + + var helloworld = []byte{72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33} + + db := NewAssetDB() + db.AddAsset("/hello", helloworld) + + file, err := db.Open("/hello") + // Ensure it does exist + is.True(err == nil) + + buff := make([]byte, len(helloworld)) + n, err := file.Read(buff) + fmt.Printf("Error %v\n", err) + is.True(err == nil) + is.Equal(n, len(helloworld)) + result := string(buff) + + // Ensure the string is blank + is.Equal(result, string(helloworld)) +} + +func TestOpen(t *testing.T) { + is := is.New(t) + + var helloworld = []byte{72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33} + + db := NewAssetDB() + db.AddAsset("/hello", helloworld) + + file, err := db.Open("/hello") + + // Ensure it does exist + is.True(err == nil) + + buff := make([]byte, len(helloworld)) + n, err := file.Read(buff) + is.True(err == nil) + is.Equal(n, len(helloworld)) + result := string(buff) + + // Ensure the string is blank + is.Equal(result, string(helloworld)) +} + +func TestReaddir(t *testing.T) { + is := is.New(t) + + var helloworld = []byte{72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33} + + db := NewAssetDB() + db.AddAsset("/hello", helloworld) + db.AddAsset("/directory/hello", helloworld) + db.AddAsset("/directory/subdirectory/hello", helloworld) + + dir, err := db.Open("/doesntexist") + is.True(err == os.ErrNotExist) + ents, err := dir.Readdir(-1) + is.Equal([]os.FileInfo{}, ents) + + dir, err = db.Open("/") + is.True(dir != nil) + is.True(err == nil) + ents, err = dir.Readdir(-1) + is.True(err == nil) + is.Equal(3, len(ents)) +} + +func TestReaddirSubdirectory(t *testing.T) { + is := is.New(t) + + var helloworld = []byte{72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33} + + db := NewAssetDB() + db.AddAsset("/hello", helloworld) + db.AddAsset("/directory/hello", helloworld) + db.AddAsset("/directory/subdirectory/hello", helloworld) + + expected := []os.FileInfo{ + FI{name: "hello", dir: false, size: len(helloworld)}, + FI{name: "subdirectory", dir: true, size: -1}, + } + + dir, err := db.Open("/directory") + is.True(dir != nil) + is.True(err == nil) + ents, err := dir.Readdir(-1) + is.Equal(expected, ents) + + // Check sub-subdirectory + dir, err = db.Open("/directory/subdirectory") + is.True(dir != nil) + is.True(err == nil) + ents, err = dir.Readdir(-1) + is.True(err == nil) + is.Equal([]os.FileInfo{FI{name: "hello", size: len(helloworld)}}, ents) +} diff --git a/v2/internal/bind/bind.go b/v2/internal/bind/bind.go new file mode 100644 index 000000000..156fd4ce4 --- /dev/null +++ b/v2/internal/bind/bind.go @@ -0,0 +1,9 @@ +package bind + +func IsStructPointer(value interface{}) bool { + switch t := value.(type) { + default: + println(t) + } + return false +} diff --git a/v2/internal/binding/assets/package.json b/v2/internal/binding/assets/package.json new file mode 100644 index 000000000..1b82716c0 --- /dev/null +++ b/v2/internal/binding/assets/package.json @@ -0,0 +1,10 @@ +{ + "name": "go", + "version": "1.0.0", + "description": "Package to wrap your bound go methods", + "main": "bindings.js", + "types": "bindings.d.ts", + "scripts": {}, + "author": "", + "license": "ISC" +} \ No newline at end of file diff --git a/v2/internal/binding/binding.go b/v2/internal/binding/binding.go old mode 100644 new mode 100755 index b7bf07ae0..ef33d858f --- a/v2/internal/binding/binding.go +++ b/v2/internal/binding/binding.go @@ -1,20 +1,13 @@ package binding import ( - "bufio" - "bytes" "fmt" - "os" - "path/filepath" + "github.com/leaanthony/typescriptify-golang-structs/typescriptify" "reflect" "runtime" - "sort" "strings" - "github.com/wailsapp/wails/v2/internal/typescriptify" - "github.com/leaanthony/slicer" - "github.com/wailsapp/wails/v2/internal/logger" ) @@ -23,26 +16,26 @@ type Bindings struct { logger logger.CustomLogger exemptions slicer.StringSlicer - structsToGenerateTS map[string]map[string]interface{} - enumsToGenerateTS map[string]map[string]interface{} - tsPrefix string - tsSuffix string - tsInterface bool - obfuscate bool + // Typescript writer + converter *typescriptify.TypeScriptify } // NewBindings returns a new Bindings object -func NewBindings(logger *logger.Logger, structPointersToBind []interface{}, exemptions []interface{}, obfuscate bool, enumsToBind []interface{}) *Bindings { +func NewBindings(logger *logger.Logger, structPointersToBind []interface{}, exemptions []interface{}) *Bindings { result := &Bindings{ - db: newDB(), - logger: logger.CustomLogger("Bindings"), - structsToGenerateTS: make(map[string]map[string]interface{}), - enumsToGenerateTS: make(map[string]map[string]interface{}), - obfuscate: obfuscate, + db: newDB(), + logger: logger.CustomLogger("Bindings"), + converter: typescriptify.New(), } + // No backups + result.converter.WithBackupDir("") + + // Hack for TS compilation error + result.converter.AddImport("export {};") + for _, exemption := range exemptions { - if exemption == nil { + if exemptions == nil { continue } name := runtime.FuncForPC(reflect.ValueOf(exemption).Pointer()).Name() @@ -51,10 +44,6 @@ func NewBindings(logger *logger.Logger, structPointersToBind []interface{}, exem result.exemptions.Add(name) } - for _, enum := range enumsToBind { - result.AddEnumToGenerateTS(enum) - } - // Add the structs to bind for _, ptr := range structPointersToBind { err := result.Add(ptr) @@ -68,17 +57,28 @@ func NewBindings(logger *logger.Logger, structPointersToBind []interface{}, exem // Add the given struct methods to the Bindings func (b *Bindings) Add(structPtr interface{}) error { + methods, err := b.getMethods(structPtr) if err != nil { return fmt.Errorf("cannot bind value to app: %s", err.Error()) } for _, method := range methods { - b.db.AddMethod(method.Path.Package, method.Path.Struct, method.Path.Name, method) + splitName := strings.Split(method.Name, ".") + packageName := splitName[0] + structName := splitName[1] + methodName := splitName[2] + + // Add it as a regular method + b.db.AddMethod(packageName, structName, methodName, method) } return nil } +func (b *Bindings) WriteTS(filename string) error { + return b.converter.ConvertToFile(filename) +} + func (b *Bindings) DB() *DB { return b.db } @@ -86,299 +86,3 @@ func (b *Bindings) DB() *DB { func (b *Bindings) ToJSON() (string, error) { return b.db.ToJSON() } - -func (b *Bindings) GenerateModels() ([]byte, error) { - models := map[string]string{} - var seen slicer.StringSlicer - var seenEnumsPackages slicer.StringSlicer - allStructNames := b.getAllStructNames() - allStructNames.Sort() - allEnumNames := b.getAllEnumNames() - allEnumNames.Sort() - for packageName, structsToGenerate := range b.structsToGenerateTS { - thisPackageCode := "" - w := typescriptify.New() - w.WithPrefix(b.tsPrefix) - w.WithSuffix(b.tsSuffix) - w.WithInterface(b.tsInterface) - w.Namespace = packageName - w.WithBackupDir("") - w.KnownStructs = allStructNames - w.KnownEnums = allEnumNames - // sort the structs - var structNames []string - for structName := range structsToGenerate { - structNames = append(structNames, structName) - } - sort.Strings(structNames) - for _, structName := range structNames { - fqstructname := packageName + "." + structName - if seen.Contains(fqstructname) { - continue - } - structInterface := structsToGenerate[structName] - w.Add(structInterface) - } - - // if we have enums for this package, add them as well - var enums, enumsExist = b.enumsToGenerateTS[packageName] - if enumsExist { - // Sort the enum names first to make the output deterministic - sortedEnumNames := make([]string, 0, len(enums)) - for enumName := range enums { - sortedEnumNames = append(sortedEnumNames, enumName) - } - sort.Strings(sortedEnumNames) - - for _, enumName := range sortedEnumNames { - enum := enums[enumName] - fqemumname := packageName + "." + enumName - if seen.Contains(fqemumname) { - continue - } - w.AddEnum(enum) - } - seenEnumsPackages.Add(packageName) - } - - str, err := w.Convert(nil) - if err != nil { - return nil, err - } - thisPackageCode += str - seen.AddSlice(w.GetGeneratedStructs()) - models[packageName] = thisPackageCode - } - - // Add outstanding enums to the models that were not in packages with structs - for packageName, enumsToGenerate := range b.enumsToGenerateTS { - if seenEnumsPackages.Contains(packageName) { - continue - } - - thisPackageCode := "" - w := typescriptify.New() - w.WithPrefix(b.tsPrefix) - w.WithSuffix(b.tsSuffix) - w.WithInterface(b.tsInterface) - w.Namespace = packageName - w.WithBackupDir("") - - for enumName, enum := range enumsToGenerate { - fqemumname := packageName + "." + enumName - if seen.Contains(fqemumname) { - continue - } - w.AddEnum(enum) - } - str, err := w.Convert(nil) - if err != nil { - return nil, err - } - thisPackageCode += str - models[packageName] = thisPackageCode - } - - // Sort the package names first to make the output deterministic - sortedPackageNames := make([]string, 0, len(models)) - for packageName := range models { - sortedPackageNames = append(sortedPackageNames, packageName) - } - sort.Strings(sortedPackageNames) - - var modelsData bytes.Buffer - for _, packageName := range sortedPackageNames { - modelData := models[packageName] - if strings.TrimSpace(modelData) == "" { - continue - } - modelsData.WriteString("export namespace " + packageName + " {\n") - sc := bufio.NewScanner(strings.NewReader(modelData)) - for sc.Scan() { - modelsData.WriteString("\t" + sc.Text() + "\n") - } - modelsData.WriteString("\n}\n\n") - } - return modelsData.Bytes(), nil -} - -func (b *Bindings) WriteModels(modelsDir string) error { - modelsData, err := b.GenerateModels() - if err != nil { - return err - } - // Don't write if we don't have anything - if len(modelsData) == 0 { - return nil - } - - filename := filepath.Join(modelsDir, "models.ts") - err = os.WriteFile(filename, modelsData, 0o755) - if err != nil { - return err - } - - return nil -} - -func (b *Bindings) AddEnumToGenerateTS(e interface{}) { - enumType := reflect.TypeOf(e) - - var packageName string - var enumName string - // enums should be represented as array of all possible values - if hasElements(enumType) { - enum := enumType.Elem() - // simple enum represented by struct with Value/TSName fields - if enum.Kind() == reflect.Struct { - _, tsNamePresented := enum.FieldByName("TSName") - enumT, valuePresented := enum.FieldByName("Value") - if tsNamePresented && valuePresented { - packageName = getPackageName(enumT.Type.String()) - enumName = enumT.Type.Name() - } else { - return - } - // otherwise expecting implementation with TSName() https://github.com/tkrajina/typescriptify-golang-structs#enums-with-tsname - } else { - packageName = getPackageName(enumType.Elem().String()) - enumName = enumType.Elem().Name() - } - if b.enumsToGenerateTS[packageName] == nil { - b.enumsToGenerateTS[packageName] = make(map[string]interface{}) - } - if b.enumsToGenerateTS[packageName][enumName] != nil { - return - } - b.enumsToGenerateTS[packageName][enumName] = e - } -} - -func (b *Bindings) AddStructToGenerateTS(packageName string, structName string, s interface{}) { - if b.structsToGenerateTS[packageName] == nil { - b.structsToGenerateTS[packageName] = make(map[string]interface{}) - } - if b.structsToGenerateTS[packageName][structName] != nil { - return - } - b.structsToGenerateTS[packageName][structName] = s - - // Iterate this struct and add any struct field references - structType := reflect.TypeOf(s) - for hasElements(structType) { - structType = structType.Elem() - } - - for i := 0; i < structType.NumField(); i++ { - field := structType.Field(i) - if field.Anonymous || !field.IsExported() { - continue - } - kind := field.Type.Kind() - if kind == reflect.Struct { - fqname := field.Type.String() - sNameSplit := strings.SplitN(fqname, ".", 2) - if len(sNameSplit) < 2 { - continue - } - sName := sNameSplit[1] - pName := getPackageName(fqname) - a := reflect.New(field.Type) - if b.hasExportedJSONFields(field.Type) { - s := reflect.Indirect(a).Interface() - b.AddStructToGenerateTS(pName, sName, s) - } - } else { - fType := field.Type - for hasElements(fType) { - fType = fType.Elem() - } - if fType.Kind() == reflect.Struct { - fqname := fType.String() - sNameSplit := strings.SplitN(fqname, ".", 2) - if len(sNameSplit) < 2 { - continue - } - sName := sNameSplit[1] - pName := getPackageName(fqname) - a := reflect.New(fType) - if b.hasExportedJSONFields(fType) { - s := reflect.Indirect(a).Interface() - b.AddStructToGenerateTS(pName, sName, s) - } - } - } - } -} - -func (b *Bindings) SetTsPrefix(prefix string) *Bindings { - b.tsPrefix = prefix - return b -} - -func (b *Bindings) SetTsSuffix(postfix string) *Bindings { - b.tsSuffix = postfix - return b -} - -func (b *Bindings) SetOutputType(outputType string) *Bindings { - if outputType == "interfaces" { - b.tsInterface = true - } - return b -} - -func (b *Bindings) getAllStructNames() *slicer.StringSlicer { - var result slicer.StringSlicer - for packageName, structsToGenerate := range b.structsToGenerateTS { - for structName := range structsToGenerate { - result.Add(packageName + "." + structName) - } - } - return &result -} - -func (b *Bindings) getAllEnumNames() *slicer.StringSlicer { - var result slicer.StringSlicer - for packageName, enumsToGenerate := range b.enumsToGenerateTS { - for enumName := range enumsToGenerate { - result.Add(packageName + "." + enumName) - } - } - return &result -} - -func (b *Bindings) hasExportedJSONFields(typeOf reflect.Type) bool { - for i := 0; i < typeOf.NumField(); i++ { - jsonFieldName := "" - f := typeOf.Field(i) - // function, complex, and channel types cannot be json-encoded - if f.Type.Kind() == reflect.Chan || - f.Type.Kind() == reflect.Func || - f.Type.Kind() == reflect.UnsafePointer || - f.Type.Kind() == reflect.Complex128 || - f.Type.Kind() == reflect.Complex64 { - continue - } - jsonTag, hasTag := f.Tag.Lookup("json") - if !hasTag && f.IsExported() { - return true - } - if len(jsonTag) == 0 { - continue - } - jsonTagParts := strings.Split(jsonTag, ",") - if len(jsonTagParts) > 0 { - jsonFieldName = jsonTagParts[0] - } - for _, t := range jsonTagParts { - if t == "-" { - continue - } - } - if jsonFieldName != "" { - return true - } - } - return false -} diff --git a/v2/internal/binding/binding_test/binding_anonymous_sub_struct_multi_level_test.go b/v2/internal/binding/binding_test/binding_anonymous_sub_struct_multi_level_test.go deleted file mode 100644 index 29777481b..000000000 --- a/v2/internal/binding/binding_test/binding_anonymous_sub_struct_multi_level_test.go +++ /dev/null @@ -1,65 +0,0 @@ -package binding_test - -type StructWithAnonymousSubMultiLevelStruct struct { - Name string `json:"name"` - Meta struct { - Age int `json:"age"` - More struct { - Info string `json:"info"` - MoreInMore struct { - Demo string `json:"demo"` - } `json:"more_in_more"` - } `json:"more"` - } `json:"meta"` -} - -func (s StructWithAnonymousSubMultiLevelStruct) Get() StructWithAnonymousSubMultiLevelStruct { - return s -} - -var AnonymousSubStructMultiLevelTest = BindingTest{ - name: "StructWithAnonymousSubMultiLevelStruct", - structs: []interface{}{ - &StructWithAnonymousSubMultiLevelStruct{}, - }, - exemptions: nil, - shouldError: false, - want: ` -export namespace binding_test { - export class StructWithAnonymousSubMultiLevelStruct { - name: string; - // Go type: struct { Age int "json:\"age\""; More struct { Info string "json:\"info\""; MoreInMore struct { Demo string "json:\"demo\"" } "json:\"more_in_more\"" } "json:\"more\"" } - meta: any; - - static createFrom(source: any = {}) { - return new StructWithAnonymousSubMultiLevelStruct(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.name = source["name"]; - this.meta = this.convertValues(source["meta"], Object); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - -} -`, -} diff --git a/v2/internal/binding/binding_test/binding_anonymous_sub_struct_test.go b/v2/internal/binding/binding_test/binding_anonymous_sub_struct_test.go deleted file mode 100644 index 11afe4f0d..000000000 --- a/v2/internal/binding/binding_test/binding_anonymous_sub_struct_test.go +++ /dev/null @@ -1,59 +0,0 @@ -package binding_test - -type StructWithAnonymousSubStruct struct { - Name string `json:"name"` - Meta struct { - Age int `json:"age"` - } `json:"meta"` -} - -func (s StructWithAnonymousSubStruct) Get() StructWithAnonymousSubStruct { - return s -} - -var AnonymousSubStructTest = BindingTest{ - name: "StructWithAnonymousSubStruct", - structs: []interface{}{ - &StructWithAnonymousSubStruct{}, - }, - exemptions: nil, - shouldError: false, - want: ` -export namespace binding_test { - export class StructWithAnonymousSubStruct { - name: string; - // Go type: struct { Age int "json:\"age\"" } - meta: any; - - static createFrom(source: any = {}) { - return new StructWithAnonymousSubStruct(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.name = source["name"]; - this.meta = this.convertValues(source["meta"], Object); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - -} -`, -} diff --git a/v2/internal/binding/binding_test/binding_conflicting_package_name_test.go b/v2/internal/binding/binding_test/binding_conflicting_package_name_test.go deleted file mode 100644 index b37334ec3..000000000 --- a/v2/internal/binding/binding_test/binding_conflicting_package_name_test.go +++ /dev/null @@ -1,64 +0,0 @@ -package binding_test - -import ( - "io/fs" - "os" - "testing" - - "github.com/wailsapp/wails/v2/internal/binding" - "github.com/wailsapp/wails/v2/internal/binding/binding_test/binding_test_import/float_package" - "github.com/wailsapp/wails/v2/internal/binding/binding_test/binding_test_import/int_package" - "github.com/wailsapp/wails/v2/internal/binding/binding_test/binding_test_import/map_package" - "github.com/wailsapp/wails/v2/internal/binding/binding_test/binding_test_import/uint_package" - "github.com/wailsapp/wails/v2/internal/logger" -) - -const expectedBindings = `// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT -import {float_package} from '../models'; -import {int_package} from '../models'; -import {map_package} from '../models'; -import {uint_package} from '../models'; - -export function StartingWithFloat(arg1:float_package.SomeStruct):Promise; - -export function StartingWithInt(arg1:int_package.SomeStruct):Promise; - -export function StartingWithMap(arg1:map_package.SomeStruct):Promise; - -export function StartingWithUint(arg1:uint_package.SomeStruct):Promise; -` - -type HandlerTest struct{} - -func (h *HandlerTest) StartingWithInt(_ int_package.SomeStruct) {} -func (h *HandlerTest) StartingWithFloat(_ float_package.SomeStruct) {} -func (h *HandlerTest) StartingWithUint(_ uint_package.SomeStruct) {} -func (h *HandlerTest) StartingWithMap(_ map_package.SomeStruct) {} - -func TestConflictingPackageName(t *testing.T) { - // given - generationDir := t.TempDir() - - // setup - testLogger := &logger.Logger{} - b := binding.NewBindings(testLogger, []interface{}{&HandlerTest{}}, []interface{}{}, false, []interface{}{}) - - // then - err := b.GenerateGoBindings(generationDir) - if err != nil { - t.Fatalf("could not generate the Go bindings: %v", err) - } - - // then - rawGeneratedBindings, err := fs.ReadFile(os.DirFS(generationDir), "binding_test/HandlerTest.d.ts") - if err != nil { - t.Fatalf("could not read the generated bindings: %v", err) - } - - // then - generatedBindings := string(rawGeneratedBindings) - if generatedBindings != expectedBindings { - t.Fatalf("the generated bindings does not match the expected ones.\nWanted:\n%s\n\nGot:\n%s", expectedBindings, generatedBindings) - } -} diff --git a/v2/internal/binding/binding_test/binding_deepelements_test.go b/v2/internal/binding/binding_test/binding_deepelements_test.go deleted file mode 100644 index 034687474..000000000 --- a/v2/internal/binding/binding_test/binding_deepelements_test.go +++ /dev/null @@ -1,126 +0,0 @@ -package binding_test - -// Issues 2303, 3442, 3709 - -type DeepMessage struct { - Msg string -} - -type DeepElements struct { - Single []int - Double [][]string - FourDouble [4][]float64 - DoubleFour [][4]int64 - Triple [][][]int - - SingleMap map[string]int - SliceMap map[string][]int - DoubleSliceMap map[string][][]int - - ArrayMap map[string][4]int - DoubleArrayMap1 map[string][4][]int - DoubleArrayMap2 map[string][][4]int - DoubleArrayMap3 map[string][4][4]int - - OneStructs []*DeepMessage - TwoStructs [3][]*DeepMessage - ThreeStructs [][][]DeepMessage - MapStructs map[string][]*DeepMessage - MapTwoStructs map[string][4][]DeepMessage - MapThreeStructs map[string][][7][]*DeepMessage -} - -func (x DeepElements) Get() DeepElements { - return x -} - -var DeepElementsTest = BindingTest{ - name: "DeepElements", - structs: []interface{}{ - &DeepElements{}, - }, - exemptions: nil, - shouldError: false, - want: ` -export namespace binding_test { - - export class DeepMessage { - Msg: string; - - static createFrom(source: any = {}) { - return new DeepMessage(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.Msg = source["Msg"]; - } - } - export class DeepElements { - Single: number[]; - Double: string[][]; - FourDouble: number[][]; - DoubleFour: number[][]; - Triple: number[][][]; - SingleMap: Record; - SliceMap: Record>; - DoubleSliceMap: Record>>; - ArrayMap: Record>; - DoubleArrayMap1: Record>>; - DoubleArrayMap2: Record>>; - DoubleArrayMap3: Record>>; - OneStructs: DeepMessage[]; - TwoStructs: DeepMessage[][]; - ThreeStructs: DeepMessage[][][]; - MapStructs: Record>; - MapTwoStructs: Record>>; - MapThreeStructs: Record>>>; - - static createFrom(source: any = {}) { - return new DeepElements(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.Single = source["Single"]; - this.Double = source["Double"]; - this.FourDouble = source["FourDouble"]; - this.DoubleFour = source["DoubleFour"]; - this.Triple = source["Triple"]; - this.SingleMap = source["SingleMap"]; - this.SliceMap = source["SliceMap"]; - this.DoubleSliceMap = source["DoubleSliceMap"]; - this.ArrayMap = source["ArrayMap"]; - this.DoubleArrayMap1 = source["DoubleArrayMap1"]; - this.DoubleArrayMap2 = source["DoubleArrayMap2"]; - this.DoubleArrayMap3 = source["DoubleArrayMap3"]; - this.OneStructs = this.convertValues(source["OneStructs"], DeepMessage); - this.TwoStructs = this.convertValues(source["TwoStructs"], DeepMessage); - this.ThreeStructs = this.convertValues(source["ThreeStructs"], DeepMessage); - this.MapStructs = this.convertValues(source["MapStructs"], Array, true); - this.MapTwoStructs = this.convertValues(source["MapTwoStructs"], Array>, true); - this.MapThreeStructs = this.convertValues(source["MapThreeStructs"], Array>>, true); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - - } -`, -} diff --git a/v2/internal/binding/binding_test/binding_emptystruct_test.go b/v2/internal/binding/binding_test/binding_emptystruct_test.go deleted file mode 100644 index ffb85e865..000000000 --- a/v2/internal/binding/binding_test/binding_emptystruct_test.go +++ /dev/null @@ -1,53 +0,0 @@ -package binding_test - -type EmptyStruct struct { - Empty struct{} `json:"empty"` -} - -func (s EmptyStruct) Get() EmptyStruct { - return s -} - -var EmptyStructTest = BindingTest{ - name: "EmptyStruct", - structs: []interface{}{ - &EmptyStruct{}, - }, - exemptions: nil, - shouldError: false, - want: ` -export namespace binding_test { - export class EmptyStruct { - // Go type: struct {} - - empty: any; - - static createFrom(source: any = {}) { - return new EmptyStruct(source); - } - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.empty = this.convertValues(source["empty"], Object); - } - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } -} -`, -} diff --git a/v2/internal/binding/binding_test/binding_enum_ordering_test.go b/v2/internal/binding/binding_test/binding_enum_ordering_test.go deleted file mode 100644 index 0939535ec..000000000 --- a/v2/internal/binding/binding_test/binding_enum_ordering_test.go +++ /dev/null @@ -1,271 +0,0 @@ -package binding_test - -// Test for PR #4664: Fix generated enums ordering -// This test ensures that enum output is deterministic regardless of map iteration order - -// ZFirstEnum - named with Z prefix to test alphabetical sorting -type ZFirstEnum int - -const ( - ZFirstEnumValue1 ZFirstEnum = iota - ZFirstEnumValue2 -) - -var AllZFirstEnumValues = []struct { - Value ZFirstEnum - TSName string -}{ - {ZFirstEnumValue1, "ZValue1"}, - {ZFirstEnumValue2, "ZValue2"}, -} - -// ASecondEnum - named with A prefix to test alphabetical sorting -type ASecondEnum int - -const ( - ASecondEnumValue1 ASecondEnum = iota - ASecondEnumValue2 -) - -var AllASecondEnumValues = []struct { - Value ASecondEnum - TSName string -}{ - {ASecondEnumValue1, "AValue1"}, - {ASecondEnumValue2, "AValue2"}, -} - -// MMiddleEnum - named with M prefix to test alphabetical sorting -type MMiddleEnum int - -const ( - MMiddleEnumValue1 MMiddleEnum = iota - MMiddleEnumValue2 -) - -var AllMMiddleEnumValues = []struct { - Value MMiddleEnum - TSName string -}{ - {MMiddleEnumValue1, "MValue1"}, - {MMiddleEnumValue2, "MValue2"}, -} - -type EntityWithMultipleEnums struct { - Name string `json:"name"` - EnumZ ZFirstEnum `json:"enumZ"` - EnumA ASecondEnum `json:"enumA"` - EnumM MMiddleEnum `json:"enumM"` -} - -func (e EntityWithMultipleEnums) Get() EntityWithMultipleEnums { - return e -} - -// EnumOrderingTest tests that multiple enums in the same package are output -// in alphabetical order by enum name. Before PR #4664, the order was -// non-deterministic due to Go map iteration order. -var EnumOrderingTest = BindingTest{ - name: "EnumOrderingTest", - structs: []interface{}{ - &EntityWithMultipleEnums{}, - }, - enums: []interface{}{ - // Intentionally add enums in non-alphabetical order - AllZFirstEnumValues, - AllASecondEnumValues, - AllMMiddleEnumValues, - }, - exemptions: nil, - shouldError: false, - TsGenerationOptionsTest: TsGenerationOptionsTest{ - TsPrefix: "", - TsSuffix: "", - }, - // Expected output should have enums in alphabetical order: ASecondEnum, MMiddleEnum, ZFirstEnum - want: `export namespace binding_test { - - export enum ASecondEnum { - AValue1 = 0, - AValue2 = 1, - } - export enum MMiddleEnum { - MValue1 = 0, - MValue2 = 1, - } - export enum ZFirstEnum { - ZValue1 = 0, - ZValue2 = 1, - } - export class EntityWithMultipleEnums { - name: string; - enumZ: ZFirstEnum; - enumA: ASecondEnum; - enumM: MMiddleEnum; - - static createFrom(source: any = {}) { - return new EntityWithMultipleEnums(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.name = source["name"]; - this.enumZ = source["enumZ"]; - this.enumA = source["enumA"]; - this.enumM = source["enumM"]; - } - } - -} -`, -} - -// EnumElementOrderingEnum tests sorting of enum elements by TSName -type EnumElementOrderingEnum string - -const ( - EnumElementZ EnumElementOrderingEnum = "z_value" - EnumElementA EnumElementOrderingEnum = "a_value" - EnumElementM EnumElementOrderingEnum = "m_value" -) - -// AllEnumElementOrderingValues intentionally lists values out of alphabetical order -// to test that AddEnum sorts them -var AllEnumElementOrderingValues = []struct { - Value EnumElementOrderingEnum - TSName string -}{ - {EnumElementZ, "Zebra"}, - {EnumElementA, "Apple"}, - {EnumElementM, "Mango"}, -} - -type EntityWithUnorderedEnumElements struct { - Name string `json:"name"` - Enum EnumElementOrderingEnum `json:"enum"` -} - -func (e EntityWithUnorderedEnumElements) Get() EntityWithUnorderedEnumElements { - return e -} - -// EnumElementOrderingTest tests that enum elements are sorted alphabetically -// by their TSName within an enum. Before PR #4664, elements appeared in the -// order they were added, which could be arbitrary. -var EnumElementOrderingTest = BindingTest{ - name: "EnumElementOrderingTest", - structs: []interface{}{ - &EntityWithUnorderedEnumElements{}, - }, - enums: []interface{}{ - AllEnumElementOrderingValues, - }, - exemptions: nil, - shouldError: false, - TsGenerationOptionsTest: TsGenerationOptionsTest{ - TsPrefix: "", - TsSuffix: "", - }, - // Expected output should have enum elements sorted: Apple, Mango, Zebra - want: `export namespace binding_test { - - export enum EnumElementOrderingEnum { - Apple = "a_value", - Mango = "m_value", - Zebra = "z_value", - } - export class EntityWithUnorderedEnumElements { - name: string; - enum: EnumElementOrderingEnum; - - static createFrom(source: any = {}) { - return new EntityWithUnorderedEnumElements(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.name = source["name"]; - this.enum = source["enum"]; - } - } - -} -`, -} - -// TSNameEnumElementOrdering tests sorting with TSName() method enum -type TSNameEnumElementOrdering string - -const ( - TSNameEnumZ TSNameEnumElementOrdering = "z_value" - TSNameEnumA TSNameEnumElementOrdering = "a_value" - TSNameEnumM TSNameEnumElementOrdering = "m_value" -) - -func (v TSNameEnumElementOrdering) TSName() string { - switch v { - case TSNameEnumZ: - return "Zebra" - case TSNameEnumA: - return "Apple" - case TSNameEnumM: - return "Mango" - default: - return "Unknown" - } -} - -// AllTSNameEnumValues intentionally out of order -var AllTSNameEnumValues = []TSNameEnumElementOrdering{TSNameEnumZ, TSNameEnumA, TSNameEnumM} - -type EntityWithTSNameEnumOrdering struct { - Name string `json:"name"` - Enum TSNameEnumElementOrdering `json:"enum"` -} - -func (e EntityWithTSNameEnumOrdering) Get() EntityWithTSNameEnumOrdering { - return e -} - -// TSNameEnumElementOrderingTest tests that enums using TSName() method -// also have their elements sorted alphabetically by the TSName. -var TSNameEnumElementOrderingTest = BindingTest{ - name: "TSNameEnumElementOrderingTest", - structs: []interface{}{ - &EntityWithTSNameEnumOrdering{}, - }, - enums: []interface{}{ - AllTSNameEnumValues, - }, - exemptions: nil, - shouldError: false, - TsGenerationOptionsTest: TsGenerationOptionsTest{ - TsPrefix: "", - TsSuffix: "", - }, - // Expected output should have enum elements sorted: Apple, Mango, Zebra - want: `export namespace binding_test { - - export enum TSNameEnumElementOrdering { - Apple = "a_value", - Mango = "m_value", - Zebra = "z_value", - } - export class EntityWithTSNameEnumOrdering { - name: string; - enum: TSNameEnumElementOrdering; - - static createFrom(source: any = {}) { - return new EntityWithTSNameEnumOrdering(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.name = source["name"]; - this.enum = source["enum"]; - } - } - -} -`, -} diff --git a/v2/internal/binding/binding_test/binding_escapedname_test.go b/v2/internal/binding/binding_test/binding_escapedname_test.go deleted file mode 100644 index 1bf6ce3ad..000000000 --- a/v2/internal/binding/binding_test/binding_escapedname_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package binding_test - -type EscapedName struct { - Name string `json:"n.a.m.e"` -} - -func (s EscapedName) Get() EscapedName { - return s -} - -var EscapedNameTest = BindingTest{ - name: "EscapedName", - structs: []interface{}{ - &EscapedName{}, - }, - exemptions: nil, - shouldError: false, - want: ` -export namespace binding_test { - export class EscapedName { - "n.a.m.e": string; - static createFrom(source: any = {}) { - return new EscapedName(source); - } - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this["n.a.m.e"] = source["n.a.m.e"]; - } - } -} -`, -} diff --git a/v2/internal/binding/binding_test/binding_generics_test.go b/v2/internal/binding/binding_test/binding_generics_test.go deleted file mode 100644 index 920bd2a7a..000000000 --- a/v2/internal/binding/binding_test/binding_generics_test.go +++ /dev/null @@ -1,154 +0,0 @@ -package binding_test - -import "github.com/wailsapp/wails/v2/internal/binding/binding_test/binding_test_import/float_package" - -// Issues 3900, 3371, 2323 (no TS generics though) - -type ListData[T interface{}] struct { - Total int64 `json:"Total"` - TotalPage int64 `json:"TotalPage"` - PageNum int `json:"PageNum"` - List []T `json:"List,omitempty"` -} - -func (x ListData[T]) Get() ListData[T] { - return x -} - -var Generics1Test = BindingTest{ - name: "Generics1", - structs: []interface{}{ - &ListData[string]{}, - }, - exemptions: nil, - shouldError: false, - want: ` -export namespace binding_test { - - export class ListData_string_ { - Total: number; - TotalPage: number; - PageNum: number; - List?: string[]; - - static createFrom(source: any = {}) { - return new ListData_string_(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.Total = source["Total"]; - this.TotalPage = source["TotalPage"]; - this.PageNum = source["PageNum"]; - this.List = source["List"]; - } - } - - } -`, -} - -var Generics2Test = BindingTest{ - name: "Generics2", - structs: []interface{}{ - &ListData[float_package.SomeStruct]{}, - &ListData[*float_package.SomeStruct]{}, - }, - exemptions: nil, - shouldError: false, - want: ` -export namespace binding_test { - - export class ListData__github_com_wailsapp_wails_v2_internal_binding_binding_test_binding_test_import_float_package_SomeStruct_ { - Total: number; - TotalPage: number; - PageNum: number; - List?: float_package.SomeStruct[]; - - static createFrom(source: any = {}) { - return new ListData__github_com_wailsapp_wails_v2_internal_binding_binding_test_binding_test_import_float_package_SomeStruct_(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.Total = source["Total"]; - this.TotalPage = source["TotalPage"]; - this.PageNum = source["PageNum"]; - this.List = this.convertValues(source["List"], float_package.SomeStruct); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class ListData_github_com_wailsapp_wails_v2_internal_binding_binding_test_binding_test_import_float_package_SomeStruct_ { - Total: number; - TotalPage: number; - PageNum: number; - List?: float_package.SomeStruct[]; - - static createFrom(source: any = {}) { - return new ListData_github_com_wailsapp_wails_v2_internal_binding_binding_test_binding_test_import_float_package_SomeStruct_(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.Total = source["Total"]; - this.TotalPage = source["TotalPage"]; - this.PageNum = source["PageNum"]; - this.List = this.convertValues(source["List"], float_package.SomeStruct); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - - } - - export namespace float_package { - - export class SomeStruct { - string: string; - - static createFrom(source: any = {}) { - return new SomeStruct(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.string = source["string"]; - } - } - - } -`, -} diff --git a/v2/internal/binding/binding_test/binding_ignored_test.go b/v2/internal/binding/binding_test/binding_ignored_test.go deleted file mode 100644 index aeb6a9c3f..000000000 --- a/v2/internal/binding/binding_test/binding_ignored_test.go +++ /dev/null @@ -1,47 +0,0 @@ -package binding_test - -import ( - "unsafe" -) - -// Issues 3755, 3809 - -type Ignored struct { - Valid bool - Total func() int `json:"Total"` - UnsafeP unsafe.Pointer - Complex64 complex64 `json:"Complex"` - Complex128 complex128 - StringChan chan string -} - -func (x Ignored) Get() Ignored { - return x -} - -var IgnoredTest = BindingTest{ - name: "Ignored", - structs: []interface{}{ - &Ignored{}, - }, - exemptions: nil, - shouldError: false, - want: ` -export namespace binding_test { - - export class Ignored { - Valid: boolean; - - static createFrom(source: any = {}) { - return new Ignored(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.Valid = source["Valid"]; - } - } - - } -`, -} diff --git a/v2/internal/binding/binding_test/binding_importedenum_test.go b/v2/internal/binding/binding_test/binding_importedenum_test.go deleted file mode 100644 index 5b5b4419e..000000000 --- a/v2/internal/binding/binding_test/binding_importedenum_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package binding_test - -import "github.com/wailsapp/wails/v2/internal/binding/binding_test/binding_test_import" - -type ImportedEnumStruct struct { - EnumValue binding_test_import.ImportedEnum `json:"EnumValue"` -} - -func (s ImportedEnumStruct) Get() ImportedEnumStruct { - return s -} - -var ImportedEnumTest = BindingTest{ - name: "ImportedEnum", - structs: []interface{}{ - &ImportedEnumStruct{}, - }, - enums: []interface{}{ - binding_test_import.AllImportedEnumValues, - }, - exemptions: nil, - shouldError: false, - want: `export namespace binding_test { - - export class ImportedEnumStruct { - EnumValue: binding_test_import.ImportedEnum; - - static createFrom(source: any = {}) { - return new ImportedEnumStruct(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.EnumValue = source["EnumValue"]; - } - } - - } - - export namespace binding_test_import { - - export enum ImportedEnum { - Value1 = "value1", - Value2 = "value2", - Value3 = "value3", - } - - } -`, -} diff --git a/v2/internal/binding/binding_test/binding_importedmap_test.go b/v2/internal/binding/binding_test/binding_importedmap_test.go deleted file mode 100644 index 4a4b2996c..000000000 --- a/v2/internal/binding/binding_test/binding_importedmap_test.go +++ /dev/null @@ -1,94 +0,0 @@ -package binding_test - -import "github.com/wailsapp/wails/v2/internal/binding/binding_test/binding_test_import" - -type ImportedMap struct { - AMapWrapperContainer binding_test_import.AMapWrapper `json:"AMapWrapperContainer"` -} - -func (s ImportedMap) Get() ImportedMap { - return s -} - -var ImportedMapTest = BindingTest{ - name: "ImportedMap", - structs: []interface{}{ - &ImportedMap{}, - }, - exemptions: nil, - shouldError: false, - want: ` -export namespace binding_test { - export class ImportedMap { - AMapWrapperContainer: binding_test_import.AMapWrapper; - static createFrom(source: any = {}) { - return new ImportedMap(source); - } - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.AMapWrapperContainer = this.convertValues(source["AMapWrapperContainer"], binding_test_import.AMapWrapper); - } - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } -} - -export namespace binding_test_import { - export class AMapWrapper { - AMap: Record; - static createFrom(source: any = {}) { - return new AMapWrapper(source); - } - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.AMap = this.convertValues(source["AMap"], binding_test_nestedimport.A, true); - } - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } -} - -export namespace binding_test_nestedimport { - export class A { - A: string; - static createFrom(source: any = {}) { - return new A(source); - } - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.A = source["A"]; - } - } -} -`, -} diff --git a/v2/internal/binding/binding_test/binding_importedslice_test.go b/v2/internal/binding/binding_test/binding_importedslice_test.go deleted file mode 100644 index 5abf55b43..000000000 --- a/v2/internal/binding/binding_test/binding_importedslice_test.go +++ /dev/null @@ -1,94 +0,0 @@ -package binding_test - -import "github.com/wailsapp/wails/v2/internal/binding/binding_test/binding_test_import" - -type ImportedSlice struct { - ASliceWrapperContainer binding_test_import.ASliceWrapper `json:"ASliceWrapperContainer"` -} - -func (s ImportedSlice) Get() ImportedSlice { - return s -} - -var ImportedSliceTest = BindingTest{ - name: "ImportedSlice", - structs: []interface{}{ - &ImportedSlice{}, - }, - exemptions: nil, - shouldError: false, - want: ` -export namespace binding_test { - export class ImportedSlice { - ASliceWrapperContainer: binding_test_import.ASliceWrapper; - static createFrom(source: any = {}) { - return new ImportedSlice(source); - } - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.ASliceWrapperContainer = this.convertValues(source["ASliceWrapperContainer"], binding_test_import.ASliceWrapper); - } - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } -} - -export namespace binding_test_import { - export class ASliceWrapper { - ASlice: binding_test_nestedimport.A[]; - static createFrom(source: any = {}) { - return new ASliceWrapper(source); - } - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.ASlice = this.convertValues(source["ASlice"], binding_test_nestedimport.A); - } - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } -} - -export namespace binding_test_nestedimport { - export class A { - A: string; - static createFrom(source: any = {}) { - return new A(source); - } - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.A = source["A"]; - } - } -} -`, -} diff --git a/v2/internal/binding/binding_test/binding_importedstruct_test.go b/v2/internal/binding/binding_test/binding_importedstruct_test.go deleted file mode 100644 index 1e94453c2..000000000 --- a/v2/internal/binding/binding_test/binding_importedstruct_test.go +++ /dev/null @@ -1,95 +0,0 @@ -package binding_test - -import "github.com/wailsapp/wails/v2/internal/binding/binding_test/binding_test_import" - -type ImportedStruct struct { - AWrapperContainer binding_test_import.AWrapper `json:"AWrapperContainer"` -} - -func (s ImportedStruct) Get() ImportedStruct { - return s -} - -var ImportedStructTest = BindingTest{ - name: "ImportedStruct", - structs: []interface{}{ - &ImportedStruct{}, - }, - exemptions: nil, - shouldError: false, - want: ` -export namespace binding_test { - export class ImportedStruct { - AWrapperContainer: binding_test_import.AWrapper; - static createFrom(source: any = {}) { - return new ImportedStruct(source); - } - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.AWrapperContainer = this.convertValues(source["AWrapperContainer"], binding_test_import.AWrapper); - } - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } -} - -export namespace binding_test_import { - export class AWrapper { - AWrapper: binding_test_nestedimport.A; - static createFrom(source: any = {}) { - return new AWrapper(source); - } - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.AWrapper = this.convertValues(source["AWrapper"], binding_test_nestedimport.A); - } - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } -} - -export namespace binding_test_nestedimport { - export class A { - A: string; - static createFrom(source: any = {}) { - return new A(source); - } - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.A = source["A"]; - } - } -} -`, -} diff --git a/v2/internal/binding/binding_test/binding_multiplestructs_test.go b/v2/internal/binding/binding_test/binding_multiplestructs_test.go deleted file mode 100644 index 144867813..000000000 --- a/v2/internal/binding/binding_test/binding_multiplestructs_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package binding_test - -type Multistruct1 struct { - Name string `json:"name"` -} - -func (s Multistruct1) Get() Multistruct1 { - return s -} - -type Multistruct2 struct { - Name string `json:"name"` -} - -func (s Multistruct2) Get() Multistruct2 { - return s -} - -type Multistruct3 struct { - Name string `json:"name"` -} - -func (s Multistruct3) Get() Multistruct3 { - return s -} - -type Multistruct4 struct { - Name string `json:"name"` -} - -func (s Multistruct4) Get() Multistruct4 { - return s -} - -var MultistructTest = BindingTest{ - name: "Multistruct", - structs: []interface{}{ - &Multistruct1{}, - &Multistruct2{}, - &Multistruct3{}, - &Multistruct4{}, - }, - exemptions: nil, - shouldError: false, - want: `export namespace binding_test { - export class Multistruct1 { - name: string; - static createFrom(source: any = {}) { - return new Multistruct1(source); - } - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.name = source["name"]; - } - } - export class Multistruct2 { - name: string; - static createFrom(source: any = {}) { - return new Multistruct2(source); - } - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.name = source["name"]; - } - } - export class Multistruct3 { - name: string; - static createFrom(source: any = {}) { - return new Multistruct3(source); - } - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.name = source["name"]; - } - } - export class Multistruct4 { - name: string; - static createFrom(source: any = {}) { - return new Multistruct4(source); - } - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.name = source["name"]; - } - } -} -`, -} diff --git a/v2/internal/binding/binding_test/binding_nestedfield_test.go b/v2/internal/binding/binding_test/binding_nestedfield_test.go deleted file mode 100644 index 66dd11cbf..000000000 --- a/v2/internal/binding/binding_test/binding_nestedfield_test.go +++ /dev/null @@ -1,63 +0,0 @@ -package binding_test - -type As struct { - B Bs `json:"b"` -} - -type Bs struct { - Name string `json:"name"` -} - -func (a As) Get() As { - return a -} - -var NestedFieldTest = BindingTest{ - name: "NestedField", - structs: []interface{}{ - &As{}, - }, - exemptions: nil, - shouldError: false, - want: ` -export namespace binding_test { - export class Bs { - name: string; - static createFrom(source: any = {}) { - return new Bs(source); - } - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.name = source["name"]; - } - } - export class As { - b: Bs; - static createFrom(source: any = {}) { - return new As(source); - } - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.b = this.convertValues(source["b"], Bs); - } - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } -} -`, -} diff --git a/v2/internal/binding/binding_test/binding_nonstringmapkey_test.go b/v2/internal/binding/binding_test/binding_nonstringmapkey_test.go deleted file mode 100644 index 9efee710f..000000000 --- a/v2/internal/binding/binding_test/binding_nonstringmapkey_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package binding_test - -type NonStringMapKey struct { - NumberMap map[uint]any `json:"numberMap"` -} - -func (s NonStringMapKey) Get() NonStringMapKey { - return s -} - -var NonStringMapKeyTest = BindingTest{ - name: "NonStringMapKey", - structs: []interface{}{ - &NonStringMapKey{}, - }, - exemptions: nil, - shouldError: false, - want: ` -export namespace binding_test { - export class NonStringMapKey { - numberMap: Record; - static createFrom(source: any = {}) { - return new NonStringMapKey(source); - } - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.numberMap = source["numberMap"]; - } - } -} -`, -} diff --git a/v2/internal/binding/binding_test/binding_notags_test.go b/v2/internal/binding/binding_test/binding_notags_test.go deleted file mode 100644 index d4d9997e0..000000000 --- a/v2/internal/binding/binding_test/binding_notags_test.go +++ /dev/null @@ -1,60 +0,0 @@ -package binding_test - -type NoFieldTags struct { - Name string - Address string - Zip *string - Spouse *NoFieldTags - NoFunc func() string -} - -func (n NoFieldTags) Get() NoFieldTags { - return n -} - -var NoFieldTagsTest = BindingTest{ - name: "NoFieldTags", - structs: []interface{}{ - &NoFieldTags{}, - }, - exemptions: nil, - shouldError: false, - want: ` -export namespace binding_test { - export class NoFieldTags { - Name: string; - Address: string; - Zip?: string; - Spouse?: NoFieldTags; - static createFrom(source: any = {}) { - return new NoFieldTags(source); - } - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.Name = source["Name"]; - this.Address = source["Address"]; - this.Zip = source["Zip"]; - this.Spouse = this.convertValues(source["Spouse"], NoFieldTags); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } -} -`, -} diff --git a/v2/internal/binding/binding_test/binding_returned_promises_test.go b/v2/internal/binding/binding_test/binding_returned_promises_test.go deleted file mode 100644 index 94941d0a3..000000000 --- a/v2/internal/binding/binding_test/binding_returned_promises_test.go +++ /dev/null @@ -1,81 +0,0 @@ -package binding_test - -import ( - "io/fs" - "os" - "testing" - - "github.com/wailsapp/wails/v2/internal/binding" - "github.com/wailsapp/wails/v2/internal/logger" -) - -const expectedPromiseBindings = `// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT -import {binding_test} from '../models'; - -export function ErrorReturn(arg1:number):Promise; - -export function NoReturn(arg1:string):Promise; - -export function SingleReturn(arg1:any):Promise; - -export function SingleReturnStruct(arg1:any):Promise; - -export function SingleReturnStructPointer(arg1:any):Promise; - -export function SingleReturnStructPointerSlice(arg1:any):Promise>; - -export function SingleReturnStructSlice(arg1:any):Promise>; - -export function SingleReturnWithError(arg1:number):Promise; - -export function TwoReturn(arg1:any):Promise; -` - -type PromisesTest struct{} -type PromisesTestReturnStruct struct{} - -func (h *PromisesTest) NoReturn(_ string) {} -func (h *PromisesTest) ErrorReturn(_ int) error { return nil } -func (h *PromisesTest) SingleReturn(_ interface{}) int { return 0 } -func (h *PromisesTest) SingleReturnStructPointer(_ interface{}) *PromisesTestReturnStruct { - return &PromisesTestReturnStruct{} -} -func (h *PromisesTest) SingleReturnStruct(_ interface{}) PromisesTestReturnStruct { - return PromisesTestReturnStruct{} -} -func (h *PromisesTest) SingleReturnStructSlice(_ interface{}) []PromisesTestReturnStruct { - return []PromisesTestReturnStruct{} -} -func (h *PromisesTest) SingleReturnStructPointerSlice(_ interface{}) []*PromisesTestReturnStruct { - return []*PromisesTestReturnStruct{} -} -func (h *PromisesTest) SingleReturnWithError(_ int) (string, error) { return "", nil } -func (h *PromisesTest) TwoReturn(_ interface{}) (string, int) { return "", 0 } - -func TestPromises(t *testing.T) { - // given - generationDir := t.TempDir() - - // setup - testLogger := &logger.Logger{} - b := binding.NewBindings(testLogger, []interface{}{&PromisesTest{}}, []interface{}{}, false, []interface{}{}) - - // then - err := b.GenerateGoBindings(generationDir) - if err != nil { - t.Fatalf("could not generate the Go bindings: %v", err) - } - - // then - rawGeneratedBindings, err := fs.ReadFile(os.DirFS(generationDir), "binding_test/PromisesTest.d.ts") - if err != nil { - t.Fatalf("could not read the generated bindings: %v", err) - } - - // then - generatedBindings := string(rawGeneratedBindings) - if generatedBindings != expectedPromiseBindings { - t.Fatalf("the generated bindings does not match the expected ones.\nWanted:\n%s\n\nGot:\n%s", expectedPromiseBindings, generatedBindings) - } -} diff --git a/v2/internal/binding/binding_test/binding_singlefield_test.go b/v2/internal/binding/binding_test/binding_singlefield_test.go deleted file mode 100644 index 2919ab29e..000000000 --- a/v2/internal/binding/binding_test/binding_singlefield_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package binding_test - -type SingleField struct { - Name string `json:"name"` -} - -func (s SingleField) Get() SingleField { - return s -} - -var SingleFieldTest = BindingTest{ - name: "SingleField", - structs: []interface{}{ - &SingleField{}, - }, - exemptions: nil, - shouldError: false, - want: ` -export namespace binding_test { - export class SingleField { - name: string; - static createFrom(source: any = {}) { - return new SingleField(source); - } - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.name = source["name"]; - } - } -} -`, -} diff --git a/v2/internal/binding/binding_test/binding_structwithoutfields_test.go b/v2/internal/binding/binding_test/binding_structwithoutfields_test.go deleted file mode 100644 index 4b2289b98..000000000 --- a/v2/internal/binding/binding_test/binding_structwithoutfields_test.go +++ /dev/null @@ -1,34 +0,0 @@ -package binding_test - -type WithoutFields struct { -} - -func (s WithoutFields) Get() WithoutFields { - return s -} - -var WithoutFieldsTest = BindingTest{ - name: "StructWithoutFields", - structs: []interface{}{ - &WithoutFields{}, - }, - exemptions: nil, - shouldError: false, - want: ` -export namespace binding_test { - - export class WithoutFields { - - - static createFrom(source: any = {}) { - return new WithoutFields(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - - } - } - -}`, -} diff --git a/v2/internal/binding/binding_test/binding_test.go b/v2/internal/binding/binding_test/binding_test.go deleted file mode 100644 index 41f0618ce..000000000 --- a/v2/internal/binding/binding_test/binding_test.go +++ /dev/null @@ -1,85 +0,0 @@ -package binding_test - -import ( - "reflect" - "strings" - "testing" - - "github.com/stretchr/testify/require" - "github.com/wailsapp/wails/v2/internal/binding" - "github.com/wailsapp/wails/v2/internal/logger" -) - -type BindingTest struct { - name string - structs []interface{} - enums []interface{} - exemptions []interface{} - want string - shouldError bool - TsGenerationOptionsTest -} - -type TsGenerationOptionsTest struct { - TsPrefix string - TsSuffix string - TsOutputType string -} - -func TestBindings_GenerateModels(t *testing.T) { - - tests := []BindingTest{ - EscapedNameTest, - ImportedStructTest, - ImportedSliceTest, - ImportedMapTest, - ImportedEnumTest, - NestedFieldTest, - NonStringMapKeyTest, - SingleFieldTest, - MultistructTest, - EmptyStructTest, - GeneratedJsEntityTest, - GeneratedJsEntityWithIntEnumTest, - GeneratedJsEntityWithStringEnumTest, - GeneratedJsEntityWithEnumTsName, - GeneratedJsEntityWithNestedStructInterfacesTest, - AnonymousSubStructTest, - AnonymousSubStructMultiLevelTest, - GeneratedJsEntityWithNestedStructTest, - EntityWithDiffNamespacesTest, - SpecialCharacterFieldTest, - WithoutFieldsTest, - NoFieldTagsTest, - Generics1Test, - Generics2Test, - IgnoredTest, - DeepElementsTest, - // PR #4664: Enum ordering tests - EnumOrderingTest, - EnumElementOrderingTest, - TSNameEnumElementOrderingTest, - } - - testLogger := &logger.Logger{} - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - b := binding.NewBindings(testLogger, tt.structs, tt.exemptions, false, tt.enums) - for _, s := range tt.structs { - err := b.Add(s) - require.NoError(t, err) - } - b.SetTsPrefix(tt.TsPrefix) - b.SetTsSuffix(tt.TsSuffix) - b.SetOutputType(tt.TsOutputType) - got, err := b.GenerateModels() - if (err != nil) != tt.shouldError { - t.Errorf("GenerateModels() error = %v, shouldError %v", err, tt.shouldError) - return - } - if !reflect.DeepEqual(strings.Fields(string(got)), strings.Fields(tt.want)) { - t.Errorf("GenerateModels() got = %v, want %v", string(got), tt.want) - } - }) - } -} diff --git a/v2/internal/binding/binding_test/binding_test_import/binding_test_import.go b/v2/internal/binding/binding_test/binding_test_import/binding_test_import.go deleted file mode 100644 index e7080c694..000000000 --- a/v2/internal/binding/binding_test/binding_test_import/binding_test_import.go +++ /dev/null @@ -1,32 +0,0 @@ -package binding_test_import - -import "github.com/wailsapp/wails/v2/internal/binding/binding_test/binding_test_import/binding_test_nestedimport" - -type AWrapper struct { - AWrapper binding_test_nestedimport.A `json:"AWrapper"` -} - -type ASliceWrapper struct { - ASlice []binding_test_nestedimport.A `json:"ASlice"` -} - -type AMapWrapper struct { - AMap map[string]binding_test_nestedimport.A `json:"AMap"` -} - -type ImportedEnum string - -const ( - ImportedEnumValue1 ImportedEnum = "value1" - ImportedEnumValue2 ImportedEnum = "value2" - ImportedEnumValue3 ImportedEnum = "value3" -) - -var AllImportedEnumValues = []struct { - Value ImportedEnum - TSName string -}{ - {ImportedEnumValue1, "Value1"}, - {ImportedEnumValue2, "Value2"}, - {ImportedEnumValue3, "Value3"}, -} diff --git a/v2/internal/binding/binding_test/binding_test_import/binding_test_nestedimport/binding_nestedimport.go b/v2/internal/binding/binding_test/binding_test_import/binding_test_nestedimport/binding_nestedimport.go deleted file mode 100644 index 31c70ad3f..000000000 --- a/v2/internal/binding/binding_test/binding_test_import/binding_test_nestedimport/binding_nestedimport.go +++ /dev/null @@ -1,5 +0,0 @@ -package binding_test_nestedimport - -type A struct { - A string `json:"A"` -} diff --git a/v2/internal/binding/binding_test/binding_test_import/float_package/type.go b/v2/internal/binding/binding_test/binding_test_import/float_package/type.go deleted file mode 100644 index 66a20304b..000000000 --- a/v2/internal/binding/binding_test/binding_test_import/float_package/type.go +++ /dev/null @@ -1,5 +0,0 @@ -package float_package - -type SomeStruct struct { - Name string `json:"string"` -} diff --git a/v2/internal/binding/binding_test/binding_test_import/int_package/type.go b/v2/internal/binding/binding_test/binding_test_import/int_package/type.go deleted file mode 100644 index bff29946a..000000000 --- a/v2/internal/binding/binding_test/binding_test_import/int_package/type.go +++ /dev/null @@ -1,5 +0,0 @@ -package int_package - -type SomeStruct struct { - Name string `json:"string"` -} diff --git a/v2/internal/binding/binding_test/binding_test_import/map_package/type.go b/v2/internal/binding/binding_test/binding_test_import/map_package/type.go deleted file mode 100644 index 34303757c..000000000 --- a/v2/internal/binding/binding_test/binding_test_import/map_package/type.go +++ /dev/null @@ -1,5 +0,0 @@ -package map_package - -type SomeStruct struct { - Name string `json:"string"` -} diff --git a/v2/internal/binding/binding_test/binding_test_import/uint_package/type.go b/v2/internal/binding/binding_test/binding_test_import/uint_package/type.go deleted file mode 100644 index dd55675f6..000000000 --- a/v2/internal/binding/binding_test/binding_test_import/uint_package/type.go +++ /dev/null @@ -1,5 +0,0 @@ -package uint_package - -type SomeStruct struct { - Name string `json:"string"` -} diff --git a/v2/internal/binding/binding_test/binding_tsgeneration_test.go b/v2/internal/binding/binding_test/binding_tsgeneration_test.go deleted file mode 100644 index 850bc778a..000000000 --- a/v2/internal/binding/binding_test/binding_tsgeneration_test.go +++ /dev/null @@ -1,509 +0,0 @@ -package binding_test - -import ( - "github.com/wailsapp/wails/v2/internal/binding/binding_test/binding_test_import" -) - -type GeneratedJsEntity struct { - Name string `json:"name"` -} - -func (s GeneratedJsEntity) Get() GeneratedJsEntity { - return s -} - -var GeneratedJsEntityTest = BindingTest{ - name: "GeneratedJsEntityTest", - structs: []interface{}{ - &GeneratedJsEntity{}, - }, - exemptions: nil, - shouldError: false, - TsGenerationOptionsTest: TsGenerationOptionsTest{ - TsPrefix: "MY_PREFIX_", - TsSuffix: "_MY_SUFFIX", - }, - want: ` -export namespace binding_test { - - export class MY_PREFIX_GeneratedJsEntity_MY_SUFFIX { - name: string; - - static createFrom(source: any = {}) { - return new MY_PREFIX_GeneratedJsEntity_MY_SUFFIX(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.name = source["name"]; - } - } - -} - -`, -} - -type ParentEntity struct { - Name string `json:"name"` - Ref ChildEntity `json:"ref"` - ParentProp string `json:"parentProp"` -} - -func (p ParentEntity) Get() ParentEntity { - return p -} - -type ChildEntity struct { - Name string `json:"name"` - ChildProp int `json:"childProp"` -} - -var GeneratedJsEntityWithNestedStructTest = BindingTest{ - name: "GeneratedJsEntityWithNestedStructTest", - structs: []interface{}{ - &ParentEntity{}, - }, - exemptions: nil, - shouldError: false, - TsGenerationOptionsTest: TsGenerationOptionsTest{ - TsPrefix: "MY_PREFIX_", - TsSuffix: "_MY_SUFFIX", - }, - want: ` -export namespace binding_test { - - export class MY_PREFIX_ChildEntity_MY_SUFFIX { - name: string; - childProp: number; - - static createFrom(source: any = {}) { - return new MY_PREFIX_ChildEntity_MY_SUFFIX(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.name = source["name"]; - this.childProp = source["childProp"]; - } - } - export class MY_PREFIX_ParentEntity_MY_SUFFIX { - name: string; - ref: MY_PREFIX_ChildEntity_MY_SUFFIX; - parentProp: string; - - static createFrom(source: any = {}) { - return new MY_PREFIX_ParentEntity_MY_SUFFIX(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.name = source["name"]; - this.ref = this.convertValues(source["ref"], MY_PREFIX_ChildEntity_MY_SUFFIX); - this.parentProp = source["parentProp"]; - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - - } -`, -} - -type ParentPackageEntity struct { - Name string `json:"name"` - Ref ChildPackageEntity `json:"ref"` -} - -func (p ParentPackageEntity) Get() ParentPackageEntity { - return p -} - -type ChildPackageEntity struct { - Name string `json:"name"` - ImportedPackage binding_test_import.AWrapper `json:"importedPackage"` -} - -var EntityWithDiffNamespacesTest = BindingTest{ - name: "EntityWithDiffNamespaces ", - structs: []interface{}{ - &ParentPackageEntity{}, - }, - exemptions: nil, - shouldError: false, - TsGenerationOptionsTest: TsGenerationOptionsTest{ - TsPrefix: "MY_PREFIX_", - TsSuffix: "_MY_SUFFIX", - }, - want: ` -export namespace binding_test { - - export class MY_PREFIX_ChildPackageEntity_MY_SUFFIX { - name: string; - importedPackage: binding_test_import.MY_PREFIX_AWrapper_MY_SUFFIX; - - static createFrom(source: any = {}) { - return new MY_PREFIX_ChildPackageEntity_MY_SUFFIX(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.name = source["name"]; - this.importedPackage = this.convertValues(source["importedPackage"], binding_test_import.MY_PREFIX_AWrapper_MY_SUFFIX); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class MY_PREFIX_ParentPackageEntity_MY_SUFFIX { - name: string; - ref: MY_PREFIX_ChildPackageEntity_MY_SUFFIX; - - static createFrom(source: any = {}) { - return new MY_PREFIX_ParentPackageEntity_MY_SUFFIX(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.name = source["name"]; - this.ref = this.convertValues(source["ref"], MY_PREFIX_ChildPackageEntity_MY_SUFFIX); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - - } - - export namespace binding_test_import { - - export class MY_PREFIX_AWrapper_MY_SUFFIX { - AWrapper: binding_test_nestedimport.MY_PREFIX_A_MY_SUFFIX; - - static createFrom(source: any = {}) { - return new MY_PREFIX_AWrapper_MY_SUFFIX(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.AWrapper = this.convertValues(source["AWrapper"], binding_test_nestedimport.MY_PREFIX_A_MY_SUFFIX); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - - } - - export namespace binding_test_nestedimport { - - export class MY_PREFIX_A_MY_SUFFIX { - A: string; - - static createFrom(source: any = {}) { - return new MY_PREFIX_A_MY_SUFFIX(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.A = source["A"]; - } - } - - } - -`, -} - -type IntEnum int - -const ( - IntEnumValue1 IntEnum = iota - IntEnumValue2 - IntEnumValue3 -) - -var AllIntEnumValues = []struct { - Value IntEnum - TSName string -}{ - {IntEnumValue1, "Value1"}, - {IntEnumValue2, "Value2"}, - {IntEnumValue3, "Value3"}, -} - -type EntityWithIntEnum struct { - Name string `json:"name"` - Enum IntEnum `json:"enum"` -} - -func (e EntityWithIntEnum) Get() EntityWithIntEnum { - return e -} - -var GeneratedJsEntityWithIntEnumTest = BindingTest{ - name: "GeneratedJsEntityWithIntEnumTest", - structs: []interface{}{ - &EntityWithIntEnum{}, - }, - enums: []interface{}{ - AllIntEnumValues, - }, - exemptions: nil, - shouldError: false, - TsGenerationOptionsTest: TsGenerationOptionsTest{ - TsPrefix: "MY_PREFIX_", - TsSuffix: "_MY_SUFFIX", - }, - want: `export namespace binding_test { - - export enum MY_PREFIX_IntEnum_MY_SUFFIX { - Value1 = 0, - Value2 = 1, - Value3 = 2, - } - export class MY_PREFIX_EntityWithIntEnum_MY_SUFFIX { - name: string; - enum: MY_PREFIX_IntEnum_MY_SUFFIX; - - static createFrom(source: any = {}) { - return new MY_PREFIX_EntityWithIntEnum_MY_SUFFIX(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.name = source["name"]; - this.enum = source["enum"]; - } - } - - } -`, -} - -type StringEnum string - -const ( - StringEnumValue1 StringEnum = "value1" - StringEnumValue2 StringEnum = "value2" - StringEnumValue3 StringEnum = "value3" -) - -var AllStringEnumValues = []struct { - Value StringEnum - TSName string -}{ - {StringEnumValue1, "Value1"}, - {StringEnumValue2, "Value2"}, - {StringEnumValue3, "Value3"}, -} - -type EntityWithStringEnum struct { - Name string `json:"name"` - Enum StringEnum `json:"enum"` -} - -func (e EntityWithStringEnum) Get() EntityWithStringEnum { - return e -} - -var GeneratedJsEntityWithStringEnumTest = BindingTest{ - name: "GeneratedJsEntityWithStringEnumTest", - structs: []interface{}{ - &EntityWithStringEnum{}, - }, - enums: []interface{}{ - AllStringEnumValues, - }, - exemptions: nil, - shouldError: false, - TsGenerationOptionsTest: TsGenerationOptionsTest{ - TsPrefix: "MY_PREFIX_", - TsSuffix: "_MY_SUFFIX", - }, - want: `export namespace binding_test { - - export enum MY_PREFIX_StringEnum_MY_SUFFIX { - Value1 = "value1", - Value2 = "value2", - Value3 = "value3", - } - export class MY_PREFIX_EntityWithStringEnum_MY_SUFFIX { - name: string; - enum: MY_PREFIX_StringEnum_MY_SUFFIX; - - static createFrom(source: any = {}) { - return new MY_PREFIX_EntityWithStringEnum_MY_SUFFIX(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.name = source["name"]; - this.enum = source["enum"]; - } - } - - } -`, -} - -type EnumWithTsName string - -const ( - EnumWithTsName1 EnumWithTsName = "value1" - EnumWithTsName2 EnumWithTsName = "value2" - EnumWithTsName3 EnumWithTsName = "value3" -) - -var AllEnumWithTsNameValues = []EnumWithTsName{EnumWithTsName1, EnumWithTsName2, EnumWithTsName3} - -func (v EnumWithTsName) TSName() string { - switch v { - case EnumWithTsName1: - return "TsName1" - case EnumWithTsName2: - return "TsName2" - case EnumWithTsName3: - return "TsName3" - default: - return "???" - } -} - -type EntityWithEnumTsName struct { - Name string `json:"name"` - Enum EnumWithTsName `json:"enum"` -} - -func (e EntityWithEnumTsName) Get() EntityWithEnumTsName { - return e -} - -var GeneratedJsEntityWithEnumTsName = BindingTest{ - name: "GeneratedJsEntityWithEnumTsName", - structs: []interface{}{ - &EntityWithEnumTsName{}, - }, - enums: []interface{}{ - AllEnumWithTsNameValues, - }, - exemptions: nil, - shouldError: false, - TsGenerationOptionsTest: TsGenerationOptionsTest{ - TsPrefix: "MY_PREFIX_", - TsSuffix: "_MY_SUFFIX", - }, - want: `export namespace binding_test { - - export enum MY_PREFIX_EnumWithTsName_MY_SUFFIX { - TsName1 = "value1", - TsName2 = "value2", - TsName3 = "value3", - } - export class MY_PREFIX_EntityWithEnumTsName_MY_SUFFIX { - name: string; - enum: MY_PREFIX_EnumWithTsName_MY_SUFFIX; - - static createFrom(source: any = {}) { - return new MY_PREFIX_EntityWithEnumTsName_MY_SUFFIX(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.name = source["name"]; - this.enum = source["enum"]; - } - } - - } -`, -} - -var GeneratedJsEntityWithNestedStructInterfacesTest = BindingTest{ - name: "GeneratedJsEntityWithNestedStructInterfacesTest", - structs: []interface{}{ - &ParentEntity{}, - }, - exemptions: nil, - shouldError: false, - TsGenerationOptionsTest: TsGenerationOptionsTest{ - TsPrefix: "MY_PREFIX_", - TsSuffix: "_MY_SUFFIX", - TsOutputType: "interfaces", - }, - want: `export namespace binding_test { - - export interface MY_PREFIX_ChildEntity_MY_SUFFIX { - name: string; - childProp: number; - } - export interface MY_PREFIX_ParentEntity_MY_SUFFIX { - name: string; - ref: MY_PREFIX_ChildEntity_MY_SUFFIX; - parentProp: string; - } - - } -`, -} diff --git a/v2/internal/binding/binding_test/binding_type_alias_test.go b/v2/internal/binding/binding_test/binding_type_alias_test.go deleted file mode 100644 index 90b009c5f..000000000 --- a/v2/internal/binding/binding_test/binding_type_alias_test.go +++ /dev/null @@ -1,64 +0,0 @@ -package binding_test - -import ( - "github.com/wailsapp/wails/v2/internal/binding/binding_test/binding_test_import/int_package" - "io/fs" - "os" - "testing" - - "github.com/wailsapp/wails/v2/internal/binding" - "github.com/wailsapp/wails/v2/internal/logger" -) - -const expectedTypeAliasBindings = `// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT -import {binding_test} from '../models'; -import {int_package} from '../models'; - -export function Map():Promise>; - -export function MapAlias():Promise; - -export function MapWithImportedStructValue():Promise>; - -export function Slice():Promise>; - -export function SliceImportedStruct():Promise>; -` - -type AliasTest struct{} -type MapAlias map[string]string - -func (h *AliasTest) Map() map[string]string { return nil } -func (h *AliasTest) MapAlias() MapAlias { return nil } -func (h *AliasTest) MapWithImportedStructValue() map[string]int_package.SomeStruct { return nil } -func (h *AliasTest) Slice() []string { return nil } -func (h *AliasTest) SliceImportedStruct() []int_package.SomeStruct { return nil } - -func TestAliases(t *testing.T) { - // given - generationDir := t.TempDir() - - // setup - testLogger := &logger.Logger{} - b := binding.NewBindings(testLogger, []interface{}{&AliasTest{}}, []interface{}{}, false, []interface{}{}) - - // then - err := b.GenerateGoBindings(generationDir) - if err != nil { - t.Fatalf("could not generate the Go bindings: %v", err) - } - - // then - rawGeneratedBindings, err := fs.ReadFile(os.DirFS(generationDir), "binding_test/AliasTest.d.ts") - if err != nil { - t.Fatalf("could not read the generated bindings: %v", err) - } - - // then - generatedBindings := string(rawGeneratedBindings) - if generatedBindings != expectedTypeAliasBindings { - t.Fatalf("the generated bindings does not match the expected ones.\nWanted:\n%s\n\nGot:\n%s", expectedTypeAliasBindings, - generatedBindings) - } -} diff --git a/v2/internal/binding/binding_test/binding_variablespecialcharacter_test.go b/v2/internal/binding/binding_test/binding_variablespecialcharacter_test.go deleted file mode 100644 index 7dbe72350..000000000 --- a/v2/internal/binding/binding_test/binding_variablespecialcharacter_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package binding_test - -type SpecialCharacterField struct { - ID string `json:"@ID,omitempty"` -} - -func (s SpecialCharacterField) Get() SpecialCharacterField { - return s -} - -var SpecialCharacterFieldTest = BindingTest{ - name: "SpecialCharacterField", - structs: []interface{}{ - &SpecialCharacterField{}, - }, - exemptions: nil, - shouldError: false, - want: ` -export namespace binding_test { - export class SpecialCharacterField { - "@ID"?: string; - static createFrom(source: any = {}) { - return new SpecialCharacterField(source); - } - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this["@ID"] = source["@ID"]; - } - } -} -`, -} diff --git a/v2/internal/binding/boundMethod.go b/v2/internal/binding/boundMethod.go index e697041b0..f6ffdb600 100644 --- a/v2/internal/binding/boundMethod.go +++ b/v2/internal/binding/boundMethod.go @@ -6,24 +6,14 @@ import ( "reflect" ) -type BoundedMethodPath struct { - Package string - Struct string - Name string -} - -func (p *BoundedMethodPath) FullName() string { - return fmt.Sprintf("%s.%s.%s", p.Package, p.Struct, p.Name) -} - // BoundMethod defines all the data related to a Go method that is // bound to the Wails application type BoundMethod struct { - Path *BoundedMethodPath `json:"path"` - Inputs []*Parameter `json:"inputs,omitempty"` - Outputs []*Parameter `json:"outputs,omitempty"` - Comments string `json:"comments,omitempty"` - Method reflect.Value `json:"-"` + Name string `json:"name"` + Inputs []*Parameter `json:"inputs,omitempty"` + Outputs []*Parameter `json:"outputs,omitempty"` + Comments string `json:"comments,omitempty"` + Method reflect.Value `json:"-"` } // InputCount returns the number of inputs this bound method has @@ -38,9 +28,10 @@ func (b *BoundMethod) OutputCount() int { // ParseArgs method converts the input json into the types expected by the method func (b *BoundMethod) ParseArgs(args []json.RawMessage) ([]interface{}, error) { + result := make([]interface{}, b.InputCount()) if len(args) != b.InputCount() { - return nil, fmt.Errorf("received %d arguments to method '%s', expected %d", len(args), b.Path.FullName(), b.InputCount()) + return nil, fmt.Errorf("received %d arguments to method '%s', expected %d", len(args), b.Name, b.InputCount()) } for index, arg := range args { typ := b.Inputs[index].reflectType @@ -64,7 +55,7 @@ func (b *BoundMethod) Call(args []interface{}) (interface{}, error) { expectedInputLength := len(b.Inputs) actualInputLength := len(args) if expectedInputLength != actualInputLength { - return nil, fmt.Errorf("%s takes %d inputs. Received %d", b.Path.FullName(), expectedInputLength, actualInputLength) + return nil, fmt.Errorf("%s takes %d inputs. Received %d", b.Name, expectedInputLength, actualInputLength) } /** Convert inputs to reflect values **/ diff --git a/v2/internal/binding/db.go b/v2/internal/binding/db.go index f7b793839..37c369720 100644 --- a/v2/internal/binding/db.go +++ b/v2/internal/binding/db.go @@ -15,29 +15,21 @@ type DB struct { // It used for performance gains at runtime methodMap map[string]*BoundMethod - // This uses ids to reference bound methods at runtime - obfuscatedMethodArray []*ObfuscatedMethod - // Lock to ensure sync access to the data lock sync.RWMutex } -type ObfuscatedMethod struct { - method *BoundMethod - methodName string -} - func newDB() *DB { return &DB{ - store: make(map[string]map[string]map[string]*BoundMethod), - methodMap: make(map[string]*BoundMethod), - obfuscatedMethodArray: []*ObfuscatedMethod{}, + store: make(map[string]map[string]map[string]*BoundMethod), + methodMap: make(map[string]*BoundMethod), } } // GetMethodFromStore returns the method for the given package/struct/method names // nil is returned if any one of those does not exist func (d *DB) GetMethodFromStore(packageName string, structName string, methodName string) *BoundMethod { + // Lock the db whilst processing and unlock on return d.lock.RLock() defer d.lock.RUnlock() @@ -56,6 +48,7 @@ func (d *DB) GetMethodFromStore(packageName string, structName string, methodNam // GetMethod returns the method for the given qualified method name // qualifiedMethodName is "packagename.structname.methodname" func (d *DB) GetMethod(qualifiedMethodName string) *BoundMethod { + // Lock the db whilst processing and unlock on return d.lock.RLock() defer d.lock.RUnlock() @@ -63,21 +56,11 @@ func (d *DB) GetMethod(qualifiedMethodName string) *BoundMethod { return d.methodMap[qualifiedMethodName] } -// GetObfuscatedMethod returns the method for the given ID -func (d *DB) GetObfuscatedMethod(id int) *BoundMethod { - // Lock the db whilst processing and unlock on return - d.lock.RLock() - defer d.lock.RUnlock() - - if len(d.obfuscatedMethodArray) <= id { - return nil - } - - return d.obfuscatedMethodArray[id].method -} - // AddMethod adds the given method definition to the db using the given qualified path: packageName.structName.methodName func (d *DB) AddMethod(packageName string, structName string, methodName string, methodDefinition *BoundMethod) { + + // TODO: Validate inputs? + // Lock the db whilst processing and unlock on return d.lock.Lock() defer d.lock.Unlock() @@ -104,31 +87,18 @@ func (d *DB) AddMethod(packageName string, structName string, methodName string, // Store in the methodMap key := packageName + "." + structName + "." + methodName d.methodMap[key] = methodDefinition - d.obfuscatedMethodArray = append(d.obfuscatedMethodArray, &ObfuscatedMethod{method: methodDefinition, methodName: key}) + } // ToJSON converts the method map to JSON func (d *DB) ToJSON() (string, error) { + // Lock the db whilst processing and unlock on return d.lock.RLock() defer d.lock.RUnlock() - d.UpdateObfuscatedCallMap() - bytes, err := json.Marshal(&d.store) // Return zero copy string as this string will be read only - result := *(*string)(unsafe.Pointer(&bytes)) - return result, err -} - -// UpdateObfuscatedCallMap sets up the secure call mappings -func (d *DB) UpdateObfuscatedCallMap() map[string]int { - mappings := make(map[string]int) - - for id, k := range d.obfuscatedMethodArray { - mappings[k.methodName] = id - } - - return mappings + return *(*string)(unsafe.Pointer(&bytes)), err } diff --git a/v2/internal/binding/generate.go b/v2/internal/binding/generate.go index 77edc983d..dd90f2ae0 100644 --- a/v2/internal/binding/generate.go +++ b/v2/internal/binding/generate.go @@ -6,8 +6,6 @@ import ( "fmt" "os" "path/filepath" - "regexp" - "sort" "strings" "github.com/wailsapp/wails/v2/internal/fs" @@ -15,234 +13,137 @@ import ( "github.com/leaanthony/slicer" ) -var ( - mapRegex *regexp.Regexp - keyPackageIndex int - keyTypeIndex int - valueArrayIndex int - valuePackageIndex int - valueTypeIndex int -) +//go:embed assets/package.json +var packageJSON []byte -func init() { - mapRegex = regexp.MustCompile(`(?:map\[(?:(?P\w+)\.)?(?P\w+)])?(?P\[])?(?:\*?(?P\w+)\.)?(?P.+)`) - keyPackageIndex = mapRegex.SubexpIndex("keyPackage") - keyTypeIndex = mapRegex.SubexpIndex("keyType") - valueArrayIndex = mapRegex.SubexpIndex("valueArray") - valuePackageIndex = mapRegex.SubexpIndex("valuePackage") - valueTypeIndex = mapRegex.SubexpIndex("valueType") -} +func (b *Bindings) GenerateBackendJS(targetfile string, isDevBindings bool) error { -func (b *Bindings) GenerateGoBindings(baseDir string) error { store := b.db.store - var obfuscatedBindings map[string]int - if b.obfuscate { - obfuscatedBindings = b.db.UpdateObfuscatedCallMap() - } - for packageName, structs := range store { - packageDir := filepath.Join(baseDir, packageName) - err := fs.Mkdir(packageDir) - if err != nil { - return err - } - for structName, methods := range structs { - var jsoutput bytes.Buffer - jsoutput.WriteString(`// @ts-check + var output bytes.Buffer + + output.WriteString(`// @ts-check // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL // This file is automatically generated. DO NOT EDIT `) - var tsBody bytes.Buffer - var tsContent bytes.Buffer - tsContent.WriteString(`// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT -`) - // Sort the method names alphabetically - methodNames := make([]string, 0, len(methods)) - for methodName := range methods { - methodNames = append(methodNames, methodName) + + if isDevBindings { + json, err := b.ToJSON() + if err != nil { + return err + } + output.WriteString("window.wailsbindings = " + json + ";") + output.WriteString("\n") + } + + output.WriteString(`const go = {`) + output.WriteString("\n") + + var sortedPackageNames slicer.StringSlicer + for packageName := range store { + sortedPackageNames.Add(packageName) + } + sortedPackageNames.Sort() + sortedPackageNames.Each(func(packageName string) { + packages := store[packageName] + output.WriteString(fmt.Sprintf(" \"%s\": {", packageName)) + output.WriteString("\n") + var sortedStructNames slicer.StringSlicer + for structName := range packages { + sortedStructNames.Add(structName) + } + sortedStructNames.Sort() + + sortedStructNames.Each(func(structName string) { + structs := packages[structName] + output.WriteString(fmt.Sprintf(" \"%s\": {", structName)) + output.WriteString("\n") + + var sortedMethodNames slicer.StringSlicer + for methodName := range structs { + sortedMethodNames.Add(methodName) } - sort.Strings(methodNames) + sortedMethodNames.Sort() - var importNamespaces slicer.StringSlicer - for _, methodName := range methodNames { - // Get the method details - methodDetails := methods[methodName] - - // Generate JS + sortedMethodNames.Each(func(methodName string) { + methodDetails := structs[methodName] + output.WriteString(" /**\n") + output.WriteString(" * " + methodName + "\n") var args slicer.StringSlicer - for count := range methodDetails.Inputs { - arg := fmt.Sprintf("arg%d", count+1) - args.Add(arg) - } - argsString := args.Join(", ") - jsoutput.WriteString(fmt.Sprintf("\nexport function %s(%s) {", methodName, argsString)) - jsoutput.WriteString("\n") - if b.obfuscate { - id := obfuscatedBindings[strings.Join([]string{packageName, structName, methodName}, ".")] - jsoutput.WriteString(fmt.Sprintf(" return ObfuscatedCall(%d, [%s]);", id, argsString)) - } else { - jsoutput.WriteString(fmt.Sprintf(" return window['go']['%s']['%s']['%s'](%s);", packageName, structName, methodName, argsString)) - } - jsoutput.WriteString("\n}\n") - - // Generate TS - tsBody.WriteString(fmt.Sprintf("\nexport function %s(", methodName)) - - args.Clear() for count, input := range methodDetails.Inputs { arg := fmt.Sprintf("arg%d", count+1) - entityName := entityFullReturnType(input.TypeName, b.tsPrefix, b.tsSuffix, &importNamespaces) - args.Add(arg + ":" + goTypeToTypescriptType(entityName, &importNamespaces)) + args.Add(arg) + output.WriteString(fmt.Sprintf(" * @param {%s} %s - Go Type: %s\n", goTypeToJSDocType(input.TypeName), arg, input.TypeName)) } - tsBody.WriteString(args.Join(",") + "):") - // now build Typescript return types - // If there is no return value or only returning error, TS returns Promise - // If returning single value, TS returns Promise - // If returning single value or error, TS returns Promise - // If returning two values, TS returns Promise - // Otherwise, TS returns Promise (instead of throwing Go error?) - var returnType string - if methodDetails.OutputCount() == 0 { - returnType = "Promise" - } else if methodDetails.OutputCount() == 1 && methodDetails.Outputs[0].TypeName == "error" { - returnType = "Promise" - } else { - outputTypeName := entityFullReturnType(methodDetails.Outputs[0].TypeName, b.tsPrefix, b.tsSuffix, &importNamespaces) - firstType := goTypeToTypescriptType(outputTypeName, &importNamespaces) - returnType = "Promise<" + firstType - if methodDetails.OutputCount() == 2 && methodDetails.Outputs[1].TypeName != "error" { - outputTypeName = entityFullReturnType(methodDetails.Outputs[1].TypeName, b.tsPrefix, b.tsSuffix, &importNamespaces) - secondType := goTypeToTypescriptType(outputTypeName, &importNamespaces) + returnType := "Promise" + returnTypeDetails := "" + if methodDetails.OutputCount() > 0 { + firstType := goTypeToJSDocType(methodDetails.Outputs[0].TypeName) + returnType += "<" + firstType + if methodDetails.OutputCount() == 2 { + secondType := goTypeToJSDocType(methodDetails.Outputs[1].TypeName) returnType += "|" + secondType } returnType += ">" + returnTypeDetails = " - Go Type: " + methodDetails.Outputs[0].TypeName + } else { + returnType = "Promise" } - tsBody.WriteString(returnType + ";\n") - } + output.WriteString(" * @returns {" + returnType + "} " + returnTypeDetails + "\n") + output.WriteString(" */\n") + argsString := args.Join(", ") + output.WriteString(fmt.Sprintf(" \"%s\": (%s) => {", methodName, argsString)) + output.WriteString("\n") + output.WriteString(fmt.Sprintf(" return window.go.%s.%s.%s(%s);", packageName, structName, methodName, argsString)) + output.WriteString("\n") + output.WriteString(fmt.Sprintf(" },")) + output.WriteString("\n") - importNamespaces.Deduplicate() - importNamespaces.Each(func(namespace string) { - tsContent.WriteString("import {" + namespace + "} from '../models';\n") }) - tsContent.WriteString(tsBody.String()) - jsfilename := filepath.Join(packageDir, structName+".js") - err = os.WriteFile(jsfilename, jsoutput.Bytes(), 0o755) - if err != nil { - return err - } - tsfilename := filepath.Join(packageDir, structName+".d.ts") - err = os.WriteFile(tsfilename, tsContent.Bytes(), 0o755) - if err != nil { - return err - } + output.WriteString(" },\n") + }) + + output.WriteString(" },\n\n") + }) + + output.WriteString(`}; +export default go;`) + output.WriteString("\n") + + dir := filepath.Dir(targetfile) + packageJsonFile := filepath.Join(dir, "package.json") + if !fs.FileExists(packageJsonFile) { + err := os.WriteFile(packageJsonFile, packageJSON, 0755) + if err != nil { + return err } } - err := b.WriteModels(baseDir) - if err != nil { - return err - } - return nil + + return os.WriteFile(targetfile, output.Bytes(), 0755) } -func fullyQualifiedName(packageName string, typeName string) string { - if len(packageName) > 0 { - return packageName + "." + typeName - } - +func goTypeToJSDocType(input string) string { switch true { - case len(typeName) == 0: - return "" - case typeName == "interface{}" || typeName == "interface {}": - return "any" - case typeName == "string": + case input == "string": return "string" - case typeName == "error": + case input == "error": return "Error" case - strings.HasPrefix(typeName, "int"), - strings.HasPrefix(typeName, "uint"), - strings.HasPrefix(typeName, "float"): + strings.HasPrefix(input, "int"), + strings.HasPrefix(input, "uint"), + strings.HasPrefix(input, "float"): return "number" - case typeName == "bool": + case input == "bool": return "boolean" + case input == "[]byte": + return "string" + case strings.HasPrefix(input, "[]"): + arrayType := goTypeToJSDocType(input[2:]) + return "Array.<" + arrayType + ">" default: + if strings.ContainsRune(input, '.') { + return strings.Split(input, ".")[1] + } return "any" } } - -var ( - jsVariableUnsafeChars = regexp.MustCompile(`[^A-Za-z0-9_]`) -) - -func arrayifyValue(valueArray string, valueType string) string { - valueType = strings.ReplaceAll(valueType, "*", "") - gidx := strings.IndexRune(valueType, '[') - if gidx > 0 { // its a generic type - rem := strings.SplitN(valueType, "[", 2) - valueType = rem[0] + "_" + jsVariableUnsafeChars.ReplaceAllLiteralString(rem[1], "_") - } - - if len(valueArray) == 0 { - return valueType - } - - return "Array<" + valueType + ">" -} - -func goTypeToJSDocType(input string, importNamespaces *slicer.StringSlicer) string { - matches := mapRegex.FindStringSubmatch(input) - keyPackage := matches[keyPackageIndex] - keyType := matches[keyTypeIndex] - valueArray := matches[valueArrayIndex] - valuePackage := matches[valuePackageIndex] - valueType := matches[valueTypeIndex] - // fmt.Printf("input=%s, keyPackage=%s, keyType=%s, valueArray=%s, valuePackage=%s, valueType=%s\n", - // input, - // keyPackage, - // keyType, - // valueArray, - // valuePackage, - // valueType) - - // byte array is special case - if valueArray == "[]" && valueType == "byte" { - return "string" - } - - // if any packages, make sure they're saved - if len(keyPackage) > 0 { - importNamespaces.Add(keyPackage) - } - - if len(valuePackage) > 0 { - importNamespaces.Add(valuePackage) - } - - key := fullyQualifiedName(keyPackage, keyType) - var value string - if strings.HasPrefix(valueType, "map") { - value = goTypeToJSDocType(valueType, importNamespaces) - } else { - value = fullyQualifiedName(valuePackage, valueType) - } - - if len(key) > 0 { - return fmt.Sprintf("Record<%s, %s>", key, arrayifyValue(valueArray, value)) - } - - return arrayifyValue(valueArray, value) -} - -func goTypeToTypescriptType(input string, importNamespaces *slicer.StringSlicer) string { - return goTypeToJSDocType(input, importNamespaces) -} - -func entityFullReturnType(input, prefix, suffix string, importNamespaces *slicer.StringSlicer) string { - if strings.ContainsRune(input, '.') { - nameSpace, returnType := getSplitReturn(input) - return nameSpace + "." + prefix + returnType + suffix - } - - return input -} diff --git a/v2/internal/binding/generate_test.go b/v2/internal/binding/generate_test.go index 26d7c70df..e2751ceb5 100644 --- a/v2/internal/binding/generate_test.go +++ b/v2/internal/binding/generate_test.go @@ -2,40 +2,8 @@ package binding import ( "testing" - - "github.com/leaanthony/slicer" - "github.com/stretchr/testify/assert" - "github.com/wailsapp/wails/v2/internal/logger" ) -type BindForTest struct { -} - -func (b *BindForTest) GetA() A { - return A{} -} - -type A struct { - B B `json:"B"` -} - -type B struct { - Name string `json:"name"` -} - -func TestNestedStruct(t *testing.T) { - bind := &BindForTest{} - testBindings := NewBindings(logger.New(nil), []interface{}{bind}, []interface{}{}, false, []interface{}{}) - - namesStrSlicer := testBindings.getAllStructNames() - names := []string{} - namesStrSlicer.Each(func(s string) { - names = append(names, s) - }) - assert.Contains(t, names, "binding.A") - assert.Contains(t, names, "binding.B") -} - func Test_goTypeToJSDocType(t *testing.T) { tests := []struct { @@ -88,11 +56,6 @@ func Test_goTypeToJSDocType(t *testing.T) { input: "bool", want: "boolean", }, - { - name: "interface{}", - input: "interface{}", - want: "any", - }, { name: "[]byte", input: "[]byte", @@ -101,48 +64,22 @@ func Test_goTypeToJSDocType(t *testing.T) { { name: "[]int", input: "[]int", - want: "Array", + want: "Array.", }, { name: "[]bool", input: "[]bool", - want: "Array", + want: "Array.", }, { name: "anything else", input: "foo", want: "any", }, - { - name: "map", - input: "map[string]float64", - want: "Record", - }, - { - name: "map", - input: "map[string]map[string]float64", - want: "Record>", - }, - { - name: "types", - input: "main.SomeType", - want: "main.SomeType", - }, - { - name: "primitive_generic", - input: "main.ListData[string]", - want: "main.ListData_string_", - }, - { - name: "stdlib_generic", - input: "main.ListData[*net/http.Request]", - want: "main.ListData_net_http_Request_", - }, } - var importNamespaces slicer.StringSlicer for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := goTypeToJSDocType(tt.input, &importNamespaces); got != tt.want { + if got := goTypeToJSDocType(tt.input); got != tt.want { t.Errorf("goTypeToJSDocType() = %v, want %v", got, tt.want) } }) diff --git a/v2/internal/binding/reflect.go b/v2/internal/binding/reflect.go old mode 100644 new mode 100755 index c254d0f0a..3b79428f0 --- a/v2/internal/binding/reflect.go +++ b/v2/internal/binding/reflect.go @@ -4,7 +4,6 @@ import ( "fmt" "reflect" "runtime" - "strings" ) // isStructPtr returns true if the value given is a @@ -19,32 +18,13 @@ func isFunction(value interface{}) bool { return reflect.ValueOf(value).Kind() == reflect.Func } -// isStruct returns true if the value given is a struct +// isStructPtr returns true if the value given is a struct func isStruct(value interface{}) bool { return reflect.ValueOf(value).Kind() == reflect.Struct } -func normalizeStructName(name string) string { - return strings.ReplaceAll( - strings.ReplaceAll( - strings.ReplaceAll( - strings.ReplaceAll( - name, - ",", - "-", - ), - "*", - "", - ), - "]", - "__", - ), - "[", - "__", - ) -} - func (b *Bindings) getMethods(value interface{}) ([]*BoundMethod, error) { + // Create result placeholder var result []*BoundMethod @@ -67,14 +47,13 @@ func (b *Bindings) getMethods(value interface{}) ([]*BoundMethod, error) { // Process Struct structType := reflect.TypeOf(value) structValue := reflect.ValueOf(value) - structName := structType.Elem().Name() - structNameNormalized := normalizeStructName(structName) - pkgPath := strings.TrimSuffix(structType.Elem().String(), fmt.Sprintf(".%s", structName)) + baseName := structType.String()[1:] // Process Methods for i := 0; i < structType.NumMethod(); i++ { methodDef := structType.Method(i) methodName := methodDef.Name + fullMethodName := baseName + "." + methodName method := structValue.MethodByName(methodName) methodReflectName := runtime.FuncForPC(methodDef.Func.Pointer()).Name() @@ -84,11 +63,7 @@ func (b *Bindings) getMethods(value interface{}) ([]*BoundMethod, error) { // Create new method boundMethod := &BoundMethod{ - Path: &BoundedMethodPath{ - Package: pkgPath, - Struct: structNameNormalized, - Name: methodName, - }, + Name: fullMethodName, Inputs: nil, Outputs: nil, Comments: "", @@ -103,31 +78,21 @@ func (b *Bindings) getMethods(value interface{}) ([]*BoundMethod, error) { input := methodType.In(inputIndex) thisParam := newParameter("", input) - thisInput := input - - if thisInput.Kind() == reflect.Slice { - thisInput = thisInput.Elem() - } - // Process struct pointer params - if thisInput.Kind() == reflect.Ptr { - if thisInput.Elem().Kind() == reflect.Struct { - typ := thisInput.Elem() + if input.Kind() == reflect.Ptr { + if input.Elem().Kind() == reflect.Struct { + typ := input.Elem() a := reflect.New(typ) s := reflect.Indirect(a).Interface() - name := typ.Name() - packageName := getPackageName(thisInput.String()) - b.AddStructToGenerateTS(packageName, name, s) + b.converter.Add(s) } } // Process struct params - if thisInput.Kind() == reflect.Struct { - a := reflect.New(thisInput) + if input.Kind() == reflect.Struct { + a := reflect.New(input) s := reflect.Indirect(a).Interface() - name := thisInput.Name() - packageName := getPackageName(thisInput.String()) - b.AddStructToGenerateTS(packageName, name, s) + b.converter.Add(s) } inputs = append(inputs, thisParam) @@ -143,34 +108,6 @@ func (b *Bindings) getMethods(value interface{}) ([]*BoundMethod, error) { for outputIndex := 0; outputIndex < outputParamCount; outputIndex++ { output := methodType.Out(outputIndex) thisParam := newParameter("", output) - - thisOutput := output - - if thisOutput.Kind() == reflect.Slice { - thisOutput = thisOutput.Elem() - } - - // Process struct pointer params - if thisOutput.Kind() == reflect.Ptr { - if thisOutput.Elem().Kind() == reflect.Struct { - typ := thisOutput.Elem() - a := reflect.New(typ) - s := reflect.Indirect(a).Interface() - name := typ.Name() - packageName := getPackageName(thisOutput.String()) - b.AddStructToGenerateTS(packageName, name, s) - } - } - - // Process struct params - if thisOutput.Kind() == reflect.Struct { - a := reflect.New(thisOutput) - s := reflect.Indirect(a).Interface() - name := thisOutput.Name() - packageName := getPackageName(thisOutput.String()) - b.AddStructToGenerateTS(packageName, name, s) - } - outputs = append(outputs, thisParam) } boundMethod.Outputs = outputs @@ -181,20 +118,3 @@ func (b *Bindings) getMethods(value interface{}) ([]*BoundMethod, error) { } return result, nil } - -func getPackageName(in string) string { - result := strings.Split(in, ".")[0] - result = strings.ReplaceAll(result, "[]", "") - result = strings.ReplaceAll(result, "*", "") - return result -} - -func getSplitReturn(in string) (string, string) { - result := strings.SplitN(in, ".", 2) - return result[0], result[1] -} - -func hasElements(typ reflect.Type) bool { - kind := typ.Kind() - return kind == reflect.Ptr || kind == reflect.Array || kind == reflect.Slice || kind == reflect.Map -} diff --git a/v2/internal/bridge/bridge.go b/v2/internal/bridge/bridge.go new file mode 100644 index 000000000..1ea509d33 --- /dev/null +++ b/v2/internal/bridge/bridge.go @@ -0,0 +1,113 @@ +package bridge + +import ( + "context" + "log" + "net/http" + "sync" + + "github.com/wailsapp/wails/v2/internal/menumanager" + + "github.com/wailsapp/wails/v2/internal/messagedispatcher" + + "github.com/gorilla/websocket" + "github.com/wailsapp/wails/v2/internal/logger" +) + +type Bridge struct { + upgrader websocket.Upgrader + server *http.Server + myLogger *logger.Logger + + bindings string + dispatcher *messagedispatcher.Dispatcher + + mu sync.Mutex + sessions map[string]*session + + ctx context.Context + cancel context.CancelFunc + + // Dialog client + dialog *messagedispatcher.DispatchClient + + // Menus + menumanager *menumanager.Manager +} + +func NewBridge(myLogger *logger.Logger) *Bridge { + result := &Bridge{ + myLogger: myLogger, + upgrader: websocket.Upgrader{CheckOrigin: func(r *http.Request) bool { return true }}, + sessions: make(map[string]*session), + } + + myLogger.SetLogLevel(1) + + ctx, cancel := context.WithCancel(context.Background()) + result.ctx = ctx + result.cancel = cancel + result.server = &http.Server{Addr: ":34115"} + http.HandleFunc("/bridge", result.wsBridgeHandler) + return result +} + +func (b *Bridge) Run(dispatcher *messagedispatcher.Dispatcher, menumanager *menumanager.Manager, bindings string, debug bool) error { + + // Ensure we cancel the context when we shutdown + defer b.cancel() + + b.bindings = bindings + b.dispatcher = dispatcher + b.menumanager = menumanager + + // Setup dialog handler + dialogClient := NewDialogClient(b.myLogger) + b.dialog = dispatcher.RegisterClient(dialogClient) + dialogClient.dispatcher = b.dialog + + b.myLogger.Info("Bridge mode started.") + + err := b.server.ListenAndServe() + if err != nil && err != http.ErrServerClosed { + return err + } + + return nil +} + +func (b *Bridge) wsBridgeHandler(w http.ResponseWriter, r *http.Request) { + c, err := b.upgrader.Upgrade(w, r, nil) + if err != nil { + log.Print("upgrade:", err) + return + } + + if err != nil { + http.Error(w, "Could not open websocket connection", http.StatusBadRequest) + } + b.myLogger.Info("Connection from frontend accepted [%s].", c.RemoteAddr().String()) + b.startSession(c) + +} + +func (b *Bridge) startSession(conn *websocket.Conn) { + + // Create a new session for this connection + s := newSession(conn, b.menumanager, b.bindings, b.dispatcher, b.myLogger, b.ctx) + + // Setup the close handler + conn.SetCloseHandler(func(int, string) error { + b.myLogger.Info("Connection dropped [%s].", s.Identifier()) + b.dispatcher.RemoveClient(s.client) + b.mu.Lock() + delete(b.sessions, s.Identifier()) + b.mu.Unlock() + return nil + }) + + b.mu.Lock() + go s.start(len(b.sessions) == 0) + b.sessions[s.Identifier()] = s + b.mu.Unlock() +} diff --git a/v2/internal/bridge/client.go b/v2/internal/bridge/client.go new file mode 100644 index 000000000..f65cffc20 --- /dev/null +++ b/v2/internal/bridge/client.go @@ -0,0 +1,141 @@ +package bridge + +import ( + "github.com/wailsapp/wails/v2/pkg/runtime" +) + +type BridgeClient struct { + session *session + + // Tray menu cache to send to reconnecting clients + messageCache chan string +} + +func (b BridgeClient) DeleteTrayMenuByID(id string) { + b.session.sendMessage("TD" + id) +} + +func NewBridgeClient() *BridgeClient { + return &BridgeClient{ + messageCache: make(chan string, 100), + } +} + +func (b BridgeClient) Quit() { + b.session.log.Info("Quit unsupported in Bridge mode") +} + +func (b BridgeClient) NotifyEvent(message string) { + b.session.sendMessage("n" + message) + b.session.log.Info("Notify: %s", message) +} + +func (b BridgeClient) CallResult(message string) { + b.session.sendMessage("c" + message) +} + +func (b BridgeClient) OpenFileDialog(dialogOptions runtime.OpenDialogOptions, callbackID string) { + // Handled by dialog_client +} + +func (b BridgeClient) OpenMultipleFilesDialog(dialogOptions runtime.OpenDialogOptions, callbackID string) { + // Handled by dialog_client +} + +func (b BridgeClient) OpenDirectoryDialog(dialogOptions runtime.OpenDialogOptions, callbackID string) { + // Handled by dialog_client +} + +func (b BridgeClient) SaveDialog(dialogOptions runtime.SaveDialogOptions, callbackID string) { + // Handled by dialog_client +} + +func (b BridgeClient) MessageDialog(dialogOptions runtime.MessageDialogOptions, callbackID string) { + // Handled by dialog_client +} + +func (b BridgeClient) WindowSetTitle(title string) { + b.session.log.Info("WindowSetTitle unsupported in Bridge mode") +} + +func (b BridgeClient) WindowShow() { + b.session.log.Info("WindowShow unsupported in Bridge mode") +} + +func (b BridgeClient) WindowHide() { + b.session.log.Info("WindowHide unsupported in Bridge mode") +} + +func (b BridgeClient) WindowCenter() { + b.session.log.Info("WindowCenter unsupported in Bridge mode") +} + +func (b BridgeClient) WindowMaximise() { + b.session.log.Info("WindowMaximise unsupported in Bridge mode") +} + +func (b BridgeClient) WindowUnmaximise() { + b.session.log.Info("WindowUnmaximise unsupported in Bridge mode") +} + +func (b BridgeClient) WindowMinimise() { + b.session.log.Info("WindowMinimise unsupported in Bridge mode") +} + +func (b BridgeClient) WindowUnminimise() { + b.session.log.Info("WindowUnminimise unsupported in Bridge mode") +} + +func (b BridgeClient) WindowPosition(x int, y int) { + b.session.log.Info("WindowPosition unsupported in Bridge mode") +} + +func (b BridgeClient) WindowSize(width int, height int) { + b.session.log.Info("WindowSize unsupported in Bridge mode") +} + +func (b BridgeClient) WindowSetMinSize(width int, height int) { + b.session.log.Info("WindowSetMinSize unsupported in Bridge mode") +} + +func (b BridgeClient) WindowSetMaxSize(width int, height int) { + b.session.log.Info("WindowSetMaxSize unsupported in Bridge mode") +} + +func (b BridgeClient) WindowFullscreen() { + b.session.log.Info("WindowFullscreen unsupported in Bridge mode") +} + +func (b BridgeClient) WindowUnFullscreen() { + b.session.log.Info("WindowUnFullscreen unsupported in Bridge mode") +} + +func (b BridgeClient) WindowSetColour(colour int) { + b.session.log.Info("WindowSetColour unsupported in Bridge mode") +} + +func (b BridgeClient) DarkModeEnabled(callbackID string) { + b.session.log.Info("DarkModeEnabled unsupported in Bridge mode") +} + +func (b BridgeClient) MenuSetApplicationMenu(menuJSON string) { + b.session.log.Info("MenuSetApplicationMenu unsupported in Bridge mode") +} + +func (b BridgeClient) SetTrayMenu(trayMenuJSON string) { + b.session.sendMessage("TS" + trayMenuJSON) +} + +func (b BridgeClient) UpdateTrayMenuLabel(trayMenuJSON string) { + b.session.sendMessage("TU" + trayMenuJSON) +} + +func (b BridgeClient) UpdateContextMenu(contextMenuJSON string) { + b.session.log.Info("UpdateContextMenu unsupported in Bridge mode") +} + +func newBridgeClient(session *session) *BridgeClient { + return &BridgeClient{ + session: session, + } +} diff --git a/v2/internal/bridge/darwin.js b/v2/internal/bridge/darwin.js new file mode 100644 index 000000000..4758b4e29 --- /dev/null +++ b/v2/internal/bridge/darwin.js @@ -0,0 +1 @@ +var Wails=function(n){var t={};function e(r){if(t[r])return t[r].exports;var i=t[r]={i:r,l:!1,exports:{}};return n[r].call(i.exports,i,i.exports,e),i.l=!0,i.exports}return e.m=n,e.c=t,e.d=function(n,t,r){e.o(n,t)||Object.defineProperty(n,t,{enumerable:!0,get:r})},e.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},e.t=function(n,t){if(1&t&&(n=e(n)),8&t)return n;if(4&t&&"object"==typeof n&&n&&n.__esModule)return n;var r=Object.create(null);if(e.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:n}),2&t&&"string"!=typeof n)for(var i in n)e.d(r,i,function(t){return n[t]}.bind(null,i));return r},e.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return e.d(t,"a",t),t},e.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},e.p="",e(e.s=0)}([function(n,t,e){"use strict";e.r(t);var r={};e.r(r),e.d(r,"Trace",(function(){return v})),e.d(r,"Print",(function(){return p})),e.d(r,"Debug",(function(){return y})),e.d(r,"Info",(function(){return m})),e.d(r,"Warning",(function(){return b})),e.d(r,"Error",(function(){return g})),e.d(r,"Fatal",(function(){return h})),e.d(r,"SetLogLevel",(function(){return S})),e.d(r,"Level",(function(){return E}));var i={};e.r(i),e.d(i,"Open",(function(){return x}));var o={};e.r(o),e.d(o,"Center",(function(){return N})),e.d(o,"SetTitle",(function(){return T})),e.d(o,"Fullscreen",(function(){return j})),e.d(o,"UnFullscreen",(function(){return D})),e.d(o,"SetSize",(function(){return I})),e.d(o,"SetPosition",(function(){return P})),e.d(o,"Hide",(function(){return A})),e.d(o,"Show",(function(){return J})),e.d(o,"Maximise",(function(){return L})),e.d(o,"Unmaximise",(function(){return R})),e.d(o,"Minimise",(function(){return _})),e.d(o,"Unminimise",(function(){return F})),e.d(o,"Close",(function(){return U}));var a={};e.r(a),e.d(a,"Open",(function(){return B})),e.d(a,"Save",(function(){return H})),e.d(a,"Message",(function(){return G}));var u={};e.r(u),e.d(u,"New",(function(){return en}));var c={};e.r(c),e.d(c,"SetIcon",(function(){return rn}));var l={AppType:"desktop",Platform:function(){return"darwin"}};var s=[];function f(n){s.push(n)}function d(n){if(function(n){window.wailsInvoke(n)}(n),s.length>0)for(var t=0;t0)var a=setTimeout((function(){i(Error("Call to "+n+" timed out. Request ID: "+o))}),e);k[o]={timeoutHandle:a,reject:i,resolve:r};try{var u={name:n,args:t,callbackID:o};d("C"+JSON.stringify(u))}catch(n){console.error(n)}}))}function W(n){var t;try{t=JSON.parse(n)}catch(t){var e="Invalid JSON passed to callback: ".concat(t.message,". Message: ").concat(n);throw y(e),new Error(e)}var r=t.callbackid,i=k[r];if(!i){var o="Callback '".concat(r,"' not registered!!!");throw console.error(o),new Error(o)}clearTimeout(i.timeoutHandle),delete k[r],t.error?i.reject(t.error):i.resolve(t.result)}function M(n){var t=[].slice.apply(arguments).slice(1);return C(".wails."+n,t)}function x(n){return d("RBO"+n)}function N(){d("Wc")}function T(n){d("WT"+n)}function j(){d("WF")}function D(){d("Wf")}function I(n,t){d("Ws:"+n+":"+t)}function P(n,t){d("Wp:"+n+":"+t)}function A(){d("WH")}function J(){d("WS")}function L(){d("WM")}function R(){d("WU")}function _(){d("Wm")}function F(){d("Wu")}function U(){d("WC")}function B(n){return M("Dialog.Open",n)}function H(n){return M("Dialog.Save",n)}function G(n){return M("Dialog.Message",n)}O=window.crypto?function(){var n=new Uint32Array(1);return window.crypto.getRandomValues(n)[0]}:function(){return 9007199254740991*Math.random()},window.backend={};var q=function n(t,e){!function(n,t){if(!(n instanceof t))throw new TypeError("Cannot call a class as a function")}(this,n),e=e||-1,this.Callback=function(n){return t.apply(null,n),-1!==e&&0===(e-=1)}},z={};function V(n,t,e){z[n]=z[n]||[];var r=new q(t,e);console.log("Pushing event listener: "+n),z[n].push(r)}function K(n,t){V(n,t)}function Q(n,t){V(n,t,1)}function X(n){var t=n.name;if(z[t]){for(var e=z[t].slice(),r=0;r0)for(var t=0;t0)var a=setTimeout((function(){i(Error("Call to "+n+" timed out. Request ID: "+o))}),e);k[o]={timeoutHandle:a,reject:i,resolve:r};try{var u={name:n,args:t,callbackID:o};d("C"+JSON.stringify(u))}catch(n){console.error(n)}}))}function W(n){var t;try{t=JSON.parse(n)}catch(t){var e="Invalid JSON passed to callback: ".concat(t.message,". Message: ").concat(n);throw y(e),new Error(e)}var r=t.callbackid,i=k[r];if(!i){var o="Callback '".concat(r,"' not registered!!!");throw console.error(o),new Error(o)}clearTimeout(i.timeoutHandle),delete k[r],t.error?i.reject(t.error):i.resolve(t.result)}function x(n){var t=[].slice.apply(arguments).slice(1);return C(".wails."+n,t)}function M(n){return d("RBO"+n)}function N(){d("Wc")}function T(n){d("WT"+n)}function j(){d("WF")}function D(){d("Wf")}function I(n,t){d("Ws:"+n+":"+t)}function P(n,t){d("Wp:"+n+":"+t)}function A(){d("WH")}function J(){d("WS")}function L(){d("WM")}function R(){d("WU")}function _(){d("Wm")}function F(){d("Wu")}function U(){d("WC")}function B(n){return x("Dialog.Open",n)}function H(n){return x("Dialog.Save",n)}function G(n){return x("Dialog.Message",n)}O=window.crypto?function(){var n=new Uint32Array(1);return window.crypto.getRandomValues(n)[0]}:function(){return 9007199254740991*Math.random()},window.backend={};var q=function n(t,e){!function(n,t){if(!(n instanceof t))throw new TypeError("Cannot call a class as a function")}(this,n),e=e||-1,this.Callback=function(n){return t.apply(null,n),-1!==e&&0===(e-=1)}},z={};function V(n,t,e){z[n]=z[n]||[];var r=new q(t,e);console.log("Pushing event listener: "+n),z[n].push(r)}function K(n,t){V(n,t)}function Q(n,t){V(n,t,1)}function X(n){var t=n.name;if(z[t]){for(var e=z[t].slice(),r=0;r:. +func (s *session) Identifier() string { + if s.conn != nil { + return s.conn.RemoteAddr().String() + } + return "" +} + +func (s *session) sendMessage(msg string) error { + if !s.done { + s.writeChan <- []byte(msg) + } + return nil +} + +func (s *session) start(firstSession bool) { + s.log.SetLogLevel(1) + s.log.Info("Connected to frontend.") + go s.writePump() + + var wailsRuntime string + switch runtime.GOOS { + case "darwin": + wailsRuntime = darwinRuntime + case "windows": + wailsRuntime = windowsRuntime + case "linux": + wailsRuntime = linuxRuntime + default: + log.Fatal("platform not supported") + } + + bindingsMessage := "window.wailsbindings = `" + s.bindings + "`;" + s.log.Info(bindingsMessage) + bootstrapMessage := bindingsMessage + wailsRuntime + + err := s.sendMessage("b" + bootstrapMessage) + if err != nil { + s.log.Error(err.Error()) + } + + // Send menus + traymenus, err := s.menumanager.GetTrayMenus() + if err != nil { + s.log.Error(err.Error()) + } + + for _, trayMenu := range traymenus { + err := s.sendMessage("TS" + trayMenu) + if err != nil { + s.log.Error(err.Error()) + } + } + + for { + messageType, buffer, err := s.conn.ReadMessage() + if messageType == -1 { + return + } + if err != nil { + s.log.Error("Error reading message: %v", err) + err = s.conn.Close() + return + } + + message := string(buffer) + + s.log.Debug("Got message: %#v\n", message) + + // Dispatch message as normal + s.client.DispatchMessage(message) + + if s.done { + break + } + } +} + +// Shutdown +func (s *session) Shutdown() { + err := s.conn.Close() + if err != nil { + s.log.Error(err.Error()) + } + s.done = true + s.log.Info("session %v exit", s.Identifier()) +} + +// writePump pulls messages from the writeChan and sends them to the client +// since it uses a channel to read the messages the socket is protected without locks +func (s *session) writePump() { + s.log.Debug("Session %v - writePump start", s.Identifier()) + defer s.log.Debug("Session %v - writePump shutdown", s.Identifier()) + for { + select { + case <-s.ctx.Done(): + s.Shutdown() + return + case msg, ok := <-s.writeChan: + err := s.conn.SetWriteDeadline(time.Now().Add(1 * time.Second)) + if err != nil { + s.log.Error(err.Error()) + } + if !ok { + s.log.Debug("writeChan was closed!") + err := s.conn.WriteMessage(websocket.CloseMessage, []byte{}) + if err != nil { + s.log.Error(err.Error()) + } + return + } + + if err := s.conn.WriteMessage(websocket.TextMessage, msg); err != nil { + s.log.Debug(err.Error()) + return + } + } + } +} diff --git a/v2/internal/bridge/windows.js b/v2/internal/bridge/windows.js new file mode 100644 index 000000000..281f47bf1 --- /dev/null +++ b/v2/internal/bridge/windows.js @@ -0,0 +1 @@ +var Wails=function(n){var t={};function e(r){if(t[r])return t[r].exports;var i=t[r]={i:r,l:!1,exports:{}};return n[r].call(i.exports,i,i.exports,e),i.l=!0,i.exports}return e.m=n,e.c=t,e.d=function(n,t,r){e.o(n,t)||Object.defineProperty(n,t,{enumerable:!0,get:r})},e.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},e.t=function(n,t){if(1&t&&(n=e(n)),8&t)return n;if(4&t&&"object"==typeof n&&n&&n.__esModule)return n;var r=Object.create(null);if(e.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:n}),2&t&&"string"!=typeof n)for(var i in n)e.d(r,i,function(t){return n[t]}.bind(null,i));return r},e.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return e.d(t,"a",t),t},e.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},e.p="",e(e.s=0)}([function(n,t,e){"use strict";e.r(t);var r={};e.r(r),e.d(r,"Trace",(function(){return v})),e.d(r,"Print",(function(){return p})),e.d(r,"Debug",(function(){return y})),e.d(r,"Info",(function(){return m})),e.d(r,"Warning",(function(){return b})),e.d(r,"Error",(function(){return g})),e.d(r,"Fatal",(function(){return h})),e.d(r,"SetLogLevel",(function(){return S})),e.d(r,"Level",(function(){return E}));var i={};e.r(i),e.d(i,"Open",(function(){return T}));var o={};e.r(o),e.d(o,"Center",(function(){return j})),e.d(o,"SetTitle",(function(){return x})),e.d(o,"Fullscreen",(function(){return M})),e.d(o,"UnFullscreen",(function(){return I})),e.d(o,"SetSize",(function(){return D})),e.d(o,"SetPosition",(function(){return P})),e.d(o,"Hide",(function(){return A})),e.d(o,"Show",(function(){return J})),e.d(o,"Maximise",(function(){return L})),e.d(o,"Unmaximise",(function(){return R})),e.d(o,"Minimise",(function(){return _})),e.d(o,"Unminimise",(function(){return F})),e.d(o,"Close",(function(){return U}));var a={};e.r(a),e.d(a,"Open",(function(){return B})),e.d(a,"Save",(function(){return H})),e.d(a,"Message",(function(){return G}));var u={};e.r(u),e.d(u,"New",(function(){return en}));var c={};e.r(c),e.d(c,"SetIcon",(function(){return rn}));var l={AppType:"desktop",Platform:function(){return"windows"}};var s=[];function f(n){s.push(n)}function d(n){if(function(n){window.wailsInvoke(n)}(n),s.length>0)for(var t=0;t0)var a=setTimeout((function(){i(Error("Call to "+n+" timed out. Request ID: "+o))}),e);k[o]={timeoutHandle:a,reject:i,resolve:r};try{var u={name:n,args:t,callbackID:o};d("C"+JSON.stringify(u))}catch(n){console.error(n)}}))}function W(n){var t;try{t=JSON.parse(n)}catch(t){var e="Invalid JSON passed to callback: ".concat(t.message,". Message: ").concat(n);throw y(e),new Error(e)}var r=t.callbackid,i=k[r];if(!i){var o="Callback '".concat(r,"' not registered!!!");throw console.error(o),new Error(o)}clearTimeout(i.timeoutHandle),delete k[r],t.error?i.reject(t.error):i.resolve(t.result)}function N(n){var t=[].slice.apply(arguments).slice(1);return C(".wails."+n,t)}function T(n){return d("RBO"+n)}function j(){d("Wc")}function x(n){d("WT"+n)}function M(){d("WF")}function I(){d("Wf")}function D(n,t){d("Ws:"+n+":"+t)}function P(n,t){d("Wp:"+n+":"+t)}function A(){d("WH")}function J(){d("WS")}function L(){d("WM")}function R(){d("WU")}function _(){d("Wm")}function F(){d("Wu")}function U(){d("WC")}function B(n){return N("Dialog.Open",n)}function H(n){return N("Dialog.Save",n)}function G(n){return N("Dialog.Message",n)}O=window.crypto?function(){var n=new Uint32Array(1);return window.crypto.getRandomValues(n)[0]}:function(){return 9007199254740991*Math.random()},window.backend={};var q=function n(t,e){!function(n,t){if(!(n instanceof t))throw new TypeError("Cannot call a class as a function")}(this,n),e=e||-1,this.Callback=function(n){return t.apply(null,n),-1!==e&&0===(e-=1)}},z={};function V(n,t,e){z[n]=z[n]||[];var r=new q(t,e);console.log("Pushing event listener: "+n),z[n].push(r)}function K(n,t){V(n,t)}function Q(n,t){V(n,t,1)}function X(n){var t=n.name;if(z[t]){for(var e=z[t].slice(),r=0;rdata); + return -1; +} + +const char* getJSONString(JsonNode *item, const char* key) { + // Get key + JsonNode *node = json_find_member(item, key); + const char *result = ""; + if ( node != NULL && node->tag == JSON_STRING) { + result = node->string_; + } + return result; +} + +void ABORT_JSON(JsonNode *node, const char* key) { + ABORT("Unable to read required key '%s' from JSON: %s\n", key, json_encode(node)); +} + +const char* mustJSONString(JsonNode *node, const char* key) { + const char* result = getJSONString(node, key); + if ( result == NULL ) { + ABORT_JSON(node, key); + } + return result; +} +JsonNode* mustJSONObject(JsonNode *node, const char* key) { + struct JsonNode* result = getJSONObject(node, key); + if ( result == NULL ) { + ABORT_JSON(node, key); + } + return result; +} + +JsonNode* getJSONObject(JsonNode* node, const char* key) { + return json_find_member(node, key); +} + +bool getJSONBool(JsonNode *item, const char* key, bool *result) { + JsonNode *node = json_find_member(item, key); + if ( node != NULL && node->tag == JSON_BOOL) { + *result = node->bool_; + return true; + } + return false; +} + +bool getJSONInt(JsonNode *item, const char* key, int *result) { + JsonNode *node = json_find_member(item, key); + if ( node != NULL && node->tag == JSON_NUMBER) { + *result = (int) node->number_; + return true; + } + return false; +} + +JsonNode* mustParseJSON(const char* JSON) { + JsonNode* parsedUpdate = json_decode(JSON); + if ( parsedUpdate == NULL ) { + ABORT("Unable to decode JSON: %s\n", JSON); + } + return parsedUpdate; +} \ No newline at end of file diff --git a/v2/internal/ffenestri/common.h b/v2/internal/ffenestri/common.h new file mode 100644 index 000000000..7f6e3a509 --- /dev/null +++ b/v2/internal/ffenestri/common.h @@ -0,0 +1,36 @@ +// +// Created by Lea Anthony on 6/1/21. +// + +#ifndef COMMON_H +#define COMMON_H + +#include +#include +#include "string.h" +#include "hashmap.h" +#include "vec.h" +#include "json.h" + +#define STREQ(a,b) strcmp(a, b) == 0 +#define STREMPTY(string) strlen(string) == 0 +#define STRCOPY(a) concat(a, "") +#define STR_HAS_CHARS(input) input != NULL && strlen(input) > 0 +#define MEMFREE(input) free((void*)input); input = NULL; +#define FREE_AND_SET(variable, value) if( variable != NULL ) { MEMFREE(variable); } variable = value + +// Credit: https://stackoverflow.com/a/8465083 +char* concat(const char *string1, const char *string2); +void ABORT(const char *message, ...); +int freeHashmapItem(void *const context, struct hashmap_element_s *const e); +const char* getJSONString(JsonNode *item, const char* key); +const char* mustJSONString(JsonNode *node, const char* key); +JsonNode* getJSONObject(JsonNode* node, const char* key); +JsonNode* mustJSONObject(JsonNode *node, const char* key); + +bool getJSONBool(JsonNode *item, const char* key, bool *result); +bool getJSONInt(JsonNode *item, const char* key, int *result); + +JsonNode* mustParseJSON(const char* JSON); + +#endif //ASSETS_C_COMMON_H diff --git a/v2/internal/ffenestri/contextmenus_darwin.c b/v2/internal/ffenestri/contextmenus_darwin.c new file mode 100644 index 000000000..fb2eb4105 --- /dev/null +++ b/v2/internal/ffenestri/contextmenus_darwin.c @@ -0,0 +1,99 @@ +//// +//// Created by Lea Anthony on 6/1/21. +//// +// + +#include "ffenestri_darwin.h" +#include "common.h" +#include "contextmenus_darwin.h" +#include "menu_darwin.h" + +ContextMenu* NewContextMenu(const char* contextMenuJSON) { + ContextMenu* result = malloc(sizeof(ContextMenu)); + + JsonNode* processedJSON = json_decode(contextMenuJSON); + if( processedJSON == NULL ) { + ABORT("[NewTrayMenu] Unable to parse TrayMenu JSON: %s", contextMenuJSON); + } + // Save reference to this json + result->processedJSON = processedJSON; + + result->ID = mustJSONString(processedJSON, "ID"); + JsonNode* processedMenu = mustJSONObject(processedJSON, "ProcessedMenu"); + + result->menu = NewMenu(processedMenu); + result->nsmenu = NULL; + result->menu->menuType = ContextMenuType; + result->menu->parentData = result; + result->contextMenuData = NULL; + return result; +} + +ContextMenu* GetContextMenuByID(ContextMenuStore* store, const char *contextMenuID) { + return (ContextMenu*)hashmap_get(&store->contextMenuMap, (char*)contextMenuID, strlen(contextMenuID)); +} + +void DeleteContextMenu(ContextMenu* contextMenu) { + // Free Menu + DeleteMenu(contextMenu->menu); + + // Delete any context menu data we may have stored + if( contextMenu->contextMenuData != NULL ) { + MEMFREE(contextMenu->contextMenuData); + } + + // Free JSON + if (contextMenu->processedJSON != NULL ) { + json_delete(contextMenu->processedJSON); + contextMenu->processedJSON = NULL; + } + + // Free context menu + free(contextMenu); +} + +int freeContextMenu(void *const context, struct hashmap_element_s *const e) { + DeleteContextMenu(e->data); + return -1; +} + +void ShowContextMenu(ContextMenuStore* store, id mainWindow, const char *contextMenuID, const char *contextMenuData) { + + // If no context menu ID was given, abort + if( contextMenuID == NULL ) { + return; + } + + ContextMenu* contextMenu = GetContextMenuByID(store, contextMenuID); + + // We don't need the ID now + MEMFREE(contextMenuID); + + if( contextMenu == NULL ) { + // Free context menu data + if( contextMenuData != NULL ) { + MEMFREE(contextMenuData); + return; + } + } + + // We need to store the context menu data. Free existing data if we have it + // and set to the new value. + FREE_AND_SET(contextMenu->contextMenuData, contextMenuData); + + // Grab the content view and show the menu + id contentView = msg_reg(mainWindow, s("contentView")); + + // Get the triggering event + id menuEvent = msg_reg(mainWindow, s("currentEvent")); + + if( contextMenu->nsmenu == NULL ) { + // GetMenu creates the NSMenu + contextMenu->nsmenu = GetMenu(contextMenu->menu); + } + + // Show popup + ((id(*)(id, SEL, id, id, id))objc_msgSend)(c("NSMenu"), s("popUpContextMenu:withEvent:forView:"), contextMenu->nsmenu, menuEvent, contentView); + +} + diff --git a/v2/internal/ffenestri/contextmenus_darwin.h b/v2/internal/ffenestri/contextmenus_darwin.h new file mode 100644 index 000000000..a1e7b976a --- /dev/null +++ b/v2/internal/ffenestri/contextmenus_darwin.h @@ -0,0 +1,33 @@ +//// +//// Created by Lea Anthony on 6/1/21. +//// +// +#ifndef CONTEXTMENU_DARWIN_H +#define CONTEXTMENU_DARWIN_H + +#include "json.h" +#include "menu_darwin.h" +#include "contextmenustore_darwin.h" + +typedef struct { + const char* ID; + id nsmenu; + Menu* menu; + + JsonNode* processedJSON; + + // Context menu data is given by the frontend when clicking a context menu. + // We send this to the backend when an item is selected + const char* contextMenuData; +} ContextMenu; + + +ContextMenu* NewContextMenu(const char* contextMenuJSON); + +ContextMenu* GetContextMenuByID( ContextMenuStore* store, const char *contextMenuID); +void DeleteContextMenu(ContextMenu* contextMenu); +int freeContextMenu(void *const context, struct hashmap_element_s *const e); + +void ShowContextMenu(ContextMenuStore* store, id mainWindow, const char *contextMenuID, const char *contextMenuData); + +#endif //CONTEXTMENU_DARWIN_H diff --git a/v2/internal/ffenestri/contextmenustore_darwin.c b/v2/internal/ffenestri/contextmenustore_darwin.c new file mode 100644 index 000000000..c777f014e --- /dev/null +++ b/v2/internal/ffenestri/contextmenustore_darwin.c @@ -0,0 +1,65 @@ + +#include "contextmenus_darwin.h" +#include "contextmenustore_darwin.h" + +ContextMenuStore* NewContextMenuStore() { + + ContextMenuStore* result = malloc(sizeof(ContextMenuStore)); + + // Allocate Context Menu Store + if( 0 != hashmap_create((const unsigned)4, &result->contextMenuMap)) { + ABORT("[NewContextMenus] Not enough memory to allocate contextMenuStore!"); + } + + return result; +} + +void AddContextMenuToStore(ContextMenuStore* store, const char* contextMenuJSON) { + ContextMenu* newMenu = NewContextMenu(contextMenuJSON); + + //TODO: check if there is already an entry for this menu + hashmap_put(&store->contextMenuMap, newMenu->ID, strlen(newMenu->ID), newMenu); +} + +ContextMenu* GetContextMenuFromStore(ContextMenuStore* store, const char* menuID) { + // Get the current menu + return hashmap_get(&store->contextMenuMap, menuID, strlen(menuID)); +} + +void UpdateContextMenuInStore(ContextMenuStore* store, const char* menuJSON) { + ContextMenu* newContextMenu = NewContextMenu(menuJSON); + + // Get the current menu + ContextMenu *currentMenu = GetContextMenuFromStore(store, newContextMenu->ID); + if ( currentMenu == NULL ) { + ABORT("Attempted to update unknown context menu with ID '%s'.", newContextMenu->ID); + } + + hashmap_remove(&store->contextMenuMap, newContextMenu->ID, strlen(newContextMenu->ID)); + + // Save the status bar reference + DeleteContextMenu(currentMenu); + + hashmap_put(&store->contextMenuMap, newContextMenu->ID, strlen(newContextMenu->ID), newContextMenu); + +} + + +void DeleteContextMenuStore(ContextMenuStore* store) { + + // Guard against NULLs + if( store == NULL ) { + return; + } + + // Delete context menus + if( hashmap_num_entries(&store->contextMenuMap) > 0 ) { + if (0 != hashmap_iterate_pairs(&store->contextMenuMap, freeContextMenu, NULL)) { + ABORT("[DeleteContextMenuStore] Failed to release contextMenuStore entries!"); + } + } + + // Free context menu hashmap + hashmap_destroy(&store->contextMenuMap); + +} diff --git a/v2/internal/ffenestri/contextmenustore_darwin.h b/v2/internal/ffenestri/contextmenustore_darwin.h new file mode 100644 index 000000000..793eef691 --- /dev/null +++ b/v2/internal/ffenestri/contextmenustore_darwin.h @@ -0,0 +1,27 @@ +// +// Created by Lea Anthony on 7/1/21. +// + +#ifndef CONTEXTMENUSTORE_DARWIN_H +#define CONTEXTMENUSTORE_DARWIN_H + +#include "common.h" + +typedef struct { + + int dummy; + + // This is our context menu store which keeps track + // of all instances of ContextMenus + struct hashmap_s contextMenuMap; + +} ContextMenuStore; + +ContextMenuStore* NewContextMenuStore(); + +void DeleteContextMenuStore(ContextMenuStore* store); +void UpdateContextMenuInStore(ContextMenuStore* store, const char* menuJSON); + +void AddContextMenuToStore(ContextMenuStore* store, const char* contextMenuJSON); + +#endif //CONTEXTMENUSTORE_DARWIN_H diff --git a/v2/internal/ffenestri/defaultdialogicons_darwin.c b/v2/internal/ffenestri/defaultdialogicons_darwin.c new file mode 100644 index 000000000..0c79a6b55 --- /dev/null +++ b/v2/internal/ffenestri/defaultdialogicons_darwin.c @@ -0,0 +1,41 @@ +// defaultdialogicons_darwin.c +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL. +// This file was auto-generated. DO NOT MODIFY. + +const unsigned char defaultDialogIcon0Name[] = { 0x69, 0x6e, 0x66, 0x6f, 0x2d, 0x64, 0x61, 0x72, 0x6b, 0x00 }; +const unsigned char defaultDialogIcon0Length[] = { 0x37, 0x38, 0x30, 0x00 }; +const unsigned char defaultDialogIcon0Data[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x40, 0x8, 0x3, 0x0, 0x0, 0x0, 0x9d, 0xb7, 0x81, 0xec, 0x0, 0x0, 0x0, 0x84, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x20, 0xdb, 0xe6, 0xd1, 0x0, 0x0, 0x0, 0x2b, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xf9, 0x9c, 0xb1, 0xe7, 0x4b, 0x91, 0x3a, 0x1b, 0xe3, 0x1e, 0xa, 0xae, 0x51, 0xe0, 0x98, 0x32, 0x4, 0x66, 0x6d, 0x2b, 0x63, 0x5d, 0x18, 0x11, 0xd6, 0xd0, 0xc8, 0xc2, 0x40, 0x7, 0x76, 0x16, 0x48, 0xa0, 0x2f, 0x57, 0xf1, 0xf0, 0x85, 0x77, 0x2c, 0xf, 0x6d, 0x84, 0xfd, 0x3d, 0x0, 0x0, 0x2, 0xc, 0x49, 0x44, 0x41, 0x54, 0x58, 0xc3, 0xed, 0x57, 0xd9, 0x96, 0x82, 0x30, 0xc, 0x15, 0x2c, 0x4b, 0x91, 0x5d, 0x40, 0x10, 0x5, 0xf7, 0x65, 0xfc, 0xff, 0xff, 0x9b, 0x63, 0xca, 0xa1, 0x40, 0xb, 0x61, 0xa6, 0xc7, 0x37, 0xf3, 0x18, 0x92, 0xdb, 0x66, 0xb9, 0x69, 0x58, 0x7c, 0xe5, 0xb3, 0x62, 0x87, 0x46, 0xfa, 0x78, 0xa4, 0x46, 0x68, 0xff, 0xc3, 0x79, 0xe3, 0x99, 0x25, 0xd5, 0x5e, 0x20, 0x1a, 0x2d, 0x4d, 0x6f, 0xf3, 0x27, 0x77, 0x2b, 0xf0, 0x5f, 0x3, 0xf1, 0x3, 0x6b, 0xb6, 0xfb, 0x7e, 0xa9, 0xbd, 0x24, 0xa2, 0x2d, 0xf7, 0xb3, 0xdc, 0x1d, 0x1d, 0xdc, 0xa5, 0x10, 0xba, 0x83, 0xfb, 0x1b, 0x7e, 0xd7, 0x83, 0x14, 0x5, 0xe9, 0xe2, 0xf9, 0x6, 0xe6, 0xbf, 0x6e, 0xcd, 0xa9, 0x1b, 0x5b, 0x89, 0x93, 0xe7, 0x4e, 0x62, 0xc5, 0x2e, 0x6d, 0x21, 0xd7, 0x93, 0xee, 0x2b, 0xb3, 0x8d, 0xd7, 0xb3, 0x7b, 0x15, 0xf5, 0xda, 0xbc, 0x98, 0xab, 0x9, 0x7f, 0xb7, 0x31, 0xda, 0x1d, 0x25, 0xb1, 0xed, 0x9a, 0x8f, 0xee, 0x38, 0x42, 0x73, 0x3e, 0xc9, 0x2a, 0xd9, 0xd7, 0x2a, 0x23, 0xcd, 0x1d, 0x46, 0xe3, 0x67, 0xdf, 0xb7, 0xe1, 0x98, 0x41, 0xb8, 0x65, 0x16, 0x23, 0x79, 0x30, 0x58, 0x94, 0xcb, 0xcd, 0x44, 0x7f, 0x2e, 0x59, 0x86, 0xc, 0x69, 0xfd, 0x29, 0xf3, 0x5f, 0x4d, 0x66, 0x99, 0x21, 0x50, 0x59, 0x3f, 0xe8, 0xec, 0xfe, 0x83, 0xf3, 0x9f, 0xcf, 0x1, 0xc1, 0x58, 0x14, 0xba, 0xa4, 0x7f, 0x21, 0x0, 0x72, 0xee, 0x1f, 0x78, 0xba, 0x5e, 0x4f, 0xfd, 0x2b, 0x9d, 0x9, 0x4, 0x21, 0x74, 0x75, 0xc4, 0xee, 0x96, 0xf5, 0xb5, 0xf1, 0x5b, 0x17, 0xf7, 0x75, 0x19, 0x8b, 0x34, 0x1a, 0xf2, 0x4f, 0x83, 0xfa, 0x57, 0x42, 0x5d, 0x85, 0xaa, 0x55, 0x3b, 0xb8, 0xc2, 0x90, 0x9b, 0x1, 0x68, 0x8f, 0xb, 0xc9, 0x69, 0x97, 0x81, 0xf2, 0x8, 0x67, 0x5, 0x7d, 0xe5, 0xc1, 0x87, 0x7b, 0x9, 0x81, 0xdd, 0x29, 0xbd, 0x47, 0x43, 0x2d, 0x44, 0xeb, 0x1f, 0x7a, 0x3a, 0xf, 0x2, 0xf3, 0xc4, 0xdc, 0x1e, 0x98, 0x1d, 0x6a, 0xc, 0xc1, 0x12, 0x7b, 0xe6, 0xac, 0x24, 0x42, 0x6a, 0xa2, 0x12, 0x58, 0x22, 0xda, 0x46, 0x96, 0x15, 0x89, 0x5a, 0xe0, 0x5c, 0x19, 0x75, 0x31, 0xa9, 0x50, 0x2f, 0x90, 0xdc, 0xd5, 0x34, 0xf7, 0x47, 0x50, 0x43, 0x75, 0xa9, 0xdd, 0x65, 0x9, 0x24, 0xd6, 0x12, 0xe9, 0x25, 0xa7, 0x8e, 0x5, 0x25, 0xb, 0xbb, 0x3c, 0x2, 0x4d, 0x22, 0x58, 0x6, 0x42, 0xc1, 0x40, 0x12, 0x38, 0xaf, 0xcb, 0xa8, 0x14, 0x72, 0xe8, 0xc8, 0xf9, 0xa1, 0x8b, 0xbc, 0x83, 0x2c, 0xa6, 0x1d, 0x4d, 0xfd, 0x56, 0x14, 0xf9, 0x5c, 0x80, 0xbc, 0x78, 0xeb, 0x6b, 0x65, 0x0, 0xe5, 0x10, 0xb0, 0x24, 0x72, 0x0, 0x3c, 0x89, 0xbc, 0x8c, 0x38, 0x0, 0x2f, 0x23, 0xd6, 0x48, 0x1c, 0x0, 0x6f, 0x24, 0xde, 0xca, 0x38, 0x0, 0x6f, 0x65, 0x84, 0x4c, 0x1c, 0x0, 0x27, 0x13, 0x67, 0x28, 0xe, 0xc0, 0x8d, 0xb1, 0x81, 0xc2, 0x1, 0xf0, 0x81, 0xc2, 0x47, 0x1a, 0xa, 0xc0, 0x47, 0x1a, 0x3a, 0x54, 0x39, 0x99, 0x90, 0xa1, 0x8a, 0x8e, 0xf5, 0x74, 0x62, 0xac, 0xe3, 0xf, 0xcb, 0xed, 0x86, 0x3c, 0x2c, 0xd8, 0xd3, 0x96, 0x24, 0xf8, 0xd3, 0xa6, 0xfe, 0xb8, 0xce, 0x7f, 0xde, 0x6d, 0xfe, 0xbc, 0xab, 0x2d, 0x18, 0xca, 0x2b, 0xe, 0xbe, 0x64, 0x19, 0xd8, 0x92, 0x85, 0xaf, 0x79, 0x17, 0xbb, 0x97, 0xe1, 0xb, 0xb2, 0xe6, 0x61, 0x8b, 0x26, 0x11, 0x17, 0x4d, 0xf5, 0x55, 0x57, 0x7d, 0xd9, 0x56, 0x5f, 0xf7, 0xd5, 0x7f, 0x38, 0xd4, 0x7f, 0x79, 0xf0, 0x9f, 0xae, 0xba, 0x86, 0x9f, 0xae, 0xaf, 0x7c, 0x54, 0x7e, 0x1, 0x7, 0x4e, 0x88, 0x96, 0x1d, 0xbb, 0xbc, 0x56, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, 0x00 }; +const unsigned char defaultDialogIcon1Name[] = { 0x69, 0x6e, 0x66, 0x6f, 0x2d, 0x64, 0x61, 0x72, 0x6b, 0x32, 0x78, 0x00 }; +const unsigned char defaultDialogIcon1Length[] = { 0x31, 0x32, 0x39, 0x35, 0x00 }; +const unsigned char defaultDialogIcon1Data[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x80, 0x8, 0x3, 0x0, 0x0, 0x0, 0xf4, 0xe0, 0x91, 0xf9, 0x0, 0x0, 0x0, 0x96, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x25, 0xc5, 0xa8, 0x0, 0x0, 0x0, 0x31, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xfb, 0x55, 0x3, 0x61, 0x95, 0xc, 0xd7, 0xb7, 0x8a, 0x82, 0x39, 0xe5, 0x40, 0x19, 0x44, 0x2b, 0x4e, 0xee, 0xc6, 0xbf, 0x48, 0x25, 0x21, 0xe2, 0xb3, 0x67, 0xe8, 0x33, 0xd0, 0x6c, 0x42, 0x9, 0xcb, 0xf, 0xf6, 0xc2, 0xbc, 0xb0, 0xa8, 0x71, 0x52, 0x14, 0x7, 0x90, 0x7c, 0x8f, 0x11, 0x7b, 0xbe, 0x95, 0xf5, 0x71, 0x0, 0x0, 0x3, 0xf7, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xec, 0x97, 0xd9, 0x72, 0xaa, 0x40, 0x10, 0x86, 0xdb, 0xc, 0xc8, 0xe, 0xa2, 0x2c, 0xee, 0x68, 0xdc, 0xf5, 0x98, 0xd4, 0xbc, 0xff, 0xcb, 0x9d, 0x4a, 0x9d, 0x53, 0xa1, 0x41, 0x98, 0x9e, 0x19, 0x30, 0x95, 0xb, 0xbf, 0xeb, 0x6, 0x7a, 0xf9, 0x7b, 0x1, 0x5e, 0xbc, 0x78, 0xf1, 0xe2, 0x85, 0x3e, 0x9b, 0x30, 0x5b, 0x16, 0x71, 0x5c, 0x2c, 0xb3, 0x70, 0x3, 0x3f, 0xcb, 0x30, 0x5a, 0x9b, 0x7, 0x9f, 0x23, 0xfc, 0x83, 0xb9, 0x8e, 0x86, 0xf0, 0x13, 0xdc, 0x2, 0x77, 0x32, 0xe0, 0x8d, 0xc, 0x26, 0x6e, 0x70, 0x83, 0xa7, 0xc2, 0xd2, 0xd3, 0x8e, 0xb, 0xd9, 0x9d, 0x52, 0x6, 0xcf, 0x62, 0xe4, 0x2c, 0xb8, 0x4, 0xb, 0x67, 0x4, 0xcf, 0xc0, 0xb3, 0xb9, 0x34, 0xb6, 0x7, 0x7d, 0x53, 0x24, 0x5c, 0x89, 0xa4, 0xe8, 0x37, 0xf9, 0x9, 0x57, 0x26, 0xe9, 0xaf, 0x10, 0x43, 0x67, 0xc0, 0x35, 0x18, 0x38, 0x3d, 0xf5, 0x65, 0x3c, 0xe5, 0x9a, 0x4c, 0x63, 0xe8, 0xe, 0x73, 0x78, 0x7, 0x1c, 0xd6, 0x39, 0xfd, 0xb3, 0xd6, 0xc, 0xfb, 0xdb, 0xa3, 0x79, 0x37, 0x8c, 0xbb, 0x79, 0xdc, 0xfa, 0xad, 0x35, 0x9a, 0x75, 0x2c, 0x43, 0x6e, 0xf1, 0x26, 0x56, 0xae, 0x17, 0x32, 0x40, 0xb0, 0xd0, 0x73, 0x57, 0xbc, 0x9, 0x2b, 0x87, 0xe, 0x4, 0xe3, 0x86, 0xc8, 0xf7, 0xe7, 0xbc, 0xc5, 0xdb, 0xf3, 0xbe, 0x21, 0x13, 0xe3, 0x0, 0xb4, 0x99, 0x3f, 0xbe, 0xcf, 0x36, 0xae, 0x20, 0xe0, 0x6a, 0xd8, 0x8f, 0x1e, 0xcf, 0x75, 0xe5, 0x67, 0xf2, 0x3a, 0x13, 0xf, 0x48, 0xbc, 0x9, 0xaf, 0x63, 0x32, 0xad, 0xef, 0x3f, 0xc8, 0xcf, 0xba, 0x80, 0x14, 0x17, 0xeb, 0x41, 0x8a, 0x3a, 0x1e, 0xd4, 0xe3, 0x5f, 0xcc, 0x99, 0xb4, 0xef, 0xf3, 0x45, 0x3d, 0x7, 0x1a, 0xf5, 0xaf, 0x15, 0xd2, 0x1d, 0x2a, 0x75, 0xaf, 0x5b, 0x93, 0x8f, 0xb2, 0xe, 0x82, 0x41, 0x55, 0xca, 0x5, 0x28, 0x12, 0x8d, 0xab, 0x1, 0x4, 0x8a, 0xfd, 0x5f, 0x7d, 0xdc, 0xca, 0x40, 0x99, 0xcc, 0xaa, 0x86, 0x90, 0x2b, 0x65, 0xb0, 0xfa, 0xb0, 0xfd, 0xe, 0x1a, 0xbc, 0xdb, 0xd5, 0x20, 0x86, 0xda, 0xd, 0xf0, 0xc1, 0x40, 0xb, 0xf6, 0xa1, 0xdb, 0xa, 0x4e, 0xa5, 0x7a, 0x6, 0x68, 0x63, 0x54, 0x94, 0xe4, 0x80, 0x24, 0x31, 0xc7, 0x18, 0xd0, 0x1, 0x83, 0x63, 0x62, 0x49, 0x1, 0x4c, 0x2b, 0xf9, 0x87, 0x4e, 0xfc, 0xe1, 0x88, 0xe9, 0x46, 0xbd, 0x0, 0x36, 0x83, 0x4e, 0x30, 0x5b, 0xb9, 0x8, 0x23, 0x5c, 0x37, 0x4b, 0xac, 0xff, 0x4f, 0xc3, 0x34, 0x8d, 0x4f, 0x71, 0x2f, 0x58, 0x58, 0x4f, 0x23, 0xa0, 0x49, 0x70, 0xf3, 0x8a, 0xfb, 0x3f, 0xf5, 0xbf, 0x8c, 0xfc, 0x14, 0x44, 0x64, 0x78, 0xa4, 0x24, 0x40, 0x52, 0x60, 0x87, 0x23, 0x10, 0xb1, 0x1c, 0xfc, 0x37, 0x5b, 0x82, 0x88, 0x8, 0xa7, 0xb4, 0x50, 0x4a, 0x80, 0xb, 0x42, 0x56, 0xdf, 0x7, 0x12, 0x8, 0x71, 0x55, 0x52, 0xe0, 0xe1, 0xfd, 0x27, 0x9e, 0x5d, 0x61, 0x69, 0x19, 0x8a, 0xdb, 0xa, 0xef, 0x46, 0xf, 0xc4, 0xd8, 0xf2, 0x1b, 0x2c, 0x2d, 0x2d, 0x53, 0x10, 0xb2, 0xc6, 0x6d, 0x45, 0xb4, 0x0, 0xee, 0x0, 0x26, 0x6d, 0x4b, 0x88, 0x9b, 0x59, 0x1c, 0xd9, 0x4a, 0xcf, 0x80, 0xb, 0xd5, 0xe2, 0xdf, 0xf2, 0x1e, 0x33, 0xea, 0x46, 0x92, 0x9d, 0x5, 0xc, 0x55, 0x6b, 0x2, 0x14, 0x73, 0xf9, 0x6b, 0x3, 0xdd, 0x89, 0x3e, 0x23, 0xca, 0x8a, 0xd4, 0x42, 0x61, 0x4a, 0xdf, 0x5b, 0x1e, 0x97, 0x13, 0xcc, 0x9, 0x8b, 0x45, 0x82, 0x78, 0xe6, 0xfb, 0xb3, 0x18, 0x30, 0xb4, 0xb8, 0x4f, 0xd0, 0xca, 0x6d, 0x47, 0x2f, 0xc1, 0xee, 0x6b, 0x71, 0x77, 0x83, 0x36, 0x2, 0x34, 0x4, 0xaf, 0xd0, 0x2b, 0x57, 0x34, 0xe, 0x3, 0x99, 0x91, 0xb5, 0x87, 0x9e, 0xd9, 0xa3, 0x1, 0x2b, 0xa3, 0xd5, 0x33, 0xf4, 0xcc, 0x59, 0xa2, 0xbf, 0x86, 0x28, 0x4d, 0x39, 0xf4, 0x4c, 0x8e, 0xca, 0xdb, 0x36, 0xe2, 0x23, 0xf4, 0xff, 0x2d, 0x79, 0xf8, 0x7e, 0xdd, 0x3, 0x92, 0x27, 0x33, 0xfa, 0x7b, 0x8f, 0xe8, 0x91, 0xed, 0x82, 0xc, 0xd1, 0xbf, 0x7b, 0xa0, 0xf6, 0x3e, 0x5a, 0x60, 0x6b, 0x68, 0xc6, 0x24, 0xa6, 0x10, 0x71, 0xf, 0x10, 0x78, 0xf4, 0x9f, 0xe2, 0x1, 0xed, 0x57, 0xa5, 0xa4, 0x6e, 0x1, 0x43, 0x6f, 0xef, 0x3, 0x34, 0xe3, 0x97, 0x32, 0x61, 0x40, 0x13, 0xaa, 0xf9, 0xcb, 0x4a, 0x89, 0x4f, 0xa1, 0x91, 0xd, 0x5a, 0x18, 0x40, 0x40, 0xdc, 0x3, 0x44, 0x7c, 0x7c, 0x43, 0x44, 0x24, 0x97, 0xd3, 0xb7, 0xd2, 0xfe, 0xd, 0x24, 0xd8, 0x52, 0x19, 0xcb, 0x4a, 0x83, 0xe3, 0x33, 0x1c, 0x38, 0x96, 0xf6, 0x59, 0xb3, 0xa8, 0x91, 0x4c, 0x3b, 0x39, 0x40, 0x37, 0xd9, 0x92, 0x5a, 0x45, 0xf7, 0x67, 0x38, 0x70, 0xa7, 0xd6, 0x51, 0x4c, 0xec, 0x62, 0xc2, 0x1, 0x95, 0x8d, 0x1c, 0xff, 0x4e, 0x7, 0xfe, 0xb6, 0x6f, 0x6, 0x29, 0xc, 0x2, 0x41, 0x10, 0x3c, 0xc4, 0x63, 0xc4, 0x78, 0x8a, 0x10, 0x90, 0x24, 0x67, 0x21, 0xfe, 0xff, 0x75, 0x1, 0x73, 0x89, 0x18, 0x28, 0xb1, 0xc, 0xb3, 0x2b, 0x3b, 0x1f, 0xb0, 0x41, 0xdd, 0x9d, 0xe9, 0xae, 0x9, 0x7f, 0x5, 0xe1, 0x1f, 0x61, 0xf8, 0x6f, 0x18, 0x7e, 0x10, 0xc1, 0x51, 0xc, 0x2, 0xc4, 0x51, 0xcc, 0x97, 0x11, 0xb, 0x50, 0x97, 0x11, 0x5f, 0xc7, 0x2c, 0x40, 0x5d, 0xc7, 0xdc, 0x90, 0xb0, 0x0, 0xd5, 0x90, 0x70, 0x4b, 0xc6, 0x2, 0x54, 0x4b, 0xc6, 0x4d, 0x29, 0xb, 0x50, 0x4d, 0x29, 0xb7, 0xe5, 0x2c, 0x40, 0xb5, 0xe5, 0x3c, 0x98, 0xb0, 0x0, 0x35, 0x98, 0xf0, 0x68, 0xc6, 0x2, 0xd4, 0x68, 0xc6, 0xc3, 0x29, 0xb, 0x50, 0xc3, 0x29, 0x8f, 0xe7, 0x2c, 0xc0, 0x8d, 0xe7, 0x6c, 0x50, 0xb0, 0x0, 0x6f, 0x50, 0xb0, 0x45, 0xc3, 0x2, 0xbc, 0x45, 0xc3, 0x26, 0x15, 0xb, 0x60, 0x93, 0xca, 0xd8, 0x74, 0x2c, 0x80, 0x6d, 0x3a, 0x65, 0x54, 0xb2, 0x0, 0x36, 0x2a, 0xd3, 0xb6, 0x6a, 0xe3, 0xcd, 0xea, 0x4d, 0x76, 0xfd, 0xc3, 0xd9, 0xf5, 0x3e, 0xb0, 0xb8, 0x88, 0xc0, 0x42, 0x45, 0x36, 0x4d, 0x37, 0x35, 0x58, 0x8d, 0x88, 0x6c, 0x64, 0x68, 0xf5, 0xac, 0x86, 0xa1, 0x82, 0x5c, 0x6b, 0x1e, 0x5a, 0xe5, 0x10, 0xdb, 0xc5, 0x7, 0x97, 0xe1, 0xd1, 0x6d, 0x7c, 0x78, 0xbd, 0x5b, 0x7c, 0x3f, 0x40, 0x7c, 0xff, 0x67, 0x80, 0xe1, 0xb5, 0x0, 0x18, 0x42, 0x11, 0x8e, 0xdb, 0xd5, 0x41, 0x2c, 0x8d, 0x86, 0x58, 0x72, 0xc3, 0x78, 0x7e, 0x80, 0x4c, 0xfd, 0x7a, 0x90, 0xa9, 0x5f, 0x80, 0x4c, 0x39, 0xa2, 0x5c, 0x3b, 0xc2, 0x6c, 0xc3, 0x29, 0x4f, 0x9c, 0x2f, 0x1, 0xa0, 0x31, 0x1e, 0xe9, 0x44, 0xa8, 0x75, 0xac, 0xaa, 0x11, 0xa0, 0xd6, 0xdc, 0xb1, 0xde, 0x78, 0xb0, 0xd9, 0xa0, 0xdd, 0xf7, 0xa3, 0xc0, 0xed, 0x9, 0xe0, 0xfd, 0x9, 0x2c, 0x38, 0x7c, 0x56, 0x3c, 0xce, 0x6b, 0x9e, 0x7e, 0x5e, 0xae, 0x78, 0x1c, 0x65, 0xc9, 0x25, 0x81, 0x35, 0x9f, 0xef, 0x45, 0xa7, 0x6e, 0xf6, 0xc7, 0x8b, 0x45, 0x27, 0xb5, 0xea, 0x55, 0xb7, 0x6d, 0x3d, 0xad, 0x7a, 0x95, 0x2a, 0x55, 0xaa, 0x54, 0xa9, 0xcd, 0xf5, 0x6, 0xc2, 0x69, 0xab, 0xf3, 0x71, 0x7e, 0x8e, 0x8, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, 0x00 }; +const unsigned char defaultDialogIcon2Name[] = { 0x69, 0x6e, 0x66, 0x6f, 0x2d, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x00 }; +const unsigned char defaultDialogIcon2Length[] = { 0x37, 0x36, 0x34, 0x00 }; +const unsigned char defaultDialogIcon2Data[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x40, 0x8, 0x3, 0x0, 0x0, 0x0, 0x9d, 0xb7, 0x81, 0xec, 0x0, 0x0, 0x0, 0x75, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x79, 0x59, 0x7d, 0x58, 0x0, 0x0, 0x0, 0x26, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xfc, 0xa5, 0xc9, 0xd, 0xf4, 0x7c, 0xd5, 0x8e, 0x7f, 0x26, 0x13, 0x78, 0xed, 0x47, 0xe0, 0xa0, 0x43, 0x8, 0xc5, 0xe9, 0xdc, 0xb4, 0xb0, 0x90, 0x88, 0x6b, 0x51, 0x29, 0x1f, 0xbe, 0x19, 0x94, 0x93, 0x37, 0x36, 0x1a, 0x58, 0x7b, 0xc0, 0x9a, 0x4f, 0x0, 0x0, 0x2, 0x10, 0x49, 0x44, 0x41, 0x54, 0x58, 0xc3, 0xed, 0x57, 0xd9, 0xb2, 0x82, 0x30, 0xc, 0x15, 0x91, 0x4d, 0x40, 0x40, 0x94, 0x4d, 0xb9, 0xee, 0xfd, 0xff, 0x4f, 0xbc, 0x93, 0x14, 0xd, 0xd3, 0x2, 0x41, 0x3b, 0xbe, 0x99, 0xd1, 0x7, 0xd2, 0xe4, 0x34, 0x3d, 0x4d, 0xd3, 0x74, 0xf1, 0x93, 0xaf, 0x4a, 0xbb, 0x69, 0xea, 0x73, 0x9a, 0x9e, 0xeb, 0x66, 0xd3, 0xbe, 0xef, 0x9d, 0xf9, 0xb6, 0x23, 0x5e, 0xe2, 0xd8, 0x7e, 0xf6, 0x8e, 0x77, 0x18, 0x79, 0xe8, 0x67, 0x75, 0x82, 0x1f, 0x5e, 0x14, 0xce, 0x74, 0x5f, 0x5, 0x3b, 0x74, 0x7e, 0x21, 0x3c, 0xbf, 0x76, 0xc1, 0x6a, 0x8e, 0xff, 0x61, 0x8f, 0xf6, 0xf8, 0x97, 0x42, 0xdf, 0xfb, 0x3, 0xef, 0xef, 0xb, 0x81, 0x53, 0xe2, 0xd2, 0x13, 0xbb, 0x2c, 0xed, 0x4, 0xc9, 0xe8, 0x94, 0x3e, 0x17, 0x7e, 0x81, 0x33, 0xc1, 0x2f, 0x77, 0x6f, 0xe1, 0x16, 0x74, 0xdb, 0xf0, 0xe6, 0xe6, 0xa8, 0x84, 0xb1, 0x62, 0x72, 0x19, 0x6b, 0x4f, 0x48, 0xcb, 0xd8, 0x5d, 0x2b, 0x23, 0x6e, 0x2c, 0xe4, 0x98, 0xb7, 0x9e, 0xf0, 0x8f, 0xa5, 0x8d, 0x55, 0x9d, 0xf4, 0xc1, 0x53, 0x65, 0xc9, 0xd1, 0x78, 0x14, 0x61, 0xd5, 0xcd, 0x9f, 0x1f, 0x87, 0xc7, 0x8f, 0x76, 0x17, 0xc3, 0xd8, 0x2a, 0xa, 0x49, 0xdd, 0x72, 0x3c, 0xc4, 0xa5, 0xa4, 0xb3, 0x18, 0xe3, 0x1f, 0xfd, 0xdd, 0x29, 0x92, 0x2, 0x89, 0xe0, 0xf, 0xee, 0xbf, 0x8c, 0x2f, 0x58, 0x4c, 0x4a, 0x20, 0xad, 0xe, 0x3, 0x4, 0xec, 0x81, 0x3d, 0x2d, 0xfe, 0xcd, 0x46, 0x5d, 0x5, 0x9a, 0xed, 0x57, 0x3a, 0x34, 0xe, 0xd8, 0xa, 0xea, 0x9f, 0x10, 0x7f, 0x8a, 0x2d, 0x30, 0x39, 0x10, 0x68, 0xb8, 0xc3, 0xd8, 0x14, 0xfe, 0x5d, 0x48, 0x1d, 0x85, 0x94, 0x23, 0xae, 0x61, 0xa7, 0x9e, 0xac, 0x8, 0x71, 0x2b, 0x45, 0x9b, 0xa, 0xc7, 0x11, 0xa9, 0xa2, 0xac, 0xd0, 0x34, 0x52, 0xb4, 0x1e, 0xcc, 0x15, 0xab, 0xf9, 0xf3, 0x0, 0xd2, 0x1f, 0x8a, 0xf2, 0x1e, 0x83, 0xad, 0xa7, 0xd4, 0xf, 0xdc, 0x1d, 0x7d, 0x7, 0xa3, 0x24, 0x89, 0x34, 0xa5, 0x8b, 0xfb, 0x9d, 0xe9, 0x39, 0x60, 0xd, 0xe4, 0xe8, 0x76, 0x3b, 0x90, 0xf1, 0x96, 0x9e, 0xb, 0x36, 0x44, 0x95, 0x2f, 0x66, 0x4a, 0x2e, 0x2c, 0x65, 0xc3, 0x5a, 0x87, 0x56, 0x30, 0x9d, 0x7, 0xb4, 0x6, 0xa7, 0xed, 0x9b, 0x9, 0x90, 0x1b, 0x29, 0x94, 0x3c, 0x50, 0xe4, 0x8a, 0xe6, 0x7d, 0xe8, 0x6, 0x21, 0x43, 0x9d, 0x43, 0x88, 0x55, 0x67, 0x31, 0xc4, 0x80, 0x9b, 0x9e, 0xa6, 0x6, 0xc3, 0x44, 0xe7, 0x6b, 0x9, 0xfa, 0xa5, 0xce, 0x6c, 0x2, 0xfa, 0xba, 0xa7, 0x39, 0x13, 0x2b, 0x1c, 0x0, 0x71, 0x7e, 0xe9, 0x67, 0x1c, 0x28, 0xca, 0xf9, 0x0, 0x25, 0xe8, 0x53, 0x63, 0x0, 0xe3, 0x25, 0x18, 0x93, 0xc8, 0x6d, 0x23, 0x1, 0xf0, 0xdb, 0x48, 0x89, 0xc4, 0x3, 0x50, 0x22, 0x31, 0xa9, 0x4c, 0x0, 0x7c, 0x2a, 0xd3, 0x61, 0xe2, 0x1, 0xe8, 0x30, 0x71, 0xc7, 0x99, 0x0, 0xf8, 0xe3, 0x4c, 0x5, 0x85, 0x7, 0xa0, 0x82, 0xc2, 0x95, 0x34, 0x2, 0xe0, 0x4b, 0x1a, 0x15, 0x55, 0x16, 0x80, 0x8a, 0x2a, 0x5b, 0xd6, 0xe9, 0x38, 0x33, 0x65, 0xdd, 0xe8, 0x62, 0xe1, 0xaf, 0xb6, 0x2c, 0x63, 0xae, 0x36, 0xe3, 0xcb, 0x55, 0xbf, 0xde, 0x83, 0xf, 0xaf, 0x77, 0xf3, 0x6, 0x83, 0x5a, 0x1c, 0x9b, 0x6d, 0x71, 0x3e, 0x6a, 0xb2, 0xee, 0x4c, 0x93, 0xc5, 0xb5, 0x79, 0x81, 0xd6, 0xe6, 0xf1, 0x8d, 0xe6, 0xf5, 0xd9, 0x68, 0x5e, 0x99, 0x46, 0xd3, 0xa0, 0xd5, 0x35, 0x6a, 0xb6, 0xcd, 0xdb, 0x7d, 0xf3, 0x7, 0x87, 0xf9, 0x93, 0x87, 0x7f, 0x74, 0x5d, 0xd2, 0xf4, 0x82, 0x8f, 0xae, 0x9f, 0x7c, 0x53, 0xfe, 0x1, 0x6f, 0xc7, 0x5c, 0x26, 0x6e, 0x29, 0x2b, 0x15, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, 0x00 }; +const unsigned char defaultDialogIcon3Name[] = { 0x69, 0x6e, 0x66, 0x6f, 0x2d, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x32, 0x78, 0x00 }; +const unsigned char defaultDialogIcon3Length[] = { 0x31, 0x32, 0x39, 0x33, 0x00 }; +const unsigned char defaultDialogIcon3Data[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x80, 0x8, 0x3, 0x0, 0x0, 0x0, 0xf4, 0xe0, 0x91, 0xf9, 0x0, 0x0, 0x0, 0x93, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7a, 0x79, 0x23, 0x75, 0x0, 0x0, 0x0, 0x30, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xfb, 0x55, 0x5, 0xe4, 0x40, 0xa, 0xb7, 0xd7, 0x62, 0x44, 0xe, 0xc0, 0x94, 0xb2, 0x2b, 0x68, 0x4e, 0xee, 0x39, 0xc6, 0x81, 0x48, 0x21, 0x89, 0x18, 0xe8, 0x33, 0xd0, 0xbd, 0xcb, 0x96, 0x8f, 0x13, 0x8b, 0xf6, 0xe1, 0xa8, 0x83, 0x7c, 0x71, 0x6c, 0x52, 0x26, 0x25, 0x1a, 0x3b, 0x5d, 0x23, 0x0, 0xd6, 0x57, 0x0, 0x0, 0x3, 0xf9, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xec, 0x97, 0xd7, 0x76, 0xab, 0x40, 0xc, 0x45, 0x35, 0xa1, 0x99, 0x6a, 0x63, 0xc, 0xb8, 0x13, 0xdc, 0x4b, 0x7c, 0xa3, 0xff, 0xff, 0xba, 0xbb, 0x6e, 0x59, 0x78, 0x26, 0x60, 0x24, 0x8a, 0xb3, 0xf2, 0xe0, 0xfd, 0x3c, 0x1e, 0xb, 0x95, 0x73, 0x34, 0xf0, 0xe2, 0xc5, 0x8b, 0x17, 0x2f, 0xda, 0x63, 0xde, 0xae, 0xb, 0x23, 0xc, 0x8d, 0xc5, 0xf5, 0x66, 0xc2, 0xf7, 0xe2, 0x3a, 0x67, 0x7f, 0xa5, 0xa3, 0x84, 0xbe, 0xf2, 0xcf, 0x8e, 0xb, 0xdf, 0x81, 0x66, 0x1c, 0x26, 0x2, 0x2b, 0x11, 0x93, 0x83, 0xa1, 0xc1, 0x53, 0xd1, 0x92, 0xfd, 0x16, 0x6b, 0xd9, 0xee, 0x93, 0xe7, 0xc5, 0x30, 0xdc, 0xcc, 0x91, 0xc1, 0x7c, 0x33, 0x84, 0x67, 0xf0, 0xcb, 0x42, 0x36, 0x56, 0x4, 0x7d, 0xe3, 0x78, 0xd8, 0x8, 0xcf, 0xe9, 0x37, 0xf9, 0x1e, 0x36, 0xc6, 0xeb, 0xaf, 0x10, 0xe6, 0x54, 0x60, 0xb, 0xc4, 0xb4, 0x27, 0x79, 0x8, 0x77, 0xd8, 0x92, 0x5d, 0x8, 0x3d, 0xb0, 0xc1, 0xe, 0x4c, 0xbb, 0x8b, 0x5e, 0xf0, 0x30, 0xc3, 0xfa, 0x3a, 0xc8, 0x8e, 0xb6, 0x7d, 0xcc, 0x82, 0xb5, 0xfe, 0xb0, 0x46, 0x41, 0x47, 0x79, 0x4c, 0x7, 0x58, 0xc5, 0x32, 0x8e, 0x66, 0xa0, 0x30, 0x8b, 0xe2, 0x25, 0x56, 0x31, 0x48, 0xa1, 0x3, 0xc6, 0x18, 0x4b, 0x8, 0xef, 0x94, 0x3e, 0x88, 0xf6, 0xe4, 0x9, 0x2c, 0x31, 0x36, 0xa0, 0x35, 0xa3, 0xf2, 0x7d, 0x96, 0x9d, 0x43, 0xd, 0xb9, 0x6d, 0x95, 0x23, 0x1e, 0xb5, 0x15, 0x7e, 0x1f, 0xbf, 0x32, 0x89, 0x18, 0x8a, 0x39, 0xc1, 0xaf, 0xf8, 0x5a, 0xab, 0xff, 0xb7, 0x4a, 0xe5, 0xbc, 0x0, 0x8b, 0xcb, 0xa0, 0x94, 0xb7, 0x36, 0x11, 0xf8, 0xa8, 0x32, 0x1f, 0x69, 0xec, 0xd8, 0x47, 0x73, 0x54, 0xf1, 0x5b, 0xd4, 0x1f, 0x15, 0x44, 0x6c, 0x36, 0x12, 0xcf, 0x58, 0xa0, 0x42, 0xe3, 0x3e, 0x30, 0x84, 0xda, 0xca, 0x4e, 0x63, 0xf7, 0x52, 0x7, 0x48, 0x18, 0xd, 0xe7, 0x7f, 0xac, 0x56, 0xff, 0x3, 0x1a, 0xf3, 0x31, 0x50, 0x3f, 0x21, 0x6d, 0xa4, 0x7f, 0xea, 0x8f, 0x2d, 0xb7, 0x95, 0x88, 0x5a, 0xea, 0x47, 0x34, 0xb9, 0x44, 0xd5, 0xdf, 0x77, 0xad, 0xe5, 0x1c, 0xbf, 0xab, 0xaa, 0xc, 0x6c, 0xa6, 0x4a, 0xf5, 0x6c, 0x68, 0x8d, 0x2d, 0x5a, 0x39, 0x53, 0x88, 0x32, 0x36, 0x74, 0xc0, 0x46, 0x99, 0x90, 0x39, 0x42, 0x3b, 0x25, 0xff, 0xd0, 0x9, 0xa5, 0xa, 0x3b, 0x93, 0x59, 0x0, 0xbe, 0x86, 0xf1, 0xf5, 0x94, 0x5f, 0x84, 0xa1, 0xe0, 0xb7, 0x6e, 0xfe, 0xe9, 0xfb, 0x9f, 0x39, 0x7f, 0xa0, 0xc4, 0x10, 0x68, 0x3c, 0x79, 0x78, 0xeb, 0xe7, 0x3f, 0xd1, 0x11, 0x11, 0xf5, 0xa4, 0x5e, 0xf, 0x64, 0x49, 0xf1, 0x80, 0xc4, 0x91, 0x3, 0xae, 0xd7, 0xbf, 0x85, 0xf8, 0x7f, 0x6c, 0x51, 0x7f, 0xa3, 0x9c, 0x52, 0xa3, 0x51, 0x2, 0x62, 0xa8, 0x65, 0x59, 0x2c, 0x48, 0x50, 0xcb, 0x1, 0xef, 0xac, 0x48, 0x37, 0x97, 0xfd, 0xaf, 0xbe, 0x69, 0x6f, 0x58, 0x30, 0xab, 0x1f, 0x2b, 0xd9, 0x1b, 0xa9, 0x8d, 0xc2, 0xe2, 0x3b, 0x58, 0x82, 0x5, 0x9, 0xdf, 0x59, 0x2d, 0x62, 0x4, 0xe4, 0x9, 0xd0, 0xd8, 0x67, 0x89, 0xe6, 0xd6, 0x6, 0xc8, 0x3d, 0xbb, 0xc1, 0x3b, 0x17, 0x6a, 0xc4, 0xc7, 0xc5, 0xb0, 0x50, 0x62, 0x71, 0xc1, 0x3b, 0x9b, 0xda, 0x3b, 0xa5, 0x6a, 0x4d, 0x80, 0x62, 0xc4, 0xdf, 0x36, 0xa4, 0x3d, 0x51, 0xd7, 0x78, 0x65, 0xc5, 0x8, 0x48, 0x32, 0xfc, 0x4b, 0xc6, 0xd8, 0x54, 0x91, 0xd7, 0x30, 0x7b, 0xa5, 0x59, 0x68, 0xc2, 0x40, 0xd7, 0x3, 0xd5, 0x62, 0xe8, 0xe6, 0xde, 0xd7, 0x54, 0x60, 0x4b, 0x9b, 0x60, 0x77, 0x5b, 0xdc, 0x3e, 0xae, 0x81, 0x21, 0x89, 0x60, 0xe, 0xbd, 0x92, 0xb, 0x8e, 0x1a, 0x1e, 0x68, 0xd1, 0xa6, 0xa1, 0x15, 0x36, 0xe6, 0xf4, 0xea, 0x9, 0x7a, 0xe6, 0xc4, 0x98, 0x2f, 0x57, 0x4a, 0x53, 0xa, 0x3d, 0x93, 0x4a, 0xe5, 0x35, 0x69, 0x23, 0x5c, 0x2, 0xb, 0xf7, 0xcf, 0x3e, 0xe0, 0x2, 0xb, 0xe9, 0xf5, 0xfe, 0xc8, 0x64, 0xcf, 0x6a, 0x99, 0x68, 0x9c, 0x7f, 0xfb, 0x80, 0x3, 0x1c, 0x62, 0x2c, 0x38, 0x43, 0x35, 0x3e, 0xa1, 0x42, 0xc4, 0x3e, 0x40, 0x10, 0xd1, 0x2f, 0xc5, 0x95, 0xea, 0xaf, 0xfc, 0xa4, 0xae, 0x81, 0xc1, 0x8d, 0x5e, 0xa, 0xf4, 0x7b, 0x9b, 0x0, 0x83, 0x59, 0xb3, 0x78, 0x35, 0x71, 0xb7, 0x3, 0xa8, 0xc4, 0x44, 0xe2, 0x4, 0x77, 0x1f, 0x20, 0xbf, 0xf, 0x4d, 0x22, 0x47, 0xbc, 0x9c, 0xbe, 0x61, 0xc1, 0x1b, 0x30, 0x58, 0x53, 0x19, 0xbb, 0x12, 0xcf, 0x38, 0x32, 0x0, 0xfe, 0x83, 0xf3, 0x5a, 0xdd, 0xd4, 0x58, 0x90, 0x3d, 0x23, 0x80, 0xc, 0xb, 0x16, 0x94, 0x15, 0x1d, 0x9f, 0x11, 0xc0, 0x91, 0xb2, 0xa3, 0x90, 0xf0, 0x62, 0x32, 0x0, 0xbe, 0x23, 0x87, 0x3f, 0x33, 0x80, 0xdf, 0xed, 0x5b, 0xcb, 0xe, 0x82, 0x30, 0x10, 0x6c, 0x2, 0xed, 0x85, 0x44, 0xf, 0x84, 0x28, 0x26, 0x18, 0x4e, 0xdc, 0x14, 0xfe, 0xff, 0xeb, 0x8c, 0x21, 0x5e, 0x1c, 0xc9, 0xd2, 0x4e, 0x65, 0x29, 0xe9, 0x7c, 0xc1, 0x24, 0x4a, 0x77, 0xe7, 0xb1, 0xea, 0x3f, 0x81, 0xfa, 0x9f, 0x50, 0xfd, 0x33, 0x54, 0x7f, 0x88, 0xf0, 0x29, 0xe6, 0x9, 0xc8, 0x4f, 0xb1, 0x3c, 0x8c, 0x78, 0x2, 0x38, 0x8c, 0xd8, 0x71, 0x8c, 0x4, 0xd8, 0x71, 0x8c, 0xb, 0x9, 0x43, 0x40, 0x5e, 0x48, 0xd8, 0x95, 0xc, 0x9, 0xb0, 0x2b, 0x19, 0x2e, 0xa5, 0xc, 0x1, 0x79, 0x29, 0x65, 0xd7, 0x72, 0x24, 0x40, 0xaf, 0xe5, 0x28, 0x4c, 0x8, 0x2, 0xa2, 0x30, 0xa1, 0xa5, 0x19, 0x12, 0xe0, 0xa5, 0x19, 0x8a, 0x53, 0x82, 0x80, 0x24, 0x4e, 0x69, 0x79, 0x8e, 0x4, 0x78, 0x79, 0x8e, 0x6, 0x5, 0x41, 0x40, 0x32, 0x28, 0x78, 0x8b, 0x6, 0x9, 0xf0, 0x16, 0xd, 0x9a, 0x54, 0xc, 0x1, 0xd9, 0xa4, 0xe2, 0x6d, 0x3a, 0x24, 0xc0, 0xdb, 0x74, 0x68, 0x54, 0xf2, 0x4, 0xd0, 0xa8, 0xdc, 0xb7, 0x55, 0x6b, 0xea, 0xf5, 0x66, 0x75, 0x4b, 0x98, 0xd5, 0x91, 0xed, 0xfa, 0x3b, 0x67, 0xd7, 0xf3, 0x81, 0xc5, 0x99, 0x8, 0x2c, 0x88, 0xc8, 0x6, 0x2c, 0x1a, 0xef, 0xc8, 0x86, 0xf, 0xad, 0xaa, 0xb1, 0xef, 0xc7, 0xca, 0x27, 0xb4, 0x4a, 0x21, 0xb6, 0xd3, 0xf, 0x2e, 0xd5, 0xa3, 0x5b, 0xfd, 0xf0, 0x5a, 0x3f, 0xbe, 0xd7, 0x2f, 0x30, 0xfc, 0xa1, 0xc2, 0x71, 0xbb, 0xa4, 0x55, 0x62, 0xc1, 0x1a, 0xcf, 0xe0, 0x57, 0xe3, 0x19, 0xbe, 0x6b, 0x3c, 0xe9, 0x15, 0x99, 0xa2, 0x56, 0xb9, 0x4e, 0x45, 0xac, 0x32, 0xdb, 0x33, 0xb0, 0xcc, 0x96, 0x66, 0x9d, 0x6f, 0x7, 0x85, 0x46, 0x8f, 0x4a, 0xe7, 0x63, 0xb9, 0xd2, 0x99, 0x76, 0xa9, 0x75, 0x9e, 0x4c, 0xe1, 0xb8, 0x1e, 0xa1, 0xd8, 0xac, 0x5f, 0xed, 0xd6, 0x2f, 0xb7, 0xbf, 0x61, 0xbb, 0xc9, 0xb, 0x9d, 0x35, 0xb1, 0x51, 0xf3, 0x7, 0xe, 0xfc, 0x89, 0x47, 0x39, 0xad, 0x40, 0x9, 0x27, 0x1e, 0x87, 0x39, 0x72, 0x99, 0x39, 0xd8, 0x66, 0xf9, 0xcc, 0xa7, 0xb1, 0x85, 0xd9, 0x2, 0xee, 0xf7, 0xa1, 0x93, 0x33, 0xdb, 0xc2, 0xb5, 0x9f, 0x53, 0xaf, 0xd6, 0x99, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x60, 0xbc, 0x0, 0xd9, 0xfc, 0x9e, 0xf5, 0xee, 0xae, 0x37, 0x12, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, 0x00 }; +const unsigned char defaultDialogIcon4Name[] = { 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x64, 0x61, 0x72, 0x6b, 0x00 }; +const unsigned char defaultDialogIcon4Length[] = { 0x39, 0x34, 0x31, 0x00 }; +const unsigned char defaultDialogIcon4Data[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x40, 0x8, 0x3, 0x0, 0x0, 0x0, 0x9d, 0xb7, 0x81, 0xec, 0x0, 0x0, 0x0, 0x99, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd5, 0x1d, 0x4, 0x54, 0x0, 0x0, 0x0, 0x32, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xf9, 0x1c, 0xe6, 0xb1, 0x3b, 0x17, 0xc9, 0xad, 0x6, 0x8f, 0x4e, 0x4b, 0x40, 0xf6, 0xe3, 0xe0, 0xc1, 0x20, 0x11, 0x62, 0x54, 0x34, 0x30, 0x2b, 0x5d, 0xd6, 0xd0, 0x98, 0x76, 0x65, 0xb, 0x9b, 0x92, 0x6d, 0x48, 0x2, 0x9, 0x3, 0x9c, 0xb5, 0x9d, 0xed, 0xe8, 0xbb, 0x78, 0xdc, 0x83, 0x71, 0x9f, 0x76, 0x53, 0x1c, 0x31, 0x0, 0x0, 0x2, 0x91, 0x49, 0x44, 0x41, 0x54, 0x58, 0xc3, 0xed, 0x57, 0x6b, 0x7b, 0xaa, 0x30, 0xc, 0x3e, 0xdc, 0x4, 0x41, 0x85, 0x71, 0x13, 0x54, 0x18, 0x53, 0xa7, 0xce, 0xcb, 0xb6, 0xb3, 0xff, 0xff, 0xe3, 0x8e, 0xa4, 0xa5, 0x29, 0x4, 0xe, 0xee, 0xe9, 0xb3, 0x6f, 0xcb, 0x27, 0xdb, 0x92, 0x34, 0x79, 0xf3, 0x26, 0x8d, 0x7f, 0x7e, 0xe5, 0x47, 0x65, 0xaf, 0xa7, 0x5e, 0x5c, 0x14, 0xb1, 0x97, 0xea, 0xfb, 0xef, 0x6b, 0x4f, 0x3c, 0xd7, 0xf6, 0xb5, 0x2f, 0x10, 0xcd, 0xb7, 0x5d, 0x6f, 0xf2, 0x2d, 0x75, 0x6b, 0x13, 0x7c, 0x75, 0x24, 0xd8, 0x58, 0xf, 0xab, 0xcf, 0xcd, 0xfa, 0x6a, 0x22, 0x9a, 0x39, 0x7f, 0x48, 0x3d, 0x3c, 0xa, 0x75, 0x62, 0xe2, 0x18, 0x8e, 0xeb, 0xcf, 0x2, 0x59, 0xc3, 0x58, 0xad, 0xc, 0xd9, 0x5e, 0x30, 0x1b, 0xd3, 0xdf, 0x2e, 0x9a, 0x6f, 0xd, 0xa7, 0xb4, 0x32, 0x3d, 0x8a, 0xf4, 0xcc, 0x2a, 0x1d, 0xa3, 0xd9, 0x5d, 0x6c, 0xff, 0xab, 0xfe, 0xfc, 0x22, 0xe2, 0x4d, 0x74, 0xf9, 0x40, 0x4f, 0x4, 0x2e, 0x2f, 0xcf, 0xc3, 0xfa, 0xaf, 0xe, 0xff, 0xe8, 0x69, 0xd7, 0x13, 0xdb, 0x13, 0x3f, 0x74, 0x5e, 0x7, 0xd, 0xf0, 0xfb, 0x8d, 0x7c, 0xda, 0x77, 0x3a, 0xcd, 0xd, 0xee, 0xc3, 0x60, 0xfc, 0xec, 0x7c, 0xbd, 0x1c, 0xfa, 0x60, 0xb9, 0x66, 0x5f, 0x6c, 0x7, 0xf0, 0x67, 0xf8, 0x99, 0x13, 0x54, 0x28, 0x1c, 0xdb, 0x36, 0x6f, 0x68, 0x70, 0x62, 0x32, 0x24, 0x7b, 0x73, 0x11, 0xfa, 0x4c, 0x5f, 0x60, 0xa4, 0x57, 0xb, 0x8e, 0xfc, 0xdf, 0x50, 0xa0, 0xcc, 0x2c, 0xf8, 0x7d, 0x7c, 0x78, 0x63, 0xfe, 0x8b, 0xfb, 0xd3, 0x15, 0xa6, 0xff, 0xdd, 0x12, 0x56, 0x59, 0x14, 0x6f, 0x3d, 0xfc, 0xd5, 0x0, 0x3f, 0xe1, 0x6e, 0xe6, 0xa3, 0xbe, 0xbc, 0xbf, 0x4, 0x24, 0x35, 0xc2, 0xea, 0x3, 0xf3, 0x2d, 0x17, 0x90, 0x43, 0xd2, 0x50, 0x6c, 0x91, 0xbb, 0x9c, 0x45, 0x7a, 0xe8, 0xd6, 0x9f, 0x6, 0xf9, 0x17, 0xf9, 0x4b, 0x38, 0x21, 0x5c, 0x97, 0x5b, 0x8a, 0x5, 0x59, 0x60, 0x43, 0xeb, 0xd6, 0xe6, 0x6, 0x76, 0x91, 0x3f, 0x27, 0x58, 0x7f, 0xde, 0xd, 0x4e, 0x3f, 0x99, 0x6d, 0xd1, 0x54, 0x76, 0xb0, 0xde, 0x74, 0xfa, 0x47, 0x0, 0x7e, 0x21, 0x75, 0xcf, 0xf5, 0xba, 0x62, 0x8b, 0xaa, 0xfe, 0x7d, 0x16, 0xc0, 0xef, 0x21, 0xda, 0xa0, 0xdd, 0x61, 0x3c, 0x70, 0x33, 0x11, 0xeb, 0x14, 0x32, 0x38, 0x6f, 0xf0, 0x45, 0x9f, 0x31, 0x3c, 0xaf, 0x65, 0xc0, 0x5, 0xa8, 0xf5, 0x76, 0x4e, 0xce, 0xfc, 0x92, 0x10, 0xac, 0x61, 0x78, 0x3a, 0x24, 0xc2, 0x6d, 0xd1, 0xdc, 0x86, 0x2a, 0x91, 0x42, 0x7a, 0xbf, 0xaf, 0x4f, 0x1c, 0xd2, 0x59, 0x17, 0x35, 0x7, 0xf2, 0x22, 0x17, 0x8c, 0xe, 0x49, 0x2f, 0x65, 0x5a, 0xd8, 0xe7, 0x53, 0xc8, 0x33, 0xc, 0x80, 0x5e, 0xa4, 0x98, 0x4b, 0x60, 0xa3, 0x5c, 0xef, 0x29, 0x0, 0x6b, 0xb5, 0x9c, 0x8a, 0xf6, 0xd, 0xa3, 0x59, 0x11, 0xcb, 0x39, 0x7, 0x97, 0xd2, 0x2e, 0x86, 0x5a, 0x46, 0xf9, 0x99, 0x7d, 0x9c, 0x2e, 0xac, 0x1e, 0x52, 0x79, 0x17, 0xee, 0x93, 0x2b, 0x2a, 0x66, 0x18, 0x52, 0x7d, 0x80, 0x8b, 0x90, 0x9f, 0xa1, 0x18, 0x4b, 0x3b, 0x45, 0xbd, 0xb1, 0x8a, 0x88, 0x81, 0x8f, 0x46, 0xff, 0xda, 0xca, 0x7a, 0x4, 0x75, 0x56, 0x3c, 0x60, 0xe0, 0xd8, 0x74, 0x31, 0x38, 0x22, 0x6, 0xc6, 0x43, 0xa8, 0x0, 0x9b, 0x75, 0x89, 0x19, 0x23, 0x21, 0x10, 0x10, 0xa9, 0x1, 0x7, 0xdb, 0x30, 0x1, 0x91, 0xa4, 0x91, 0x18, 0x20, 0x65, 0x43, 0xd2, 0x48, 0x88, 0x44, 0x30, 0x38, 0xe2, 0x9a, 0x12, 0x89, 0x52, 0x99, 0x94, 0x8, 0x92, 0x9e, 0x52, 0x99, 0x16, 0x53, 0x47, 0x76, 0x72, 0x15, 0x91, 0x62, 0x1a, 0x2e, 0x67, 0x94, 0xd8, 0xb6, 0x11, 0x6c, 0x5a, 0xce, 0xb4, 0xa1, 0x10, 0x39, 0xc8, 0xbd, 0x8f, 0x36, 0x14, 0xda, 0xd2, 0xc6, 0x85, 0xb6, 0x34, 0xda, 0x54, 0x51, 0xa2, 0x3c, 0x47, 0x12, 0x92, 0xa6, 0x3a, 0xd8, 0xd6, 0x11, 0x2e, 0xfb, 0x8e, 0x36, 0x42, 0x4b, 0xda, 0xfa, 0xc0, 0xc3, 0x82, 0x72, 0xab, 0xf7, 0x6e, 0xed, 0x7, 0xf6, 0x42, 0x1f, 0x16, 0xfa, 0xb4, 0x51, 0x1e, 0xd0, 0xa7, 0x6d, 0xfc, 0x71, 0x5, 0xb7, 0xf0, 0x32, 0xfa, 0xb8, 0xe, 0x3f, 0xef, 0x28, 0xc9, 0xf5, 0x9a, 0xc8, 0xf7, 0xe3, 0xf3, 0xae, 0x36, 0x60, 0x28, 0x8f, 0x38, 0xe3, 0x43, 0xd6, 0x6c, 0x64, 0xc8, 0x52, 0x1b, 0xf3, 0x14, 0x7, 0x4d, 0xd5, 0x51, 0x57, 0x6d, 0xd8, 0xae, 0x42, 0xc5, 0x71, 0x5f, 0xf1, 0xf, 0x87, 0xe2, 0x5f, 0x1e, 0xc5, 0x3f, 0x5d, 0xbf, 0xf2, 0x93, 0xf2, 0xf, 0x45, 0x13, 0xb6, 0x9d, 0x6, 0x38, 0x84, 0xb9, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, 0x00 }; +const unsigned char defaultDialogIcon5Name[] = { 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x64, 0x61, 0x72, 0x6b, 0x32, 0x78, 0x00 }; +const unsigned char defaultDialogIcon5Length[] = { 0x31, 0x35, 0x35, 0x37, 0x00 }; +const unsigned char defaultDialogIcon5Data[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x80, 0x8, 0x3, 0x0, 0x0, 0x0, 0xf4, 0xe0, 0x91, 0xf9, 0x0, 0x0, 0x0, 0x9f, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa, 0x77, 0x79, 0xb8, 0x0, 0x0, 0x0, 0x34, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xfb, 0x2, 0xa, 0x40, 0x62, 0xe5, 0x8a, 0x82, 0xe, 0x6, 0xb8, 0x2b, 0x19, 0x44, 0xed, 0xd9, 0x26, 0xb1, 0x94, 0x4e, 0x39, 0xc6, 0xf6, 0xbf, 0x55, 0x48, 0x21, 0x67, 0x33, 0xe0, 0xa8, 0x6c, 0xe8, 0xc2, 0x97, 0x90, 0x14, 0xd4, 0xb5, 0x3b, 0xd1, 0xcb, 0x7b, 0x52, 0xbc, 0x9e, 0xef, 0x71, 0x72, 0x5c, 0x1d, 0xd8, 0xaf, 0x95, 0x64, 0x0, 0x0, 0x4, 0xf1, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xec, 0x97, 0xdb, 0x96, 0xa2, 0x40, 0xc, 0x45, 0x23, 0x20, 0x20, 0x88, 0x82, 0x22, 0xd8, 0xde, 0xef, 0xed, 0xa5, 0x45, 0xa7, 0x27, 0xff, 0xff, 0x6d, 0xf3, 0x30, 0x6b, 0x69, 0xa, 0x52, 0x1d, 0x40, 0xed, 0x27, 0xf7, 0x6b, 0x61, 0xaa, 0xea, 0x24, 0x27, 0x29, 0xe1, 0xcd, 0x9b, 0x37, 0x6f, 0xde, 0xd4, 0xc7, 0xc, 0xa2, 0xa9, 0x15, 0xc7, 0xd6, 0x34, 0xa, 0x4c, 0xf8, 0x5d, 0x5a, 0x9d, 0x45, 0xff, 0x6c, 0x23, 0xc1, 0x3e, 0xf7, 0x17, 0x9d, 0x16, 0xfc, 0x6, 0x9e, 0xe5, 0x26, 0xd, 0x64, 0x69, 0x24, 0xae, 0xe5, 0xc1, 0x4b, 0x31, 0x46, 0xf3, 0x14, 0x7f, 0x24, 0x9d, 0x8f, 0xc, 0x78, 0x15, 0x6d, 0x67, 0x89, 0x25, 0x58, 0x3a, 0x6d, 0x78, 0x5, 0x7b, 0x1f, 0x4b, 0xe3, 0xf, 0xe0, 0xd9, 0x74, 0x86, 0x58, 0x89, 0x61, 0xe7, 0xb9, 0xe2, 0xf, 0xb1, 0x32, 0xc3, 0xe7, 0x25, 0xc2, 0x74, 0x1a, 0x58, 0x83, 0x86, 0x63, 0xc2, 0x53, 0x88, 0x67, 0x58, 0x93, 0x59, 0xfc, 0xc, 0xe7, 0x39, 0xf8, 0x0, 0xce, 0xc3, 0x9e, 0x6c, 0x7d, 0x6a, 0x15, 0xb6, 0x8f, 0xbd, 0xf5, 0xa9, 0xd9, 0x3c, 0xad, 0x7b, 0x47, 0x5b, 0x9b, 0xa3, 0xde, 0x83, 0xed, 0x71, 0xbc, 0x43, 0x8e, 0x83, 0x3b, 0x8, 0xc, 0x45, 0xa7, 0x60, 0xe0, 0x1e, 0x90, 0x63, 0x37, 0x86, 0x7, 0xb0, 0xba, 0xcc, 0xcd, 0x57, 0x57, 0x4d, 0xcc, 0xf1, 0x75, 0xc5, 0x28, 0xd1, 0xb5, 0xa0, 0x36, 0x93, 0x62, 0x3c, 0xbf, 0xb9, 0x85, 0x1f, 0xd8, 0x36, 0xfd, 0xe2, 0x89, 0x27, 0x75, 0xc7, 0x4e, 0x1f, 0xf3, 0x24, 0x3, 0x10, 0xd9, 0x27, 0x98, 0xa7, 0xef, 0xd5, 0xda, 0xbf, 0x50, 0x7e, 0xe1, 0x17, 0x94, 0xe2, 0x2b, 0xc4, 0x1c, 0x9f, 0x75, 0x4e, 0x90, 0xbf, 0xff, 0x72, 0x52, 0x3a, 0x8a, 0x37, 0x59, 0xe6, 0x35, 0xa8, 0x91, 0xff, 0x5c, 0x22, 0x5d, 0x13, 0x2a, 0x60, 0xba, 0xb9, 0xf2, 0xa9, 0x5c, 0x7, 0x96, 0x1a, 0xa0, 0xdb, 0xa9, 0x3c, 0xbd, 0xba, 0xea, 0x5, 0xac, 0x8a, 0xfe, 0x57, 0x7f, 0x1e, 0x46, 0x50, 0x99, 0x28, 0x54, 0xaf, 0x30, 0xae, 0xd4, 0xff, 0x76, 0xaa, 0xf7, 0x5a, 0xb5, 0x9a, 0xa8, 0xea, 0xc8, 0x5d, 0x85, 0x20, 0x86, 0x6a, 0x80, 0x8d, 0xa1, 0xf1, 0x7c, 0x36, 0xc, 0xd3, 0x74, 0xb6, 0x9a, 0x2f, 0x2, 0x3e, 0xcc, 0x6, 0x29, 0x3d, 0x3, 0xca, 0xe2, 0x28, 0xd9, 0x6b, 0xb2, 0xc1, 0x9b, 0x4a, 0xd7, 0x3b, 0x2e, 0x58, 0x8b, 0x34, 0x95, 0x4a, 0x72, 0xa0, 0x24, 0x31, 0x52, 0xd8, 0xfd, 0x47, 0xbb, 0xc2, 0xe8, 0xfd, 0x60, 0x4f, 0x80, 0x94, 0xb8, 0xa4, 0x85, 0x66, 0x8a, 0xfe, 0x5c, 0x76, 0x7b, 0xc8, 0xb0, 0xe2, 0x12, 0xb1, 0x51, 0xe, 0x69, 0x56, 0x4f, 0x80, 0x6f, 0x8, 0x23, 0x92, 0x30, 0x9b, 0x32, 0xa9, 0xf2, 0x2b, 0x27, 0xa1, 0x4d, 0xf3, 0x16, 0x32, 0xa5, 0x3b, 0xed, 0xa2, 0x86, 0xb4, 0xc3, 0xa8, 0x15, 0xd2, 0x7a, 0x6a, 0x83, 0xcc, 0x90, 0x9a, 0x97, 0xf1, 0x7f, 0x60, 0xa3, 0x96, 0xb, 0xf3, 0x7d, 0x44, 0xcf, 0x3b, 0x4, 0x91, 0xe, 0x3d, 0x30, 0x73, 0x23, 0xf3, 0x88, 0x3f, 0x10, 0x6e, 0x99, 0x88, 0x54, 0x52, 0xab, 0x92, 0x0, 0xae, 0x30, 0xa3, 0x18, 0xe6, 0x50, 0xc4, 0xad, 0x22, 0xc1, 0x9e, 0xce, 0x3f, 0x93, 0x11, 0x54, 0x7a, 0xa1, 0xf, 0x18, 0xd1, 0x96, 0xec, 0x3a, 0x8f, 0x2f, 0x4c, 0xb0, 0x9c, 0x1, 0xd3, 0x24, 0x49, 0x73, 0x66, 0x84, 0x22, 0xb, 0xfa, 0x34, 0x10, 0x2c, 0x40, 0xf3, 0xe9, 0x31, 0xe, 0x40, 0xca, 0xa6, 0x6d, 0x0, 0x18, 0xed, 0xd, 0x52, 0x98, 0xba, 0xf1, 0xa8, 0x13, 0xda, 0xa5, 0x7b, 0xc0, 0x97, 0xb0, 0x3e, 0xbb, 0x15, 0x94, 0x45, 0x5b, 0xd7, 0x9a, 0x7b, 0x23, 0x95, 0xed, 0x5, 0x6, 0xc9, 0x56, 0x2, 0xc, 0x21, 0xb1, 0x68, 0x40, 0xac, 0x49, 0xac, 0xb6, 0xe4, 0x66, 0xe, 0x79, 0x27, 0xda, 0x6, 0xe8, 0x19, 0x9, 0xd5, 0x12, 0x91, 0xf5, 0x6f, 0x20, 0x7c, 0xd3, 0x1f, 0xa, 0xb5, 0x3d, 0x2, 0x3d, 0x73, 0xd2, 0x83, 0x81, 0xe1, 0x43, 0xbb, 0xee, 0xb, 0xaf, 0x2f, 0x9f, 0x3a, 0x55, 0x8b, 0x97, 0xa, 0x43, 0xf0, 0xf, 0xde, 0xb8, 0x6a, 0x57, 0x5c, 0x61, 0x2c, 0xa6, 0x1e, 0xe8, 0xb0, 0x48, 0x13, 0xdc, 0xa, 0x35, 0xba, 0xd7, 0x6a, 0x9c, 0x1, 0xc3, 0xb6, 0x51, 0xa6, 0x1b, 0xba, 0xd4, 0xce, 0x1c, 0xd9, 0xfd, 0x80, 0x26, 0x28, 0xb4, 0x24, 0xa7, 0xaf, 0x58, 0x89, 0xf4, 0xb5, 0x7a, 0x15, 0x4e, 0xb8, 0xd3, 0x37, 0x90, 0x39, 0x8, 0xd9, 0x4b, 0x40, 0x43, 0x8b, 0xc8, 0x34, 0x16, 0x5c, 0x92, 0xe9, 0x73, 0xbc, 0x1, 0x8e, 0x31, 0x12, 0xf5, 0xe4, 0x41, 0x78, 0x10, 0x3a, 0xf5, 0xe5, 0x2f, 0xa8, 0xac, 0xf1, 0xc6, 0x9, 0x58, 0xe, 0xb4, 0x59, 0xf2, 0x2c, 0xe4, 0x34, 0x5, 0x87, 0xff, 0xfb, 0xc7, 0xf9, 0xc, 0xa4, 0x24, 0xbc, 0x58, 0x60, 0xb, 0xf9, 0xdf, 0xe0, 0x40, 0xeb, 0xd4, 0xd3, 0xea, 0xb2, 0xcb, 0xf2, 0xf7, 0x37, 0x8e, 0xb2, 0xc0, 0x3, 0xf9, 0x9f, 0xe2, 0x19, 0x6f, 0x4, 0x50, 0x5, 0x33, 0xc3, 0x3b, 0x67, 0x9d, 0x78, 0xf2, 0x27, 0xf6, 0xfd, 0x16, 0x6, 0x94, 0x80, 0xce, 0x22, 0xd9, 0xe5, 0xc6, 0xbd, 0xc4, 0x6d, 0xcd, 0x3d, 0x90, 0xf9, 0x42, 0xc0, 0xdc, 0x5f, 0xe7, 0x21, 0x52, 0x7c, 0x0, 0xf1, 0x7e, 0x68, 0x4a, 0x1a, 0x1d, 0xa1, 0x14, 0xad, 0xac, 0x81, 0x79, 0xa6, 0xa0, 0xe3, 0x28, 0x64, 0x98, 0x8e, 0xba, 0x5e, 0xb9, 0xfd, 0x67, 0xf2, 0x9b, 0x90, 0x7f, 0x4c, 0x45, 0xc0, 0x31, 0x55, 0x1f, 0x15, 0x32, 0x19, 0x16, 0x68, 0x44, 0xa0, 0x65, 0x2d, 0xc9, 0x64, 0x29, 0xbd, 0x44, 0xc6, 0x2c, 0xea, 0x9f, 0x8e, 0x40, 0xcf, 0x49, 0x2a, 0xd4, 0x58, 0x99, 0xc5, 0x32, 0xfb, 0xe2, 0xfe, 0x4c, 0x60, 0xb6, 0x5b, 0xc7, 0x4f, 0x39, 0xc0, 0x7, 0xe6, 0xb8, 0xfc, 0x6b, 0xdf, 0x8e, 0x5a, 0x12, 0x6, 0xa3, 0x30, 0x8e, 0x4f, 0x93, 0x5, 0x61, 0x8, 0xda, 0x8, 0x86, 0x91, 0xa0, 0x92, 0x17, 0x51, 0x24, 0x7d, 0xff, 0xcf, 0x16, 0xc6, 0x18, 0xc1, 0x5e, 0xfb, 0xb9, 0x8e, 0x31, 0x27, 0xfb, 0x5f, 0x7b, 0x71, 0x64, 0x7b, 0xcf, 0x7b, 0xce, 0xf3, 0x3c, 0xdb, 0x65, 0x81, 0x2, 0xf4, 0x8, 0x5c, 0xc0, 0xec, 0xd8, 0x1, 0xf0, 0x23, 0xf0, 0x4b, 0xe8, 0x2, 0x46, 0x6f, 0x5b, 0xfc, 0x1e, 0x2f, 0x21, 0x8e, 0x21, 0xa, 0x78, 0x7c, 0xc6, 0xdf, 0xc7, 0x31, 0x44, 0x23, 0x62, 0x1, 0x1b, 0x8, 0x50, 0x68, 0x44, 0x6a, 0xc5, 0x2e, 0xa0, 0x21, 0xcf, 0xa8, 0x15, 0xfb, 0x32, 0xa, 0x15, 0xe0, 0xcb, 0xc8, 0xd7, 0x71, 0xa8, 0x0, 0x5f, 0xc7, 0x1e, 0x48, 0x42, 0x5, 0x78, 0x20, 0xf1, 0x48, 0x16, 0x2b, 0xc0, 0x23, 0x99, 0x87, 0x52, 0xf3, 0xfa, 0xcb, 0x22, 0xed, 0xa1, 0xd4, 0x63, 0x39, 0x99, 0x62, 0xe7, 0xc7, 0x58, 0xce, 0xc5, 0x84, 0x8c, 0x67, 0x75, 0x13, 0x6e, 0x1c, 0x1a, 0x2f, 0x26, 0x5e, 0xcd, 0xcc, 0x12, 0x77, 0x17, 0x56, 0x33, 0x2e, 0xa7, 0x66, 0xd, 0x3f, 0x6, 0xcb, 0x29, 0xd7, 0x73, 0x53, 0xce, 0xf3, 0x7c, 0x5e, 0x66, 0x0, 0xeb, 0x39, 0x4, 0x8a, 0x0, 0x10, 0x28, 0x2c, 0xd1, 0x84, 0xb0, 0x44, 0x63, 0x91, 0x2a, 0x86, 0x45, 0x2a, 0xcb, 0x74, 0x31, 0x2c, 0xd3, 0x59, 0xa8, 0xc, 0x61, 0xa1, 0xd2, 0x52, 0xad, 0xd8, 0xee, 0x17, 0x8b, 0xbd, 0xe, 0xac, 0xa5, 0xda, 0x9f, 0x14, 0x69, 0xb1, 0x3a, 0x4d, 0x99, 0x7f, 0x3f, 0x54, 0x9c, 0x43, 0x8b, 0xd5, 0x96, 0xeb, 0xd3, 0x3c, 0x8d, 0xaa, 0xa6, 0x85, 0x79, 0x10, 0x72, 0x3d, 0xc, 0xb, 0xdc, 0x6f, 0xbe, 0x3b, 0x6d, 0x58, 0xd8, 0xb2, 0x49, 0x73, 0xef, 0x1, 0xca, 0x96, 0x8d, 0x4d, 0x2b, 0x74, 0x2d, 0xf4, 0x16, 0x9b, 0x56, 0xb6, 0xed, 0x62, 0xf3, 0x80, 0x6d, 0x3b, 0x1b, 0x97, 0xc7, 0x18, 0xbf, 0xd7, 0x4b, 0x61, 0x5d, 0xa5, 0x8c, 0xcb, 0x88, 0x75, 0xdb, 0x64, 0x89, 0x86, 0x1, 0xeb, 0x36, 0x62, 0x5e, 0x57, 0xac, 0xb1, 0x49, 0xc2, 0xbc, 0x8e, 0xd8, 0xf7, 0x15, 0xf, 0x87, 0x79, 0xa0, 0xfe, 0x5f, 0xb4, 0xef, 0xfb, 0x13, 0x60, 0xe8, 0x3e, 0xc2, 0xd1, 0x7d, 0x88, 0xa5, 0xfb, 0x18, 0x4f, 0x22, 0xc8, 0xb4, 0x3a, 0x3d, 0xc8, 0xb4, 0x6a, 0x4, 0x99, 0xba, 0x8e, 0x72, 0x8d, 0xcf, 0x15, 0x66, 0xdb, 0xfd, 0x29, 0xcc, 0xb6, 0xb9, 0xeb, 0x67, 0x9c, 0xaf, 0x7d, 0xa0, 0xf1, 0x23, 0x1d, 0x68, 0xec, 0x73, 0xa4, 0xb3, 0x4e, 0xec, 0x4, 0x42, 0xad, 0x7d, 0x8f, 0xf5, 0x76, 0x1f, 0x6c, 0xbe, 0x80, 0x68, 0x77, 0xf7, 0xe1, 0xf6, 0x3, 0x93, 0xb6, 0xf1, 0xfe, 0x49, 0x76, 0x6e, 0x8a, 0xba, 0x35, 0x9b, 0x97, 0x22, 0xfb, 0xf, 0xa6, 0xb7, 0xf9, 0xe7, 0x9, 0xe4, 0xc9, 0x4f, 0x3c, 0xae, 0xe2, 0x23, 0x97, 0xb, 0xf8, 0xcc, 0xa7, 0xe2, 0x26, 0xfd, 0xa1, 0x53, 0x9b, 0x53, 0xd7, 0xf3, 0x4f, 0xbd, 0x6, 0x6, 0x6, 0x6, 0xae, 0x8a, 0x2f, 0x2e, 0x60, 0x3a, 0x41, 0x7b, 0x3f, 0x8e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, 0x00 }; +const unsigned char defaultDialogIcon6Name[] = { 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x00 }; +const unsigned char defaultDialogIcon6Length[] = { 0x39, 0x33, 0x30, 0x00 }; +const unsigned char defaultDialogIcon6Data[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x40, 0x8, 0x3, 0x0, 0x0, 0x0, 0x9d, 0xb7, 0x81, 0xec, 0x0, 0x0, 0x0, 0x96, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3a, 0xb, 0xcd, 0x2a, 0x0, 0x0, 0x0, 0x31, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xf9, 0x1c, 0xe6, 0xb1, 0x4d, 0x3b, 0x17, 0xc9, 0xad, 0x49, 0x6, 0x8f, 0x40, 0xf6, 0xe3, 0xe0, 0xc1, 0x20, 0x11, 0x62, 0x54, 0x34, 0x30, 0x2b, 0x5d, 0xd6, 0xd0, 0x98, 0x76, 0x65, 0xb, 0x9b, 0x92, 0x6d, 0x2, 0x9, 0x3, 0x9c, 0xb5, 0x9d, 0xed, 0xe8, 0xbb, 0x79, 0xdc, 0x83, 0x71, 0x9f, 0x7a, 0xba, 0x9d, 0xd4, 0x0, 0x0, 0x2, 0x8a, 0x49, 0x44, 0x41, 0x54, 0x58, 0xc3, 0xec, 0x53, 0xdb, 0x62, 0x82, 0x30, 0xc, 0x5d, 0xcb, 0x5d, 0x51, 0x10, 0x10, 0x11, 0x1, 0x2f, 0xa8, 0x88, 0x9b, 0x3a, 0xfe, 0xff, 0xe7, 0xa6, 0x69, 0x9, 0x2d, 0x97, 0xa9, 0xf, 0x7b, 0x5b, 0x9e, 0x48, 0xd2, 0x13, 0x92, 0x73, 0x92, 0x8f, 0x7f, 0xfb, 0x53, 0xcb, 0x69, 0xa8, 0x5, 0x69, 0x1a, 0x68, 0x21, 0xcd, 0xdf, 0x47, 0x1b, 0x9a, 0x6d, 0x3a, 0xa4, 0x2, 0x23, 0x8e, 0x69, 0x6b, 0xc6, 0x5b, 0x70, 0x3d, 0x71, 0xab, 0x96, 0xb9, 0x89, 0xfe, 0x32, 0x7c, 0xa2, 0x92, 0xaa, 0xc7, 0x88, 0x3a, 0x79, 0x9, 0xee, 0x1d, 0x11, 0xde, 0x29, 0x71, 0xf4, 0x9e, 0xe3, 0x35, 0x57, 0x44, 0x28, 0x71, 0xac, 0x10, 0x71, 0x10, 0xed, 0x19, 0x7e, 0x37, 0xad, 0xdf, 0x2a, 0x56, 0xa6, 0x47, 0xd4, 0xf7, 0x69, 0xa4, 0x67, 0x96, 0x52, 0x47, 0xa7, 0xbb, 0x5f, 0xe1, 0xeb, 0x2d, 0xce, 0x3b, 0xa7, 0x62, 0x82, 0xce, 0x91, 0x97, 0xed, 0x7a, 0x18, 0xbf, 0xb7, 0xf8, 0xa3, 0xd9, 0xa8, 0x9b, 0x1c, 0xcd, 0x78, 0xd2, 0xda, 0xf, 0x16, 0xd8, 0xf2, 0xe6, 0x97, 0xe3, 0xbe, 0xec, 0x78, 0xa9, 0xf0, 0x1e, 0x6, 0xe7, 0x67, 0xf9, 0xd5, 0x62, 0xe8, 0xc1, 0x62, 0xc5, 0x5e, 0xc, 0xf0, 0x30, 0x62, 0xfc, 0xa9, 0x46, 0x3, 0x48, 0x2d, 0xd3, 0x54, 0xbf, 0x9a, 0x82, 0x86, 0xca, 0x98, 0x1c, 0xf5, 0xea, 0xef, 0x30, 0x3c, 0x72, 0x44, 0x37, 0x53, 0xce, 0xfc, 0xb7, 0x87, 0x2c, 0xb3, 0xa, 0x4e, 0xdf, 0x3e, 0x9c, 0x58, 0xff, 0xf8, 0xff, 0x30, 0xae, 0xd0, 0x2e, 0x3a, 0x56, 0x65, 0x53, 0x9c, 0x7a, 0xf6, 0x97, 0x0, 0x7f, 0xd8, 0x6e, 0xe4, 0x20, 0x5c, 0x8a, 0x2f, 0x80, 0x49, 0xd2, 0xd9, 0xea, 0x3, 0xeb, 0x6d, 0x89, 0x94, 0x33, 0xd1, 0xd0, 0x4c, 0xd4, 0x6e, 0xc9, 0x26, 0x3d, 0xb4, 0xef, 0x8f, 0x80, 0xfe, 0xa8, 0xdf, 0x9c, 0x2f, 0x84, 0x6d, 0xf3, 0x4a, 0x1, 0x2e, 0xb, 0x4, 0x48, 0xfb, 0x36, 0x13, 0x88, 0x36, 0xec, 0x16, 0xe0, 0xdf, 0xee, 0x5, 0xc7, 0x37, 0x56, 0x3b, 0x47, 0xb5, 0xc0, 0x4f, 0x64, 0xbc, 0xe1, 0x42, 0x5f, 0xe8, 0xd3, 0xf2, 0xe1, 0x6f, 0x98, 0xb3, 0x79, 0x7c, 0x97, 0x48, 0x7c, 0xe, 0xd3, 0xba, 0x86, 0x7c, 0x83, 0xd0, 0xe6, 0x1c, 0xfd, 0x10, 0x14, 0x9c, 0x20, 0xbf, 0xd8, 0x73, 0x33, 0x9e, 0x7c, 0x97, 0x36, 0x50, 0x4d, 0x65, 0x4d, 0x4a, 0xfe, 0x13, 0xf, 0xaa, 0x35, 0xe3, 0x51, 0x10, 0xc2, 0x96, 0xd6, 0xdc, 0x84, 0x2b, 0x11, 0x46, 0xba, 0xdc, 0xfd, 0x62, 0xcc, 0x87, 0x6e, 0xb3, 0x66, 0x81, 0x2e, 0xe2, 0xc1, 0x50, 0x10, 0x3d, 0x13, 0xd7, 0xc2, 0x2c, 0xb, 0x8f, 0x2b, 0xc, 0x84, 0x9e, 0x85, 0x99, 0x33, 0xd8, 0x46, 0xf1, 0xde, 0x43, 0x20, 0x56, 0x97, 0x9a, 0xf2, 0xf3, 0x7a, 0xa3, 0xd9, 0x11, 0x8b, 0x9a, 0x43, 0x4b, 0x61, 0x9b, 0x43, 0x12, 0xa1, 0x8f, 0x16, 0x5d, 0x8b, 0x33, 0xbb, 0x87, 0x50, 0x8c, 0x92, 0x36, 0x8b, 0x1, 0x72, 0xd8, 0xc2, 0x3, 0x5d, 0xb8, 0xfc, 0x32, 0x8b, 0x81, 0x10, 0x49, 0x1f, 0x81, 0xd8, 0xef, 0x14, 0xb8, 0xd6, 0xf8, 0x4f, 0x49, 0x75, 0x1f, 0xee, 0x2c, 0x7d, 0xa1, 0xc0, 0x4f, 0xfb, 0x65, 0xaf, 0x2, 0x20, 0xc, 0xc4, 0xe0, 0xb5, 0xae, 0xfe, 0xc, 0x22, 0x88, 0x8b, 0xe, 0xda, 0xf7, 0x7f, 0x3e, 0xb5, 0x20, 0xd1, 0x7e, 0x48, 0x87, 0xe0, 0x66, 0x36, 0x15, 0x5a, 0x9b, 0xde, 0x25, 0xb9, 0xe5, 0x52, 0xb1, 0xf4, 0x9, 0xb, 0x94, 0x8f, 0x30, 0x25, 0x6e, 0x86, 0x51, 0x37, 0x86, 0x23, 0x80, 0x44, 0x2e, 0x50, 0x49, 0x86, 0x41, 0x22, 0xae, 0x11, 0xb, 0xa0, 0x6d, 0x70, 0x8d, 0x28, 0x24, 0x70, 0xb0, 0xe8, 0x99, 0x85, 0xc4, 0x52, 0x46, 0x8b, 0xa8, 0xe8, 0x51, 0xca, 0x6c, 0x26, 0x8, 0xb5, 0xba, 0x48, 0x40, 0x33, 0xb1, 0x9d, 0x85, 0x36, 0x4, 0x91, 0xcd, 0x76, 0xa6, 0xa0, 0x0, 0x73, 0xa6, 0x7d, 0x10, 0x14, 0x48, 0x5a, 0x11, 0x94, 0x34, 0x8a, 0xaa, 0xd0, 0xf4, 0x7d, 0x5e, 0x9f, 0x14, 0x55, 0xca, 0xba, 0xe8, 0xa, 0x7, 0xdb, 0x19, 0xb5, 0x90, 0x75, 0x1a, 0x8b, 0x10, 0xcf, 0x77, 0xf1, 0x69, 0xb0, 0x2b, 0x8d, 0x85, 0xd6, 0xc6, 0x3a, 0x80, 0xb5, 0x15, 0xcc, 0x55, 0xbf, 0xa5, 0xcd, 0x60, 0xae, 0xef, 0xf6, 0x2e, 0x74, 0xdb, 0xd6, 0xdd, 0xf7, 0x97, 0xbd, 0x7b, 0x1, 0xc3, 0x8d, 0x38, 0x76, 0xc8, 0x72, 0x63, 0x9e, 0x19, 0x34, 0xdd, 0xa8, 0xeb, 0x85, 0xed, 0xa9, 0x36, 0xe3, 0xbe, 0x39, 0x70, 0x98, 0x23, 0x8f, 0x39, 0x74, 0xfd, 0xf8, 0x12, 0x3b, 0xca, 0x8, 0xb2, 0x9d, 0xe6, 0x23, 0xa2, 0x27, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, 0x00 }; +const unsigned char defaultDialogIcon7Name[] = { 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x32, 0x78, 0x00 }; +const unsigned char defaultDialogIcon7Length[] = { 0x31, 0x35, 0x33, 0x38, 0x00 }; +const unsigned char defaultDialogIcon7Data[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x80, 0x8, 0x3, 0x0, 0x0, 0x0, 0xf4, 0xe0, 0x91, 0xf9, 0x0, 0x0, 0x0, 0x9c, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf8, 0x8d, 0x4c, 0xde, 0x0, 0x0, 0x0, 0x33, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xfb, 0x42, 0x2, 0xa, 0x62, 0xb7, 0x82, 0xe6, 0x95, 0xe, 0x5, 0xb2, 0x19, 0x2b, 0xef, 0xe2, 0x3b, 0xd9, 0x4e, 0xc6, 0xf6, 0xbe, 0x55, 0x48, 0x91, 0x67, 0x33, 0x6c, 0x27, 0x23, 0xc2, 0xba, 0x20, 0x14, 0xd4, 0xa8, 0x89, 0x71, 0x38, 0xea, 0xd1, 0xcb, 0x8c, 0x7b, 0x52, 0x9c, 0xde, 0xa3, 0x88, 0x5c, 0x25, 0x3a, 0xec, 0xc2, 0x0, 0x0, 0x4, 0xe2, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xec, 0x97, 0xdb, 0x76, 0xb2, 0x30, 0x10, 0x85, 0x87, 0x70, 0x52, 0x11, 0x1, 0x1, 0x6b, 0x55, 0xea, 0x59, 0xeb, 0xa1, 0x6a, 0x3b, 0xef, 0xff, 0x6e, 0xff, 0xc5, 0xbf, 0x96, 0x24, 0x30, 0x61, 0x0, 0x6d, 0xaf, 0xfc, 0x6e, 0x61, 0x85, 0x64, 0xcf, 0xec, 0xd9, 0x1, 0x5e, 0xbc, 0x78, 0xf1, 0xe2, 0x45, 0x7b, 0x2c, 0x3f, 0x9b, 0x8a, 0x38, 0x16, 0xd3, 0xcc, 0xb7, 0xe0, 0x6f, 0xe9, 0x89, 0x59, 0x77, 0x11, 0xa2, 0x44, 0xb8, 0xe8, 0xce, 0x44, 0xf, 0xfe, 0x2, 0x4f, 0xb8, 0x89, 0x81, 0x24, 0x46, 0xe2, 0xa, 0xf, 0x7e, 0x15, 0x73, 0xbc, 0x49, 0xb1, 0x92, 0x74, 0x33, 0x36, 0xe1, 0xb7, 0x18, 0x9c, 0x3a, 0x58, 0x83, 0xce, 0x69, 0x0, 0xbf, 0x41, 0xe4, 0x60, 0x6d, 0x9c, 0x8, 0x9e, 0x8d, 0x18, 0x61, 0x23, 0x46, 0xe2, 0xb9, 0xe2, 0x8f, 0xb0, 0x31, 0xa3, 0xe7, 0x15, 0xc2, 0xda, 0x1a, 0xd8, 0x2, 0x63, 0x6b, 0xc1, 0x53, 0x88, 0x43, 0x6c, 0x49, 0x18, 0x3f, 0xc3, 0x79, 0x27, 0x7c, 0x80, 0xed, 0xc3, 0x9e, 0xec, 0xf5, 0xb5, 0xa, 0x87, 0xc7, 0x7e, 0xf7, 0x6c, 0xdb, 0xe7, 0x6e, 0xff, 0x18, 0x6a, 0x6b, 0xd4, 0x7f, 0x70, 0x3c, 0x7e, 0xac, 0x91, 0xe2, 0xe0, 0xee, 0x7d, 0x53, 0xd1, 0xc9, 0xdf, 0xbb, 0x7, 0xa4, 0x58, 0x7f, 0x3c, 0x64, 0xbe, 0x4f, 0xe2, 0xe4, 0xf3, 0xdd, 0x12, 0x48, 0x96, 0xbb, 0x39, 0xa1, 0xc4, 0xa7, 0x80, 0xd6, 0x4c, 0xca, 0xeb, 0x39, 0xf6, 0xa, 0x2a, 0x58, 0xd9, 0x4e, 0x79, 0xc7, 0x93, 0xb6, 0xb1, 0xd3, 0xc5, 0x22, 0x49, 0x4, 0x2c, 0x51, 0x82, 0x45, 0xde, 0xbd, 0x56, 0xdf, 0x2f, 0x9d, 0x65, 0xf8, 0x5, 0xb5, 0xf8, 0x1a, 0x96, 0x74, 0x6b, 0xb3, 0x83, 0xe2, 0xf9, 0x3b, 0x93, 0xda, 0xab, 0x78, 0x93, 0x4e, 0x51, 0x83, 0x16, 0xf5, 0x2f, 0x14, 0xd2, 0xb5, 0xa0, 0x1, 0x96, 0x6b, 0xa0, 0x42, 0xe3, 0x3e, 0x10, 0xea, 0x2, 0x81, 0x68, 0xbc, 0x40, 0xa0, 0x1e, 0x40, 0x34, 0xf4, 0xbf, 0xea, 0xbf, 0x61, 0xb, 0x33, 0x7f, 0xc, 0x55, 0x37, 0x2e, 0x1b, 0xcd, 0xbf, 0xb5, 0xda, 0x43, 0xbd, 0x56, 0x43, 0xd4, 0x51, 0x27, 0x52, 0x83, 0x45, 0x4c, 0x75, 0xfe, 0x9e, 0x4c, 0x8d, 0xe7, 0x6f, 0xa3, 0x61, 0x9a, 0x5e, 0xe7, 0x9b, 0x99, 0x4f, 0x2f, 0xf3, 0xae, 0x4e, 0xe5, 0xfa, 0xb9, 0xb0, 0x55, 0xaa, 0x67, 0x93, 0x8b, 0xdb, 0xca, 0xd4, 0x3b, 0xce, 0x48, 0x8b, 0xd8, 0x86, 0x92, 0x4c, 0xb5, 0xf3, 0x17, 0x65, 0xc8, 0xef, 0x8f, 0x4b, 0x19, 0x71, 0x7d, 0x23, 0x77, 0x80, 0x32, 0x71, 0x4d, 0xb, 0x85, 0x94, 0x83, 0xf9, 0x88, 0x9c, 0x53, 0x85, 0x50, 0xaa, 0x10, 0x5a, 0xcd, 0xb, 0xe0, 0x98, 0xb5, 0x23, 0x12, 0xc3, 0x29, 0x51, 0x2a, 0xa5, 0x13, 0xbf, 0xa1, 0x6, 0x3, 0x43, 0xf6, 0x1f, 0xd1, 0xba, 0xd3, 0x0, 0x35, 0xa4, 0x82, 0x50, 0x4b, 0x76, 0xa3, 0x31, 0x0, 0x9e, 0x11, 0xe6, 0x4, 0x84, 0xff, 0xfd, 0xe, 0x6a, 0x9, 0x32, 0x42, 0x2f, 0x79, 0xbf, 0x23, 0x60, 0x11, 0xcc, 0xf8, 0xb2, 0x8e, 0x58, 0xc1, 0x70, 0xc5, 0xc, 0x55, 0xd1, 0x48, 0x0, 0x97, 0xc9, 0x28, 0x82, 0xd, 0x94, 0x71, 0x9b, 0x48, 0x10, 0xc9, 0xf9, 0x47, 0x34, 0x6d, 0x66, 0x60, 0x35, 0x7b, 0x42, 0x34, 0x79, 0xae, 0x47, 0x50, 0x8d, 0xc3, 0x24, 0x58, 0xc1, 0x80, 0x69, 0x92, 0xa4, 0x5, 0x33, 0x42, 0x99, 0x99, 0x6c, 0x2b, 0xc6, 0x2, 0x72, 0x3d, 0x3d, 0xc2, 0x1, 0x6a, 0xca, 0xf, 0x4c, 0x0, 0x73, 0x20, 0x79, 0x9d, 0xae, 0xb2, 0x27, 0x3b, 0xa1, 0xda, 0x8, 0x27, 0xcc, 0xa1, 0xee, 0x3f, 0xdf, 0xf2, 0xec, 0xbb, 0x7f, 0x4a, 0x5c, 0x31, 0xe7, 0x42, 0xdd, 0x91, 0xe4, 0x64, 0xa9, 0x4c, 0x21, 0xc9, 0x62, 0x9, 0x10, 0x48, 0x47, 0x9, 0x7c, 0xc9, 0x9a, 0x81, 0xd4, 0x39, 0x54, 0xe6, 0x24, 0xc4, 0x73, 0x8a, 0x31, 0xd3, 0x2d, 0x19, 0xe6, 0xfc, 0x80, 0xc4, 0x8f, 0xdc, 0x86, 0x4c, 0x6f, 0x8f, 0x41, 0xcf, 0x86, 0x69, 0x96, 0x37, 0xed, 0xf3, 0x5, 0x73, 0xfb, 0x72, 0x64, 0xa7, 0x6a, 0xf1, 0x52, 0x26, 0x4, 0x77, 0x78, 0x67, 0xa7, 0x7d, 0xe2, 0x32, 0xb1, 0x98, 0x7a, 0x75, 0xa6, 0xa0, 0xb1, 0x62, 0x7a, 0x34, 0xd2, 0x6a, 0x7c, 0x1, 0x82, 0x95, 0x51, 0x67, 0x1a, 0xba, 0xb2, 0x9d, 0x29, 0x6e, 0xf9, 0x6, 0xad, 0x42, 0xe6, 0x48, 0x37, 0x1f, 0xa0, 0x98, 0x93, 0x12, 0xe9, 0x7b, 0x75, 0xc7, 0xec, 0x70, 0xad, 0x1f, 0x20, 0x1b, 0x60, 0xaa, 0x97, 0x80, 0x86, 0x9e, 0x24, 0xd3, 0x92, 0x76, 0x89, 0x56, 0x67, 0x9b, 0xfb, 0x9, 0x59, 0xa2, 0xa4, 0x1e, 0xdf, 0x2, 0x7, 0xc8, 0xa1, 0x9a, 0x3d, 0x58, 0xea, 0x33, 0xea, 0xc, 0x24, 0x7, 0xbe, 0x9, 0x66, 0x7c, 0x99, 0xfc, 0xff, 0xcb, 0x4, 0x31, 0xa8, 0x64, 0xa9, 0xb4, 0x3c, 0xdb, 0x60, 0x33, 0xfe, 0x6f, 0x70, 0xaf, 0x75, 0xea, 0x79, 0x1e, 0xac, 0x2f, 0xc5, 0xf3, 0x9b, 0x47, 0x5e, 0xe0, 0x3d, 0xde, 0xe9, 0x6a, 0xf5, 0xbd, 0xe3, 0x43, 0x13, 0xac, 0x1b, 0xe6, 0x2c, 0x74, 0xe2, 0xf1, 0xaf, 0x84, 0xf9, 0x29, 0x4c, 0x68, 0x40, 0x74, 0x45, 0xe4, 0xb, 0x6c, 0xe6, 0x2d, 0x1e, 0x6a, 0xce, 0x81, 0xc4, 0x1b, 0xc, 0x56, 0xb4, 0xbb, 0xd, 0x51, 0x66, 0x1, 0x3a, 0xa4, 0xa0, 0xb3, 0x38, 0x8d, 0x8e, 0x50, 0x8b, 0xde, 0xc5, 0xc0, 0x22, 0x53, 0xd0, 0x71, 0xe4, 0x2a, 0x9c, 0xa9, 0xc3, 0x8c, 0xa7, 0x77, 0xe5, 0xef, 0x84, 0xf4, 0x65, 0x2a, 0x3, 0x8a, 0xa9, 0xda, 0xa6, 0x3c, 0x17, 0x2c, 0x61, 0x64, 0xa0, 0xa5, 0xcb, 0xc9, 0x24, 0x94, 0x59, 0xc2, 0x63, 0x95, 0xf5, 0x4f, 0xab, 0xb2, 0xfe, 0xcc, 0x35, 0x6a, 0xac, 0x64, 0x31, 0x4f, 0x54, 0xf1, 0x67, 0xc4, 0x24, 0x72, 0xfc, 0x94, 0xd, 0xbc, 0x61, 0x81, 0xe0, 0x5f, 0xfb, 0x76, 0xb3, 0x9a, 0x30, 0x14, 0x44, 0x1, 0xb8, 0x12, 0x17, 0x37, 0x20, 0x95, 0x2e, 0xa, 0xa6, 0x75, 0xd1, 0xa, 0x5, 0x37, 0x95, 0xd6, 0xf7, 0x7f, 0xb8, 0x62, 0x11, 0x5, 0xaf, 0xf1, 0x53, 0xc7, 0x9f, 0x1b, 0xc9, 0x59, 0x67, 0x31, 0x9a, 0xcc, 0xdf, 0x39, 0x67, 0x5e, 0x9e, 0x2, 0x1, 0xe8, 0x15, 0x38, 0x80, 0x71, 0x5b, 0xf9, 0xf4, 0x2b, 0xf0, 0x47, 0xe8, 0x0, 0x6, 0x8b, 0x19, 0x9e, 0xc7, 0x47, 0x88, 0x34, 0x44, 0x0, 0xaf, 0x3f, 0x6d, 0xf9, 0xef, 0x34, 0x74, 0x21, 0x72, 0x0, 0xd, 0x8, 0x28, 0x14, 0x22, 0x95, 0x62, 0x7, 0x90, 0xd1, 0x33, 0x2a, 0xc5, 0x6e, 0x46, 0xa1, 0x0, 0xdc, 0x8c, 0xdc, 0x8e, 0x43, 0x1, 0xb8, 0x1d, 0x7b, 0x20, 0x9, 0x5, 0xe0, 0x81, 0xc4, 0x23, 0x59, 0x2c, 0x0, 0x8f, 0x64, 0x1e, 0x4a, 0x8d, 0xef, 0x3, 0x8b, 0xb4, 0x87, 0x52, 0x8f, 0xe5, 0xc4, 0x33, 0xf2, 0x1a, 0x63, 0x39, 0x17, 0x13, 0xa2, 0x1a, 0x6f, 0x8a, 0x70, 0x96, 0x34, 0x5e, 0x4c, 0xbc, 0x9a, 0x19, 0x6f, 0xe8, 0x5d, 0x58, 0xcd, 0xb8, 0x9c, 0x1a, 0x35, 0x3a, 0x7, 0x96, 0x53, 0xae, 0xe7, 0xc6, 0x64, 0x94, 0xd2, 0x68, 0x82, 0x87, 0xb0, 0x9e, 0x83, 0xa0, 0x8, 0x40, 0x4, 0x85, 0x29, 0x9a, 0x10, 0x4c, 0xd1, 0x98, 0xa4, 0x8a, 0xc1, 0x24, 0x95, 0x69, 0xba, 0x18, 0x4c, 0xd3, 0x99, 0xa8, 0xc, 0xc1, 0x44, 0xa5, 0xa9, 0x5a, 0x61, 0xb6, 0xac, 0xeb, 0x25, 0x12, 0x16, 0x54, 0x2d, 0xc8, 0x6a, 0x64, 0x61, 0xfa, 0x7f, 0x4c, 0x79, 0x38, 0x9c, 0x83, 0x45, 0x4, 0x5d, 0xdf, 0x8a, 0xf7, 0xc1, 0xba, 0x68, 0x61, 0x1e, 0x4, 0x5d, 0xf, 0xc1, 0x2, 0xfd, 0xd, 0xbd, 0x53, 0x82, 0x85, 0x25, 0x1b, 0x8c, 0x38, 0x18, 0xa0, 0x2c, 0xd9, 0x58, 0xb4, 0x42, 0xd5, 0x42, 0x6d, 0xb1, 0x68, 0x65, 0xd9, 0xe, 0x29, 0x8b, 0xd4, 0xa2, 0x6c, 0x67, 0xe1, 0x32, 0x36, 0xf, 0x58, 0xb8, 0xb4, 0x74, 0x8b, 0x79, 0x20, 0x2b, 0x18, 0x90, 0x6e, 0x3, 0xe2, 0x75, 0x86, 0x45, 0xc6, 0x9a, 0x42, 0xbc, 0x3e, 0x53, 0xbe, 0x6f, 0xaa, 0xd6, 0xff, 0x6a, 0x35, 0xf, 0x64, 0xbf, 0xb, 0xf2, 0xfd, 0xed, 0xc, 0xc, 0x1f, 0x3b, 0x6, 0x86, 0x2e, 0x59, 0x38, 0xee, 0x6f, 0x62, 0xb9, 0xbf, 0x8d, 0x67, 0x8f, 0x91, 0x69, 0x7a, 0xbc, 0x91, 0x69, 0x3a, 0x87, 0x91, 0xe9, 0x6, 0x56, 0x2e, 0x27, 0x80, 0x23, 0x68, 0x2e, 0x67, 0x66, 0xeb, 0xa6, 0x9d, 0xaf, 0x0, 0x43, 0xe3, 0x45, 0x2c, 0x9d, 0x9f, 0x57, 0x33, 0xb5, 0xa6, 0xad, 0xa9, 0x35, 0xc1, 0xd4, 0x1a, 0x41, 0xf5, 0x15, 0xb3, 0xf5, 0x76, 0xdf, 0xd8, 0x1c, 0xb0, 0x76, 0xff, 0xae, 0x8a, 0xe7, 0x43, 0x98, 0xdb, 0xb, 0xb0, 0xf7, 0x17, 0x70, 0xe0, 0x50, 0xc0, 0x89, 0x47, 0x1, 0x47, 0x2e, 0x5, 0x9c, 0xf9, 0xac, 0x31, 0xdc, 0x7f, 0xe8, 0x74, 0x42, 0xd6, 0x75, 0xfd, 0xd4, 0xab, 0x47, 0x8f, 0x1e, 0x3d, 0x1e, 0xa, 0x7f, 0x3b, 0x1f, 0x29, 0xf, 0xbf, 0x29, 0x8c, 0x32, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, 0x00 }; +const unsigned char defaultDialogIcon8Name[] = { 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x2d, 0x64, 0x61, 0x72, 0x6b, 0x00 }; +const unsigned char defaultDialogIcon8Length[] = { 0x38, 0x33, 0x30, 0x00 }; +const unsigned char defaultDialogIcon8Data[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x40, 0x8, 0x3, 0x0, 0x0, 0x0, 0x9d, 0xb7, 0x81, 0xec, 0x0, 0x0, 0x0, 0x78, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc6, 0xa8, 0xe4, 0xac, 0x0, 0x0, 0x0, 0x27, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x3, 0xfb, 0xa5, 0x7e, 0xc9, 0x8e, 0xeb, 0xb2, 0x1c, 0x13, 0xc, 0x7b, 0xa4, 0x43, 0x92, 0xf6, 0xe1, 0xa0, 0x77, 0x47, 0x25, 0x8, 0xc5, 0xf2, 0xdc, 0xd6, 0xd4, 0x88, 0x6b, 0x51, 0x29, 0x27, 0xe, 0xbe, 0x37, 0x36, 0xbf, 0x58, 0xbe, 0xe, 0x1c, 0x70, 0x0, 0x0, 0x2, 0x4e, 0x49, 0x44, 0x41, 0x54, 0x58, 0xc3, 0xdc, 0x54, 0x6b, 0x8f, 0x82, 0x40, 0xc, 0x64, 0x91, 0xe5, 0xa5, 0x82, 0xf2, 0x46, 0x5e, 0xea, 0x99, 0xf4, 0xff, 0xff, 0xc3, 0x4b, 0xbb, 0x1e, 0x50, 0xea, 0x5, 0x3c, 0xbf, 0x5d, 0xa3, 0x89, 0x3b, 0x9d, 0x19, 0xda, 0x6e, 0xd1, 0xfa, 0xdf, 0xa1, 0xc6, 0xf8, 0x93, 0x58, 0x9c, 0xdf, 0x9, 0x62, 0x7, 0x59, 0xd7, 0xc6, 0x49, 0x12, 0xb7, 0x5d, 0x16, 0x10, 0xf8, 0x8e, 0x5c, 0x45, 0xae, 0x3e, 0xc1, 0x18, 0x27, 0xed, 0x46, 0x88, 0x6e, 0x95, 0x87, 0x69, 0x43, 0x3a, 0xfb, 0x19, 0x74, 0x68, 0xd2, 0x90, 0x92, 0xeb, 0xfa, 0xbd, 0xe3, 0x91, 0x78, 0x74, 0xf8, 0x39, 0x79, 0xce, 0x7e, 0xcd, 0x1, 0xf3, 0x7d, 0x4d, 0x7c, 0xfa, 0x9a, 0x98, 0xce, 0x75, 0x2f, 0x8a, 0x10, 0x7a, 0x17, 0x0, 0x95, 0xa4, 0xae, 0xce, 0xda, 0xf7, 0xf5, 0xb9, 0x2, 0x18, 0x41, 0x97, 0x3b, 0xc8, 0xf2, 0x7d, 0x7a, 0x12, 0x7e, 0xca, 0xc3, 0x23, 0x2c, 0x70, 0x72, 0x45, 0xf8, 0x38, 0x94, 0x4, 0x62, 0xce, 0x9f, 0xb5, 0x21, 0xf5, 0xd7, 0xb, 0xd1, 0xb0, 0xdd, 0x9c, 0xe7, 0x72, 0x1c, 0xc, 0xe5, 0x2e, 0xd7, 0xc9, 0x41, 0xe8, 0x3d, 0xc3, 0xb1, 0xdd, 0x80, 0xed, 0xe, 0xfd, 0xa, 0x5c, 0xdb, 0x64, 0xbd, 0xd1, 0x41, 0xd4, 0xff, 0x7c, 0x7e, 0x39, 0xbc, 0xde, 0xc4, 0x41, 0x3f, 0x6b, 0xf8, 0xad, 0xb, 0xdf, 0x8c, 0xee, 0xa8, 0x26, 0x39, 0xb7, 0x50, 0x47, 0x33, 0x4e, 0xff, 0x75, 0x1, 0xae, 0xd1, 0x3b, 0x6c, 0xce, 0x93, 0x15, 0xc1, 0x8e, 0x71, 0x70, 0x2d, 0x25, 0xf5, 0xbd, 0xa9, 0xcf, 0x61, 0x1a, 0x51, 0x84, 0x63, 0x58, 0xbd, 0x74, 0xd8, 0xd7, 0x80, 0x43, 0x3a, 0xf2, 0x8c, 0xca, 0x32, 0x7e, 0xb6, 0x8e, 0x44, 0xab, 0xf7, 0xa2, 0x0, 0x87, 0x12, 0x5a, 0x31, 0x83, 0xdb, 0x1d, 0xe0, 0x7e, 0x63, 0x3c, 0xa5, 0x89, 0xe8, 0x2c, 0x4b, 0x8, 0xcd, 0xd, 0xe, 0x88, 0x4f, 0xec, 0x3, 0xae, 0xce, 0x81, 0x63, 0x83, 0xb9, 0xcb, 0x70, 0x51, 0x40, 0xa, 0xb6, 0x18, 0xe, 0xd5, 0x8b, 0x5d, 0x71, 0x30, 0x26, 0x6a, 0xba, 0xe8, 0xb5, 0x41, 0xaa, 0x17, 0x2c, 0xb8, 0x3b, 0x44, 0x77, 0xb, 0x30, 0xf0, 0x10, 0x6d, 0x38, 0x18, 0x1, 0x4c, 0x8d, 0x49, 0x3, 0x39, 0x2e, 0x80, 0x8, 0x61, 0xbe, 0x3, 0x76, 0xbe, 0xcd, 0x20, 0xb7, 0xe5, 0x2e, 0x68, 0x64, 0x96, 0xd3, 0x59, 0x18, 0xb0, 0x28, 0x11, 0xd6, 0x73, 0x24, 0x38, 0x1, 0xf0, 0x71, 0x4b, 0x3, 0x7e, 0x39, 0x0, 0xa7, 0x60, 0x86, 0x64, 0x80, 0xf1, 0xd8, 0x6a, 0xf0, 0x45, 0xf4, 0x8c, 0x70, 0x83, 0x74, 0x68, 0x59, 0x85, 0x5b, 0x5b, 0x8, 0x2b, 0x2c, 0xb8, 0x9b, 0x19, 0xb4, 0x48, 0x3c, 0x17, 0x5b, 0xd, 0x8a, 0x33, 0xe2, 0xed, 0xcc, 0x20, 0xa6, 0xa9, 0xa8, 0xad, 0x6, 0x8a, 0x66, 0x1e, 0xcf, 0xc, 0x12, 0x4, 0x7c, 0x6b, 0xab, 0x81, 0xe5, 0x23, 0x9e, 0x7c, 0x6c, 0xf0, 0x71, 0xb, 0xeb, 0x43, 0x94, 0x2f, 0x93, 0x1c, 0xa2, 0xbc, 0x46, 0xf9, 0x3a, 0xaf, 0x5c, 0xa3, 0x5c, 0x24, 0xf9, 0x87, 0xb2, 0xb2, 0x48, 0x72, 0x95, 0x27, 0x72, 0xf4, 0xdd, 0x7d, 0xb9, 0xa3, 0x0, 0xc, 0xc3, 0x30, 0x74, 0xea, 0x9a, 0xe6, 0x73, 0x84, 0x90, 0xf8, 0xfe, 0x37, 0x6c, 0x31, 0x18, 0xf, 0xa2, 0x8, 0xaa, 0x2d, 0x86, 0x40, 0x8, 0x64, 0x31, 0xb6, 0xf4, 0x54, 0xf2, 0xd, 0x47, 0x19, 0x97, 0x9, 0x55, 0xd4, 0xf, 0x5b, 0x26, 0x5c, 0xe7, 0xec, 0x97, 0x77, 0x96, 0xac, 0x33, 0x8, 0x4a, 0xd6, 0x68, 0x6d, 0xc4, 0x1d, 0x5, 0x85, 0x4b, 0xda, 0xb6, 0xb7, 0xf6, 0xa7, 0xa4, 0x71, 0x51, 0xed, 0x56, 0xab, 0x75, 0x22, 0xaa, 0x8a, 0xac, 0x73, 0x63, 0x59, 0x66, 0x8b, 0x18, 0xb, 0xb1, 0xb6, 0x52, 0x88, 0xb5, 0xc9, 0xe6, 0xaa, 0xdb, 0xbb, 0xe, 0x18, 0x88, 0x38, 0xd7, 0x2f, 0xc4, 0xe1, 0x90, 0x75, 0x7, 0x64, 0xf9, 0xc4, 0xb, 0x98, 0x17, 0xff, 0x39, 0x68, 0xce, 0x0, 0xcd, 0x9, 0xa0, 0xa9, 0xa1, 0xae, 0xa, 0xdb, 0x22, 0xee, 0xab, 0x81, 0x43, 0x8c, 0x3c, 0x62, 0xe8, 0x12, 0x63, 0x9f, 0x16, 0x3c, 0x8f, 0xae, 0x7, 0x37, 0xe7, 0x62, 0x42, 0xa9, 0x5c, 0xc2, 0xf9, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, 0x00 }; +const unsigned char defaultDialogIcon9Name[] = { 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x2d, 0x64, 0x61, 0x72, 0x6b, 0x32, 0x78, 0x00 }; +const unsigned char defaultDialogIcon9Length[] = { 0x31, 0x32, 0x37, 0x34, 0x00 }; +const unsigned char defaultDialogIcon9Data[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x80, 0x8, 0x3, 0x0, 0x0, 0x0, 0xf4, 0xe0, 0x91, 0xf9, 0x0, 0x0, 0x0, 0x96, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x25, 0xc5, 0xa8, 0x0, 0x0, 0x0, 0x31, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x55, 0xfb, 0x3, 0xe3, 0xc, 0x43, 0x92, 0x8a, 0xd7, 0xb7, 0x82, 0x62, 0x40, 0x19, 0x48, 0x4e, 0x2b, 0xee, 0xe7, 0x39, 0xbf, 0x21, 0x97, 0x67, 0xb4, 0x33, 0xd0, 0x6c, 0x9, 0xcb, 0xf, 0xc5, 0xb1, 0xf6, 0xc2, 0xbc, 0xa8, 0x71, 0x26, 0x25, 0x14, 0x7, 0xc6, 0x3b, 0x7c, 0x5d, 0x11, 0x7b, 0x95, 0x98, 0x75, 0x67, 0x0, 0x0, 0x3, 0xe2, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xec, 0x96, 0xd9, 0x8e, 0xb3, 0x30, 0xc, 0x85, 0x5d, 0x2, 0x94, 0xb2, 0xb7, 0x65, 0x69, 0xe9, 0xbe, 0x4f, 0xb7, 0x91, 0xf2, 0xfe, 0x2f, 0xf7, 0x4b, 0xbf, 0x46, 0xc2, 0x50, 0x1a, 0x13, 0x12, 0x46, 0x73, 0xd1, 0xef, 0xda, 0xa2, 0x27, 0x3e, 0x3e, 0x76, 0xe1, 0xc3, 0x87, 0xf, 0x1f, 0x3e, 0x74, 0x67, 0x15, 0x5e, 0xa, 0x3b, 0x8e, 0xed, 0xe2, 0x12, 0xae, 0xe0, 0x77, 0xb1, 0xec, 0x65, 0x7e, 0x34, 0x39, 0xc2, 0x3c, 0xe6, 0x4b, 0xdb, 0x82, 0xdf, 0xe0, 0x16, 0x78, 0x77, 0x83, 0x37, 0x62, 0xdc, 0xbd, 0xe0, 0x6, 0xbd, 0xc2, 0xa2, 0xd3, 0x9e, 0xb, 0xd9, 0x9f, 0x22, 0x6, 0x7d, 0x31, 0x76, 0xa6, 0xbc, 0x5, 0x53, 0x67, 0xc, 0x7d, 0xf0, 0x70, 0x79, 0x6b, 0xdc, 0x4, 0x74, 0x63, 0xa7, 0x5c, 0x8a, 0xd4, 0xd6, 0xdb, 0xfc, 0x94, 0x4b, 0x93, 0xea, 0x33, 0xc2, 0x72, 0xc, 0xde, 0x1, 0xc3, 0xd1, 0x94, 0xcb, 0xd8, 0xe4, 0x1d, 0x31, 0x63, 0x50, 0x87, 0x39, 0x5c, 0x1, 0x87, 0x29, 0xb7, 0x7f, 0xfe, 0xb6, 0xc3, 0xe6, 0x7a, 0x97, 0x3f, 0x7d, 0xff, 0x99, 0xef, 0xd6, 0xe6, 0x5b, 0x8f, 0xe6, 0x8a, 0x36, 0x64, 0x23, 0xde, 0xc4, 0xc2, 0x4b, 0x42, 0x6, 0x8, 0x16, 0x26, 0xde, 0x82, 0x37, 0x31, 0xca, 0x40, 0x81, 0x60, 0xd2, 0xf0, 0xf2, 0xc3, 0x39, 0x7b, 0xa3, 0xf6, 0x7c, 0x68, 0xe8, 0xc4, 0x24, 0x80, 0xce, 0xcc, 0x5e, 0xbf, 0xe7, 0xfa, 0x57, 0x10, 0x70, 0xf5, 0xdd, 0x57, 0xc5, 0x33, 0xe8, 0x6, 0x1b, 0xf2, 0x3a, 0xdb, 0x4, 0x48, 0x1e, 0x5b, 0x5e, 0x67, 0xc8, 0x3a, 0xfd, 0xfe, 0xfc, 0xc5, 0xce, 0x96, 0xa9, 0x1a, 0x8c, 0x5e, 0x46, 0xb1, 0x8b, 0x82, 0xfa, 0xfb, 0xa7, 0x33, 0xd6, 0x5a, 0xfb, 0x6c, 0x5a, 0xef, 0x41, 0x7, 0xff, 0x6b, 0x46, 0x7a, 0x96, 0x54, 0x7a, 0xbd, 0xda, 0xf8, 0x48, 0xcf, 0x41, 0x60, 0x54, 0x47, 0xd9, 0x6, 0x49, 0xec, 0x6a, 0x80, 0x8c, 0x40, 0x32, 0xff, 0x93, 0xaa, 0xfb, 0x5f, 0x20, 0xcd, 0xd7, 0xa8, 0xfa, 0x84, 0x4c, 0xaa, 0x83, 0xa3, 0x6a, 0xf6, 0x36, 0xd0, 0x81, 0x8d, 0x5b, 0x7d, 0x84, 0xd5, 0x39, 0x0, 0xe, 0x53, 0xcb, 0xb1, 0x7c, 0x14, 0x9c, 0x8a, 0x7b, 0x3e, 0x74, 0xc6, 0x37, 0x2a, 0xf, 0x81, 0x96, 0xc4, 0x1c, 0xe3, 0x83, 0x2, 0x3e, 0xc7, 0xc4, 0x2d, 0x7, 0xc0, 0x14, 0x24, 0x58, 0x69, 0x9b, 0x98, 0x2b, 0x79, 0x3, 0x5c, 0x6, 0x4a, 0x30, 0x57, 0xda, 0x84, 0x31, 0xf6, 0x6d, 0xb4, 0x11, 0xf, 0xfa, 0xf7, 0x70, 0xf8, 0x4d, 0x94, 0xe0, 0x40, 0x19, 0x63, 0xa0, 0x49, 0x71, 0x78, 0xc5, 0xf9, 0x8f, 0xfe, 0x9b, 0x65, 0x46, 0xe2, 0x7d, 0x80, 0x57, 0x4a, 0xa, 0x24, 0x36, 0x16, 0x6c, 0x83, 0x88, 0xc2, 0xf8, 0x29, 0x2b, 0xc4, 0x5f, 0xc4, 0x2d, 0xb5, 0xa5, 0x1a, 0xe0, 0x81, 0x90, 0x5, 0xff, 0x61, 0xd, 0x42, 0x3c, 0x99, 0x16, 0x3c, 0xf0, 0xfd, 0xb3, 0x40, 0x44, 0x58, 0x56, 0x86, 0xe2, 0x58, 0xe1, 0xdb, 0x98, 0x80, 0x18, 0xb7, 0xfd, 0x5, 0x8b, 0xca, 0xca, 0x8, 0x84, 0x2c, 0x71, 0xac, 0x88, 0x8, 0xe0, 0x4, 0x10, 0x9, 0x1c, 0x94, 0xa5, 0x3, 0x22, 0x8b, 0x38, 0x9, 0xe3, 0xd6, 0x3b, 0x60, 0x0, 0x84, 0x0, 0xe9, 0x52, 0x7a, 0x17, 0x30, 0xe4, 0xd6, 0x16, 0xf4, 0x9, 0x80, 0x3b, 0x9a, 0x2c, 0xd6, 0xce, 0x56, 0x9e, 0xe8, 0x14, 0xf0, 0xe0, 0xed, 0x6, 0xe6, 0x44, 0xd, 0xb, 0x2d, 0x80, 0x1e, 0xee, 0x13, 0xbc, 0xe5, 0xb6, 0xa7, 0x8e, 0x20, 0x2d, 0x80, 0x3e, 0x8b, 0xfb, 0x1b, 0xbc, 0x23, 0x40, 0x4b, 0xf0, 0xaa, 0x57, 0xc0, 0x15, 0xad, 0xc3, 0xa0, 0xcd, 0xca, 0x3a, 0x80, 0x5e, 0x1, 0x70, 0xa8, 0x2c, 0x58, 0x7a, 0x56, 0xcf, 0xba, 0x5, 0x9c, 0x5b, 0xe4, 0xcb, 0x42, 0x6d, 0xca, 0x74, 0xb, 0xc8, 0x90, 0xbd, 0x16, 0x7d, 0x8, 0x17, 0xa0, 0x5b, 0x0, 0x2c, 0xe8, 0x93, 0xb8, 0x44, 0x36, 0x29, 0x8, 0xa0, 0x7, 0x6c, 0x9, 0xcd, 0xe4, 0x68, 0xb, 0xe9, 0x17, 0x90, 0xd0, 0xff, 0x33, 0x8f, 0xe8, 0xbe, 0x2a, 0x8, 0xa0, 0xaf, 0xf7, 0x11, 0x9a, 0x31, 0xcb, 0x31, 0x61, 0xfa, 0x5, 0xb0, 0x72, 0xc4, 0x4d, 0x68, 0x64, 0xc5, 0x51, 0x85, 0x8a, 0x0, 0xf2, 0x7d, 0x7c, 0x45, 0xf5, 0x68, 0xdd, 0x87, 0x80, 0x35, 0xe5, 0xf0, 0xa5, 0x2c, 0xd8, 0xf5, 0x21, 0x60, 0x57, 0xd6, 0x5f, 0xa0, 0x89, 0xa2, 0x2c, 0xc8, 0x95, 0x4, 0xd0, 0x21, 0x2b, 0xa8, 0x53, 0xf4, 0xec, 0x43, 0xc0, 0x93, 0x3a, 0x47, 0x31, 0xba, 0xc5, 0x4a, 0x2, 0xe8, 0x8b, 0x1c, 0xff, 0x4d, 0x1, 0xff, 0xda, 0x37, 0x83, 0x15, 0x4, 0xa1, 0x28, 0x88, 0x1a, 0x12, 0x6e, 0x14, 0x34, 0x5d, 0x24, 0x19, 0xd8, 0x3a, 0x41, 0xff, 0xff, 0xeb, 0xc2, 0xa0, 0x20, 0x31, 0x4f, 0x3a, 0xd2, 0x7d, 0xca, 0x9b, 0xb5, 0xbb, 0xd2, 0x7b, 0x67, 0xee, 0x19, 0xf3, 0x9f, 0xc0, 0xfc, 0x4f, 0x68, 0xfe, 0x1a, 0x9a, 0x7f, 0x88, 0xe0, 0x53, 0xc, 0xd6, 0x4c, 0xf8, 0x14, 0xf3, 0x30, 0x62, 0x73, 0x2a, 0xd, 0x23, 0x1e, 0xc7, 0x6c, 0xcf, 0x85, 0x71, 0xcc, 0xb, 0x9, 0x7, 0x14, 0x59, 0x20, 0x2c, 0x24, 0xb0, 0x92, 0x9, 0x11, 0xd, 0xac, 0x64, 0xca, 0x52, 0xca, 0x21, 0x15, 0x2f, 0xa5, 0xbc, 0x96, 0x4b, 0xe2, 0xb5, 0x9c, 0x8d, 0x89, 0x24, 0x36, 0x26, 0x6c, 0xcd, 0x34, 0xb1, 0x35, 0x63, 0x73, 0x2a, 0x89, 0xcd, 0x29, 0xdb, 0x73, 0x4d, 0x6c, 0xcf, 0x39, 0xa0, 0x60, 0xa5, 0x65, 0x9e, 0x97, 0x90, 0x81, 0x43, 0x40, 0x1, 0x11, 0xd, 0xc, 0x58, 0x18, 0xde, 0x10, 0xd1, 0x60, 0x48, 0x45, 0x3a, 0x43, 0xa0, 0x8, 0x21, 0x95, 0x1c, 0xd3, 0x85, 0xa7, 0x77, 0xa6, 0x1d, 0x2a, 0x31, 0x1d, 0x7, 0x95, 0xfc, 0x6c, 0x36, 0x27, 0xa8, 0x74, 0x3b, 0xaa, 0xd, 0xa, 0x83, 0xb0, 0x5a, 0x8f, 0xeb, 0x2f, 0x33, 0xe2, 0x7a, 0xf7, 0xf, 0x16, 0xe6, 0x27, 0x9b, 0x59, 0x47, 0xab, 0xb6, 0xdf, 0x7, 0xda, 0xe9, 0x47, 0x3e, 0x8f, 0x56, 0x5b, 0x38, 0xdb, 0xd9, 0x1f, 0x2e, 0xcd, 0x4f, 0xb7, 0xf6, 0xc7, 0xeb, 0xe1, 0xf9, 0x3e, 0x5a, 0xeb, 0x7c, 0xff, 0x67, 0x80, 0xa1, 0x1d, 0x2, 0xc, 0x5b, 0x42, 0x38, 0xec, 0x21, 0x16, 0x7b, 0x8c, 0x67, 0x4, 0x64, 0xaa, 0x7e, 0x7, 0x99, 0x2a, 0x0, 0x99, 0x96, 0xa2, 0x5c, 0x7, 0x15, 0xe5, 0xd2, 0x61, 0xb6, 0x26, 0x40, 0x35, 0xf7, 0x11, 0x98, 0x6d, 0x9b, 0x38, 0x9f, 0x3, 0x40, 0xa3, 0x3d, 0xd2, 0x89, 0x50, 0x6b, 0x17, 0xc7, 0xdd, 0x24, 0xd4, 0x7a, 0x3b, 0x6e, 0x1d, 0xeb, 0xb5, 0x7, 0x9b, 0x15, 0xb4, 0xfb, 0xba, 0x17, 0xb8, 0xdd, 0x1, 0xbc, 0xbf, 0x57, 0xb1, 0xb4, 0xe0, 0xb0, 0x9b, 0x8a, 0x87, 0x3, 0x25, 0x97, 0x57, 0xcd, 0xa7, 0xfe, 0x56, 0xf3, 0xa9, 0xa1, 0xe6, 0xb3, 0x66, 0xd1, 0x29, 0x1a, 0x16, 0x9d, 0x22, 0xa1, 0xe8, 0x24, 0x54, 0xbd, 0x92, 0x34, 0x4d, 0x9e, 0x55, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0xaf, 0xc5, 0x7a, 0x0, 0xb3, 0x43, 0xaa, 0xfb, 0xee, 0x9f, 0xf1, 0x9c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, 0x00 }; +const unsigned char defaultDialogIcon10Name[] = { 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x2d, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x00 }; +const unsigned char defaultDialogIcon10Length[] = { 0x37, 0x32, 0x30, 0x00 }; +const unsigned char defaultDialogIcon10Data[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x40, 0x8, 0x3, 0x0, 0x0, 0x0, 0x9d, 0xb7, 0x81, 0xec, 0x0, 0x0, 0x0, 0x75, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x79, 0x59, 0x7d, 0x58, 0x0, 0x0, 0x0, 0x26, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x7, 0xd2, 0xab, 0x12, 0x22, 0x73, 0x50, 0x7d, 0x25, 0xcb, 0xa7, 0xb8, 0x7c, 0x60, 0x2e, 0xfa, 0x8f, 0xeb, 0xe3, 0xd9, 0xc3, 0x9e, 0x84, 0x69, 0x1d, 0xf1, 0xcd, 0xb2, 0x91, 0xb9, 0xed, 0x49, 0x48, 0x36, 0x35, 0x93, 0xf2, 0x7e, 0x13, 0xd0, 0xd1, 0x0, 0x0, 0x1, 0xe4, 0x49, 0x44, 0x41, 0x54, 0x58, 0xc3, 0xed, 0x57, 0xd9, 0x96, 0xc2, 0x20, 0xc, 0x2d, 0x4c, 0x37, 0xb5, 0x8b, 0xb5, 0xda, 0xd5, 0xba, 0xf, 0xff, 0xff, 0x89, 0x73, 0xa, 0x8c, 0xa9, 0x8, 0xd, 0x1e, 0x4e, 0xdf, 0xcc, 0x63, 0x48, 0xd2, 0xe6, 0xde, 0x24, 0x4, 0xef, 0x2b, 0x8b, 0x8a, 0x7f, 0x8b, 0x9a, 0xba, 0xaa, 0xea, 0x26, 0xba, 0xf9, 0x9f, 0x7b, 0x7, 0xe1, 0x81, 0x4d, 0xe4, 0x10, 0x6, 0x9f, 0x78, 0x93, 0x90, 0xb2, 0x37, 0xa1, 0x21, 0xb1, 0xf5, 0xcf, 0x4a, 0xa6, 0x95, 0x32, 0xb3, 0x72, 0xbf, 0x50, 0x66, 0x14, 0x7a, 0xc1, 0xfd, 0x87, 0xa9, 0xc3, 0x8e, 0x26, 0x9, 0xdd, 0x4d, 0x35, 0x5, 0x86, 0xfc, 0xe9, 0x69, 0xba, 0x4e, 0x73, 0x22, 0x21, 0xc9, 0xd3, 0xf5, 0x53, 0x7d, 0x9a, 0x65, 0x64, 0xb5, 0x97, 0x66, 0x5d, 0xda, 0xbe, 0x9e, 0xb4, 0x71, 0x27, 0x8f, 0xf6, 0xab, 0x19, 0xff, 0xb3, 0xb0, 0xd9, 0xe, 0x9a, 0xcf, 0xf8, 0xc3, 0x56, 0x9c, 0x9e, 0x8d, 0x11, 0x7c, 0xf9, 0xfd, 0x75, 0x60, 0x88, 0x2f, 0x13, 0xd9, 0x9b, 0xb2, 0x90, 0xf9, 0x6f, 0x8c, 0x7c, 0x93, 0x8d, 0xb0, 0x48, 0xf4, 0xc7, 0x85, 0x38, 0x4d, 0xe7, 0x40, 0x4a, 0x67, 0xb8, 0xb8, 0x20, 0xfe, 0x42, 0x62, 0x61, 0x75, 0xd5, 0x1c, 0x51, 0xf1, 0xff, 0x6a, 0x4f, 0xa8, 0x78, 0x88, 0x2c, 0xa8, 0xa6, 0x7e, 0x5, 0x7e, 0x4a, 0xfe, 0x47, 0xc6, 0x8e, 0xa, 0xe, 0x2, 0xc9, 0xec, 0xd, 0x9f, 0x92, 0xf3, 0xa7, 0x7c, 0x2f, 0x1a, 0x95, 0x91, 0xc2, 0x5, 0x67, 0xb3, 0x54, 0x91, 0xe, 0x79, 0xdc, 0x41, 0xfd, 0x5f, 0x5d, 0x56, 0xf, 0x6e, 0x1a, 0xea, 0x10, 0xe8, 0x54, 0x82, 0x7f, 0x46, 0xed, 0x8f, 0x5a, 0x2e, 0x9d, 0x6, 0x85, 0x40, 0x32, 0x80, 0x6, 0x0, 0x26, 0x2, 0x4d, 0x6, 0xad, 0x5d, 0x80, 0x56, 0x93, 0xc3, 0x81, 0x53, 0xe0, 0xd9, 0x5, 0xf0, 0x7a, 0x3e, 0xe5, 0x5e, 0xd2, 0x82, 0xc, 0xb0, 0x0, 0x90, 0xc3, 0x14, 0xb0, 0x1b, 0xd7, 0xe4, 0xb6, 0x1, 0x72, 0x6e, 0x7e, 0x57, 0xf9, 0x66, 0xc4, 0x36, 0x0, 0x61, 0x6a, 0x7d, 0x34, 0x7c, 0x7e, 0x79, 0x48, 0x0, 0x10, 0x3e, 0xe5, 0x9a, 0x89, 0xa2, 0x6, 0x66, 0xb1, 0x0, 0x50, 0x35, 0xf5, 0x44, 0x51, 0x41, 0x97, 0x5b, 0x5, 0x48, 0x46, 0x7d, 0xe5, 0x1c, 0xc0, 0x39, 0x5, 0xc, 0x44, 0x68, 0x26, 0x1c, 0x44, 0xa0, 0x11, 0x6f, 0x67, 0xa0, 0x11, 0x29, 0x24, 0x18, 0x28, 0x48, 0x21, 0x29, 0xa5, 0x8c, 0x8c, 0x34, 0x28, 0xe5, 0xad, 0x8f, 0x34, 0x13, 0x8, 0xde, 0x4c, 0xd0, 0xce, 0x6, 0xc1, 0xdb, 0x39, 0x30, 0xe4, 0x90, 0xf5, 0x7d, 0x66, 0x68, 0xc6, 0x0, 0x19, 0x69, 0x80, 0x56, 0x8e, 0x8f, 0x34, 0x18, 0xaa, 0xba, 0xcb, 0xaa, 0xc0, 0x87, 0x2a, 0x8c, 0xf5, 0x95, 0xfd, 0x58, 0xb7, 0xba, 0x58, 0xc8, 0x58, 0x7, 0x4, 0xb9, 0x58, 0x5c, 0xaf, 0x36, 0xf7, 0xcb, 0x55, 0xbd, 0xde, 0x63, 0xb, 0xff, 0xc2, 0x75, 0xc1, 0x58, 0x64, 0xc5, 0xc1, 0x97, 0xac, 0x7, 0x2c, 0x59, 0x16, 0x6b, 0x5e, 0xfc, 0xb6, 0xe6, 0xfd, 0xc2, 0x9a, 0x67, 0xb7, 0x68, 0xf6, 0x31, 0x2c, 0x9a, 0x71, 0xff, 0x54, 0x27, 0xd8, 0xea, 0x5f, 0x60, 0xab, 0x2e, 0x2a, 0xd7, 0xb9, 0x65, 0xfb, 0xea, 0xbe, 0xee, 0xbb, 0x3f, 0x38, 0x96, 0x7f, 0xf2, 0x0, 0x23, 0xf7, 0xff, 0x47, 0xd7, 0xdd, 0xf7, 0xbe, 0xb2, 0xa4, 0xfc, 0x1, 0xb3, 0x34, 0x7e, 0xa8, 0x9d, 0x48, 0x16, 0xe7, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, 0x00 }; +const unsigned char defaultDialogIcon11Name[] = { 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x2d, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x32, 0x78, 0x00 }; +const unsigned char defaultDialogIcon11Length[] = { 0x31, 0x32, 0x36, 0x32, 0x00 }; +const unsigned char defaultDialogIcon11Data[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x80, 0x8, 0x3, 0x0, 0x0, 0x0, 0xf4, 0xe0, 0x91, 0xf9, 0x0, 0x0, 0x0, 0x93, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7a, 0x79, 0x23, 0x75, 0x0, 0x0, 0x0, 0x30, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xfb, 0x55, 0x42, 0xc, 0xd7, 0xb7, 0x8a, 0x82, 0x7, 0x19, 0xe5, 0xc0, 0x48, 0x2b, 0x68, 0x62, 0x4e, 0xee, 0x94, 0x39, 0x6f, 0x21, 0xe8, 0xe2, 0xb4, 0x90, 0x33, 0xd0, 0xbd, 0x9, 0xcb, 0x97, 0x3c, 0xf, 0xc5, 0xb1, 0xf6, 0xa8, 0x7c, 0x52, 0x26, 0x25, 0x14, 0xc6, 0x61, 0x5d, 0x11, 0x8d, 0xf, 0xdf, 0x6c, 0x0, 0x0, 0x3, 0xda, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xec, 0x97, 0xd9, 0x72, 0xb3, 0x30, 0xc, 0x85, 0xe5, 0x42, 0xc0, 0x6c, 0x9, 0x94, 0xa5, 0x49, 0xc9, 0xbe, 0xa7, 0x49, 0x3a, 0x7e, 0xff, 0xa7, 0xfb, 0xff, 0x8b, 0xce, 0xd8, 0x10, 0x62, 0xd9, 0xc6, 0x74, 0x7a, 0x91, 0xef, 0x5a, 0x4c, 0xe, 0xd2, 0x39, 0x52, 0x80, 0x17, 0x2f, 0x5e, 0xbc, 0x78, 0x61, 0xce, 0x32, 0xbc, 0xd4, 0x4e, 0x96, 0x39, 0xf5, 0x25, 0x5c, 0xc2, 0xef, 0xe2, 0x3a, 0x65, 0xbe, 0x88, 0x98, 0x40, 0xb4, 0xc8, 0x4b, 0xc7, 0x85, 0xdf, 0x20, 0x70, 0xe8, 0x8d, 0xb0, 0x4e, 0xc8, 0x8d, 0x3a, 0x1, 0xc, 0x4b, 0x72, 0x3c, 0x30, 0x29, 0x87, 0x63, 0x2, 0x83, 0x31, 0xf6, 0x3f, 0x98, 0x2, 0x1f, 0xfe, 0x18, 0x86, 0x60, 0xe3, 0x31, 0x65, 0xbc, 0x2, 0x6c, 0xe3, 0xc4, 0x4c, 0x8b, 0xd8, 0xb1, 0xdb, 0xfc, 0x98, 0x69, 0x13, 0xdb, 0x1b, 0x84, 0xeb, 0x13, 0x66, 0x0, 0xf1, 0x2d, 0xe5, 0x32, 0x9b, 0x32, 0x43, 0xa6, 0x19, 0x58, 0xc0, 0x67, 0x3d, 0xf0, 0xfb, 0xb7, 0x7f, 0xf6, 0xb4, 0xc3, 0xd1, 0x6a, 0xbf, 0x3e, 0xa5, 0xe9, 0x69, 0xbd, 0x5f, 0x45, 0x4f, 0x67, 0x34, 0xeb, 0x39, 0x86, 0x6a, 0xc4, 0xba, 0x98, 0xd3, 0x22, 0x84, 0x6, 0x61, 0x41, 0xe7, 0xac, 0x8b, 0x51, 0xd5, 0x2b, 0x7c, 0xef, 0x1d, 0x6f, 0x1e, 0x97, 0xd5, 0x13, 0xb5, 0x65, 0xdc, 0xd1, 0x89, 0xf7, 0x1e, 0x81, 0x9c, 0x10, 0xd6, 0xc6, 0xbb, 0x5f, 0x41, 0xc2, 0xf5, 0xee, 0x3d, 0x2a, 0x9e, 0x80, 0x19, 0x41, 0xce, 0xda, 0xec, 0xa, 0x40, 0xd9, 0xec, 0x58, 0x9b, 0x3c, 0x30, 0xfa, 0xfd, 0xd9, 0xc3, 0x38, 0xcf, 0xa0, 0xc4, 0x79, 0xf4, 0x60, 0x45, 0x13, 0x5, 0x79, 0xfb, 0xc6, 0x4c, 0x2, 0x65, 0xed, 0x93, 0x8f, 0x76, 0xf, 0xc, 0xe6, 0xdf, 0x1a, 0x24, 0x75, 0xb5, 0xd2, 0x4b, 0x5b, 0xf6, 0xd1, 0xf6, 0x81, 0x43, 0x10, 0x2b, 0x6b, 0x6, 0x88, 0x6c, 0x34, 0xf3, 0xdf, 0x7c, 0x7c, 0xf4, 0x5, 0xda, 0x7c, 0x8d, 0x9a, 0xaf, 0x50, 0x69, 0x75, 0xb0, 0xf9, 0xb0, 0xb7, 0x5, 0x3, 0xb6, 0x5e, 0xf3, 0x25, 0x74, 0x66, 0xd8, 0xc, 0xc0, 0x27, 0x18, 0xf2, 0xd9, 0x8c, 0x82, 0xe1, 0xfd, 0x21, 0x29, 0x18, 0x93, 0x12, 0xa3, 0xcb, 0x94, 0x31, 0x91, 0x14, 0x7a, 0x90, 0x32, 0x91, 0x4c, 0xd1, 0x0, 0x53, 0xa4, 0xff, 0xc6, 0x53, 0x98, 0x2e, 0xf5, 0x7, 0xe0, 0x41, 0x4f, 0x3c, 0xed, 0x21, 0x8c, 0x89, 0x68, 0xdd, 0xad, 0xdc, 0xe8, 0xdf, 0x79, 0xfe, 0x8d, 0x94, 0x88, 0x81, 0x22, 0x63, 0xc0, 0x89, 0xc5, 0xf0, 0xca, 0xf3, 0x9f, 0x44, 0xec, 0x3f, 0x51, 0x22, 0xdf, 0x7, 0xe2, 0x4a, 0x89, 0x1, 0xc5, 0x11, 0x5, 0x3b, 0x20, 0xa3, 0x26, 0x3f, 0x65, 0xb5, 0xfa, 0x52, 0x75, 0xb4, 0x1a, 0x40, 0x41, 0xca, 0x9c, 0xfd, 0xb0, 0x2, 0x29, 0x94, 0x71, 0x16, 0xe8, 0x35, 0x17, 0xef, 0x9f, 0xb, 0x32, 0x42, 0x5e, 0x19, 0xca, 0x63, 0x25, 0xde, 0xc6, 0x2, 0x33, 0xad, 0xfa, 0x5, 0x4b, 0x78, 0x65, 0xa2, 0x7e, 0x59, 0x3d, 0x24, 0x2, 0x62, 0x2, 0x90, 0xfb, 0xff, 0xc6, 0x4b, 0xdf, 0x40, 0x4a, 0x20, 0x26, 0x61, 0xac, 0xbc, 0x3, 0xce, 0x60, 0x4b, 0x0, 0x9c, 0x95, 0x77, 0x81, 0x30, 0xad, 0x1d, 0xd8, 0x13, 0x0, 0x37, 0x5e, 0x1b, 0x29, 0x8e, 0x95, 0x15, 0x36, 0x5, 0x6c, 0x98, 0x9a, 0x61, 0x8e, 0x98, 0x59, 0x70, 0x1, 0xb8, 0xb9, 0x8f, 0x12, 0xb3, 0x1c, 0x78, 0xd9, 0xdd, 0x50, 0x0, 0x7e, 0x16, 0xf, 0x81, 0xca, 0x16, 0x24, 0x57, 0xbb, 0x2, 0xae, 0x44, 0x65, 0x1b, 0x52, 0x7c, 0x69, 0xe3, 0x2, 0xf0, 0xd, 0x4b, 0x55, 0xbc, 0x5a, 0xda, 0x16, 0x50, 0x2a, 0xe4, 0xcb, 0x15, 0xda, 0x54, 0xd9, 0x16, 0x50, 0x9, 0xe3, 0x75, 0x71, 0xb, 0xcc, 0xc1, 0xb6, 0x0, 0x98, 0xb, 0x26, 0xc0, 0xbb, 0x44, 0xed, 0xb, 0xa0, 0xf8, 0x7c, 0x73, 0x61, 0xb, 0xd9, 0x17, 0x50, 0xe0, 0x5f, 0x8a, 0xb, 0xe1, 0xbe, 0xda, 0x17, 0x10, 0xe2, 0x7f, 0xa, 0x22, 0x6e, 0x13, 0xb0, 0x2f, 0x0, 0xb8, 0xc5, 0xa7, 0xd0, 0xc9, 0x12, 0x39, 0x18, 0x7d, 0x5, 0x44, 0xbc, 0x7e, 0x89, 0xf5, 0x68, 0x35, 0x84, 0x80, 0x15, 0x36, 0xe1, 0xb, 0x2f, 0xd8, 0xf, 0x21, 0x60, 0xcf, 0xeb, 0x2f, 0xd0, 0x45, 0xcd, 0xb, 0xd6, 0x43, 0x8, 0x58, 0xf3, 0xfa, 0x1a, 0xdb, 0x43, 0xa7, 0x21, 0x4, 0x9c, 0xb0, 0x4d, 0x94, 0xf1, 0x82, 0xb4, 0x97, 0x0, 0xfc, 0x22, 0x67, 0x7f, 0x53, 0xc0, 0xbf, 0xf6, 0xcd, 0x6e, 0x5, 0x41, 0x20, 0xa, 0xc2, 0x7, 0xea, 0x26, 0xa2, 0x5f, 0x22, 0x4b, 0x2a, 0x92, 0xba, 0x2c, 0xf4, 0xfd, 0x9f, 0x2e, 0xc, 0xa, 0x44, 0xf2, 0x6b, 0x99, 0x85, 0xe3, 0x8a, 0x73, 0x6d, 0x37, 0x95, 0xbb, 0x67, 0xbe, 0x33, 0xe3, 0xfe, 0x13, 0xb8, 0xff, 0x9, 0xdd, 0x5f, 0x43, 0xf7, 0x83, 0x8, 0x8e, 0x62, 0xb0, 0x66, 0xc2, 0x51, 0xcc, 0x97, 0x11, 0x9b, 0x53, 0xe9, 0x32, 0xe2, 0xeb, 0x98, 0xed, 0xb9, 0x70, 0x1d, 0xf3, 0x40, 0xc2, 0x80, 0x62, 0x69, 0xc2, 0x40, 0xd2, 0x31, 0x92, 0xa1, 0x16, 0x87, 0xf7, 0x17, 0xba, 0x30, 0x13, 0x46, 0x32, 0x1a, 0x4a, 0x1, 0x52, 0xe5, 0x39, 0x40, 0x2a, 0x18, 0x4a, 0x61, 0x2c, 0x17, 0x44, 0x63, 0x39, 0x1b, 0x13, 0x49, 0x6c, 0x4c, 0xd8, 0x9a, 0x69, 0x62, 0x6b, 0xc6, 0xe6, 0x54, 0x12, 0x9b, 0x53, 0xb6, 0xe7, 0x9a, 0xd8, 0x9e, 0x33, 0xa0, 0x60, 0x6d, 0x8e, 0x59, 0x76, 0x4, 0x6, 0xe, 0x80, 0x42, 0x40, 0x34, 0x66, 0x57, 0xb8, 0xbc, 0x1, 0xd1, 0xa8, 0x90, 0xca, 0x56, 0x0, 0x14, 0x1, 0x52, 0xc9, 0x98, 0xce, 0xb6, 0x5f, 0xa6, 0x6d, 0xa, 0xa6, 0x63, 0x50, 0xc9, 0xcf, 0x2e, 0x43, 0x40, 0x65, 0xbf, 0x51, 0xad, 0xed, 0x1c, 0x60, 0xb5, 0x8e, 0xeb, 0x4f, 0x1, 0xb8, 0xbe, 0xff, 0xb, 0xb, 0xf7, 0x95, 0x4d, 0xd0, 0xd2, 0xaa, 0xac, 0xe7, 0x81, 0xb2, 0xfb, 0x91, 0xe6, 0xd2, 0x2a, 0x85, 0xb5, 0x9d, 0xff, 0xe2, 0xd2, 0x7d, 0x75, 0xeb, 0xbf, 0xbc, 0xf6, 0x5f, 0xdf, 0xc7, 0x9, 0x30, 0x94, 0xad, 0x0, 0x83, 0x6b, 0x84, 0x23, 0xdb, 0xa7, 0x15, 0x62, 0xf1, 0x8f, 0xf1, 0xf8, 0x7, 0x99, 0xe2, 0x46, 0xb9, 0xa2, 0x85, 0xd9, 0xa, 0x43, 0x15, 0x8f, 0xd6, 0xc7, 0xf2, 0x59, 0xc4, 0x38, 0xdf, 0xba, 0x3b, 0xce, 0xb7, 0x86, 0x38, 0x9f, 0x47, 0xa0, 0xb1, 0x48, 0x39, 0xd2, 0xc9, 0xa1, 0xd6, 0xe7, 0xb3, 0x3b, 0xd4, 0x7a, 0x9f, 0xa6, 0x1e, 0xeb, 0xed, 0x41, 0xb0, 0x59, 0x88, 0x76, 0x5f, 0x86, 0x12, 0x6e, 0xaf, 0x35, 0x39, 0x57, 0x41, 0x3a, 0x4f, 0x2c, 0xb6, 0x76, 0x7a, 0xc1, 0x41, 0xaf, 0x78, 0xcc, 0xab, 0x3f, 0x34, 0x6f, 0x57, 0x3c, 0x86, 0x52, 0x72, 0xf9, 0xd4, 0x7c, 0x6e, 0xbf, 0x6a, 0x3e, 0x37, 0xa8, 0xf9, 0xc4, 0x2d, 0x3a, 0x1d, 0x1a, 0x6f, 0x7c, 0x50, 0xd1, 0x29, 0xfd, 0xaa, 0xd7, 0xa8, 0x51, 0xa3, 0x46, 0xd, 0x4a, 0x2f, 0xb9, 0x87, 0x9d, 0xa4, 0x64, 0xb5, 0x51, 0x8a, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, 0x00 }; +const unsigned char *defaultDialogIcons[] = { defaultDialogIcon0Name, defaultDialogIcon0Length, defaultDialogIcon0Data, defaultDialogIcon1Name, defaultDialogIcon1Length, defaultDialogIcon1Data, defaultDialogIcon2Name, defaultDialogIcon2Length, defaultDialogIcon2Data, defaultDialogIcon3Name, defaultDialogIcon3Length, defaultDialogIcon3Data, defaultDialogIcon4Name, defaultDialogIcon4Length, defaultDialogIcon4Data, defaultDialogIcon5Name, defaultDialogIcon5Length, defaultDialogIcon5Data, defaultDialogIcon6Name, defaultDialogIcon6Length, defaultDialogIcon6Data, defaultDialogIcon7Name, defaultDialogIcon7Length, defaultDialogIcon7Data, defaultDialogIcon8Name, defaultDialogIcon8Length, defaultDialogIcon8Data, defaultDialogIcon9Name, defaultDialogIcon9Length, defaultDialogIcon9Data, defaultDialogIcon10Name, defaultDialogIcon10Length, defaultDialogIcon10Data, defaultDialogIcon11Name, defaultDialogIcon11Length, defaultDialogIcon11Data, 0x00 }; diff --git a/v2/internal/ffenestri/effectstructs_windows.h b/v2/internal/ffenestri/effectstructs_windows.h new file mode 100644 index 000000000..8313c4538 --- /dev/null +++ b/v2/internal/ffenestri/effectstructs_windows.h @@ -0,0 +1,64 @@ +// Credit: https://gist.github.com/ysc3839/b08d2bff1c7dacde529bed1d37e85ccf +#pragma once + +typedef enum _WINDOWCOMPOSITIONATTRIB +{ + WCA_UNDEFINED = 0, + WCA_NCRENDERING_ENABLED = 1, + WCA_NCRENDERING_POLICY = 2, + WCA_TRANSITIONS_FORCEDISABLED = 3, + WCA_ALLOW_NCPAINT = 4, + WCA_CAPTION_BUTTON_BOUNDS = 5, + WCA_NONCLIENT_RTL_LAYOUT = 6, + WCA_FORCE_ICONIC_REPRESENTATION = 7, + WCA_EXTENDED_FRAME_BOUNDS = 8, + WCA_HAS_ICONIC_BITMAP = 9, + WCA_THEME_ATTRIBUTES = 10, + WCA_NCRENDERING_EXILED = 11, + WCA_NCADORNMENTINFO = 12, + WCA_EXCLUDED_FROM_LIVEPREVIEW = 13, + WCA_VIDEO_OVERLAY_ACTIVE = 14, + WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 15, + WCA_DISALLOW_PEEK = 16, + WCA_CLOAK = 17, + WCA_CLOAKED = 18, + WCA_ACCENT_POLICY = 19, + WCA_FREEZE_REPRESENTATION = 20, + WCA_EVER_UNCLOAKED = 21, + WCA_VISUAL_OWNER = 22, + WCA_HOLOGRAPHIC = 23, + WCA_EXCLUDED_FROM_DDA = 24, + WCA_PASSIVEUPDATEMODE = 25, + WCA_USEDARKMODECOLORS = 26, + WCA_LAST = 27 +} WINDOWCOMPOSITIONATTRIB; + +typedef struct _WINDOWCOMPOSITIONATTRIBDATA +{ + WINDOWCOMPOSITIONATTRIB Attrib; + PVOID pvData; + SIZE_T cbData; +} WINDOWCOMPOSITIONATTRIBDATA; + +typedef enum _ACCENT_STATE +{ + ACCENT_DISABLED = 0, + ACCENT_ENABLE_GRADIENT = 1, + ACCENT_ENABLE_TRANSPARENTGRADIENT = 2, + ACCENT_ENABLE_BLURBEHIND = 3, + ACCENT_ENABLE_ACRYLICBLURBEHIND = 4, // RS4 1803 + ACCENT_ENABLE_HOSTBACKDROP = 5, // RS5 1809 + ACCENT_INVALID_STATE = 6 +} ACCENT_STATE; + +typedef struct _ACCENT_POLICY +{ + ACCENT_STATE AccentState; + DWORD AccentFlags; + DWORD GradientColor; + DWORD AnimationId; +} ACCENT_POLICY; + +typedef BOOL (WINAPI *pfnGetWindowCompositionAttribute)(HWND, WINDOWCOMPOSITIONATTRIBDATA*); + +typedef BOOL (WINAPI *pfnSetWindowCompositionAttribute)(HWND, WINDOWCOMPOSITIONATTRIBDATA*); \ No newline at end of file diff --git a/v2/internal/ffenestri/ffenestri.go b/v2/internal/ffenestri/ffenestri.go new file mode 100644 index 000000000..15205b727 --- /dev/null +++ b/v2/internal/ffenestri/ffenestri.go @@ -0,0 +1,178 @@ +package ffenestri + +import ( + "runtime" + "strings" + "unsafe" + + "github.com/wailsapp/wails/v2/internal/menumanager" + + "github.com/wailsapp/wails/v2/internal/logger" + "github.com/wailsapp/wails/v2/internal/messagedispatcher" + "github.com/wailsapp/wails/v2/pkg/options" +) + +/* +#cgo linux CFLAGS: -DFFENESTRI_LINUX=1 +#cgo linux pkg-config: gtk+-3.0 webkit2gtk-4.0 + +#cgo darwin CFLAGS: -DFFENESTRI_DARWIN=1 +#cgo darwin LDFLAGS: -framework WebKit -lobjc + +#cgo windows CXXFLAGS: -std=c++11 +#cgo windows,amd64 LDFLAGS: -L./windows/x64 -lWebView2Loader -lgdi32 -lole32 -lShlwapi -luser32 -loleaut32 -ldwmapi + +#include +#include "ffenestri.h" +*/ +import "C" + +// Application is our main application object +type Application struct { + config *options.App + memory []unsafe.Pointer + + // This is the main app pointer + app *C.struct_Application + + // Manages menus + menuManager *menumanager.Manager + + // Logger + logger logger.CustomLogger +} + +func (a *Application) saveMemoryReference(mem unsafe.Pointer) { + a.memory = append(a.memory, mem) +} + +func (a *Application) string2CString(str string) *C.char { + result := C.CString(str) + a.saveMemoryReference(unsafe.Pointer(result)) + return result +} + +func init() { + runtime.LockOSThread() +} + +// NewApplicationWithConfig creates a new application based on the given config +func NewApplicationWithConfig(config *options.App, logger *logger.Logger, menuManager *menumanager.Manager) *Application { + return &Application{ + config: config, + logger: logger.CustomLogger("Ffenestri"), + menuManager: menuManager, + } +} + +func (a *Application) freeMemory() { + for _, mem := range a.memory { + // fmt.Printf("Freeing memory: %+v\n", mem) + C.free(mem) + } +} + +// bool2Cint converts a Go boolean to a C integer +func (a *Application) bool2Cint(value bool) C.int { + if value { + return C.int(1) + } + return C.int(0) +} + +// dispatcher is the interface to send messages to +var dispatcher *messagedispatcher.DispatchClient + +// Dispatcher is what we register out client with +type Dispatcher interface { + RegisterClient(client messagedispatcher.Client) *messagedispatcher.DispatchClient +} + +// DispatchClient is the means for passing messages to the backend +type DispatchClient interface { + SendMessage(string) +} + +func intToColour(colour int) (C.int, C.int, C.int, C.int) { + var alpha = C.int(colour & 0xFF) + var blue = C.int((colour >> 8) & 0xFF) + var green = C.int((colour >> 16) & 0xFF) + var red = C.int((colour >> 24) & 0xFF) + return red, green, blue, alpha +} + +// Run the application +func (a *Application) Run(incomingDispatcher Dispatcher, bindings string, debug bool) error { + title := a.string2CString(a.config.Title) + width := C.int(a.config.Width) + height := C.int(a.config.Height) + resizable := a.bool2Cint(!a.config.DisableResize) + devtools := a.bool2Cint(a.config.DevTools) + fullscreen := a.bool2Cint(a.config.Fullscreen) + startHidden := a.bool2Cint(a.config.StartHidden) + logLevel := C.int(a.config.LogLevel) + hideWindowOnClose := a.bool2Cint(a.config.HideWindowOnClose) + app := C.NewApplication(title, width, height, resizable, devtools, fullscreen, startHidden, logLevel, hideWindowOnClose) + + // Save app reference + a.app = (*C.struct_Application)(app) + + // Set Min Window Size + minWidth := C.int(a.config.MinWidth) + minHeight := C.int(a.config.MinHeight) + C.SetMinWindowSize(a.app, minWidth, minHeight) + + // Set Max Window Size + maxWidth := C.int(a.config.MaxWidth) + maxHeight := C.int(a.config.MaxHeight) + C.SetMaxWindowSize(a.app, maxWidth, maxHeight) + + // Set debug if needed + C.SetDebug(app, a.bool2Cint(debug)) + + if a.config.Frameless { + C.DisableFrame(a.app) + } + + if a.config.RGBA != 0 { + r, g, b, alpha := intToColour(a.config.RGBA) + C.SetColour(a.app, r, g, b, alpha) + } + + // Escape bindings so C doesn't freak out + bindings = strings.ReplaceAll(bindings, `"`, `\"`) + + // Set bindings + C.SetBindings(app, a.string2CString(bindings)) + + // save the dispatcher in a package variable so that the C callbacks + // can access it + dispatcher = incomingDispatcher.RegisterClient(newClient(a)) + + // Process platform settings + err := a.processPlatformSettings() + if err != nil { + return err + } + + // Check we could initialise the application + if app != nil { + // Yes - Save memory reference and run app, cleaning up afterwards + a.saveMemoryReference(unsafe.Pointer(app)) + C.Run(app, 0, nil) + } else { + // Oh no! We couldn't initialise the application + a.logger.Fatal("Cannot initialise Application.") + } + //println("\n\n\n\n\n\nhererererer\n\n\n\n") + a.freeMemory() + return nil +} + +// messageFromWindowCallback is called by any messages sent in +// webkit to window.external.invoke. It relays the message on to +// the dispatcher. +//export messageFromWindowCallback +func messageFromWindowCallback(data *C.char) { + dispatcher.DispatchMessage(C.GoString(data)) +} diff --git a/v2/internal/ffenestri/ffenestri.h b/v2/internal/ffenestri/ffenestri.h new file mode 100644 index 000000000..1bbc9d907 --- /dev/null +++ b/v2/internal/ffenestri/ffenestri.h @@ -0,0 +1,56 @@ +#ifndef __FFENESTRI_H__ +#define __FFENESTRI_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +struct Application; + +extern struct Application *NewApplication(const char *title, int width, int height, int resizable, int devtools, int fullscreen, int startHidden, int logLevel, int hideWindowOnClose); +extern void SetMinWindowSize(struct Application*, int minWidth, int minHeight); +extern void SetMaxWindowSize(struct Application*, int maxWidth, int maxHeight); +extern void Run(struct Application*, int argc, char **argv); +extern void DestroyApplication(struct Application*); +extern void SetDebug(struct Application*, int flag); +extern void SetBindings(struct Application*, const char *bindings); +extern void ExecJS(struct Application*, const char *script); +extern void Hide(struct Application*); +extern void Show(struct Application*); +extern void Center(struct Application*); +extern void Maximise(struct Application*); +extern void Unmaximise(struct Application*); +extern void ToggleMaximise(struct Application*); +extern void Minimise(struct Application*); +extern void Unminimise(struct Application*); +extern void ToggleMinimise(struct Application*); +extern void SetColour(struct Application*, int red, int green, int blue, int alpha); +extern void SetSize(struct Application*, int width, int height); +extern void SetPosition(struct Application*, int x, int y); +extern void Quit(struct Application*); +extern void SetTitle(struct Application*, const char *title); +extern void Fullscreen(struct Application*); +extern void UnFullscreen(struct Application*); +extern void ToggleFullscreen(struct Application*); +extern void DisableFrame(struct Application*); +extern void OpenDialog(struct Application*, char *callbackID, char *title, char *filters, char *defaultFilename, char *defaultDir, int allowFiles, int allowDirs, int allowMultiple, int showHiddenFiles, int canCreateDirectories, int resolvesAliases, int treatPackagesAsDirectories); +extern void SaveDialog(struct Application*, char *callbackID, char *title, char *filters, char *defaultFilename, char *defaultDir, int showHiddenFiles, int canCreateDirectories, int treatPackagesAsDirectories); +extern void MessageDialog(struct Application*, char *callbackID, char *type, char *title, char *message, char *icon, char *button1, char *button2, char *button3, char *button4, char *defaultButton, char *cancelButton); +extern void DarkModeEnabled(struct Application*, char *callbackID); +extern void SetApplicationMenu(struct Application*, const char *); +extern void AddTrayMenu(struct Application*, const char *menuTrayJSON); +extern void SetTrayMenu(struct Application*, const char *menuTrayJSON); +extern void DeleteTrayMenuByID(struct Application*, const char *id); +extern void UpdateTrayMenuLabel(struct Application*, const char* JSON); +extern void AddContextMenu(struct Application*, char *contextMenuJSON); +extern void UpdateContextMenu(struct Application*, char *contextMenuJSON); +extern void WebviewIsTransparent(struct Application*); +extern void WindowIsTranslucent(struct Application*); +extern void* GetWindowHandle(struct Application*); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/v2/internal/ffenestri/ffenestri_client.go b/v2/internal/ffenestri/ffenestri_client.go new file mode 100644 index 000000000..05af2cdf2 --- /dev/null +++ b/v2/internal/ffenestri/ffenestri_client.go @@ -0,0 +1,272 @@ +// +build !windows + +package ffenestri + +/* +#include "ffenestri.h" +*/ +import "C" + +import ( + goruntime "runtime" + "strconv" + "strings" + + "github.com/wailsapp/wails/v2/pkg/runtime" + + "github.com/wailsapp/wails/v2/internal/logger" +) + +// Client is our implementation of messageDispatcher.Client +type Client struct { + app *Application + logger logger.CustomLogger +} + +func newClient(app *Application) *Client { + return &Client{ + app: app, + logger: app.logger, + } +} + +// Quit the application +func (c *Client) Quit() { + c.app.logger.Trace("Got shutdown message") + C.Quit(c.app.app) +} + +// NotifyEvent will pass on the event message to the frontend +func (c *Client) NotifyEvent(message string) { + eventMessage := `window.wails._.Notify(` + strconv.Quote(message) + `);` + c.app.logger.Trace("eventMessage = %+v", eventMessage) + C.ExecJS(c.app.app, c.app.string2CString(eventMessage)) +} + +// CallResult contains the result of the call from JS +func (c *Client) CallResult(message string) { + callbackMessage := `window.wails._.Callback(` + strconv.Quote(message) + `);` + c.app.logger.Trace("callbackMessage = %+v", callbackMessage) + C.ExecJS(c.app.app, c.app.string2CString(callbackMessage)) +} + +// WindowSetTitle sets the window title to the given string +func (c *Client) WindowSetTitle(title string) { + C.SetTitle(c.app.app, c.app.string2CString(title)) +} + +// WindowFullscreen will set the window to be fullscreen +func (c *Client) WindowFullscreen() { + C.Fullscreen(c.app.app) +} + +// WindowUnFullscreen will unfullscreen the window +func (c *Client) WindowUnFullscreen() { + C.UnFullscreen(c.app.app) +} + +// WindowShow will show the window +func (c *Client) WindowShow() { + C.Show(c.app.app) +} + +// WindowHide will hide the window +func (c *Client) WindowHide() { + C.Hide(c.app.app) +} + +// WindowCenter will hide the window +func (c *Client) WindowCenter() { + C.Center(c.app.app) +} + +// WindowMaximise will maximise the window +func (c *Client) WindowMaximise() { + C.Maximise(c.app.app) +} + +// WindowMinimise will minimise the window +func (c *Client) WindowMinimise() { + C.Minimise(c.app.app) +} + +// WindowUnmaximise will unmaximise the window +func (c *Client) WindowUnmaximise() { + C.Unmaximise(c.app.app) +} + +// WindowUnminimise will unminimise the window +func (c *Client) WindowUnminimise() { + C.Unminimise(c.app.app) +} + +// WindowPosition will position the window to x,y on the +// monitor that the window is mostly on +func (c *Client) WindowPosition(x int, y int) { + C.SetPosition(c.app.app, C.int(x), C.int(y)) +} + +// WindowSize will resize the window to the given +// width and height +func (c *Client) WindowSize(width int, height int) { + C.SetSize(c.app.app, C.int(width), C.int(height)) +} + +func (c *Client) WindowSetMinSize(width int, height int) { + C.SetMinWindowSize(c.app.app, C.int(width), C.int(height)) +} + +func (c *Client) WindowSetMaxSize(width int, height int) { + C.SetMaxWindowSize(c.app.app, C.int(width), C.int(height)) +} + +// WindowSetColour sets the window colour +func (c *Client) WindowSetColour(colour int) { + r, g, b, a := intToColour(colour) + C.SetColour(c.app.app, r, g, b, a) +} + +// OpenFileDialog will open a dialog with the given title and filter +func (c *Client) OpenFileDialog(dialogOptions runtime.OpenDialogOptions, callbackID string) { + filters := []string{} + if goruntime.GOOS == "darwin" { + for _, filter := range dialogOptions.Filters { + filters = append(filters, strings.Split(filter.Pattern, ",")...) + } + } + C.OpenDialog(c.app.app, + c.app.string2CString(callbackID), + c.app.string2CString(dialogOptions.Title), + c.app.string2CString(strings.Join(filters, ";")), + c.app.string2CString(dialogOptions.DefaultFilename), + c.app.string2CString(dialogOptions.DefaultDirectory), + c.app.bool2Cint(dialogOptions.AllowFiles), + c.app.bool2Cint(dialogOptions.AllowDirectories), + c.app.bool2Cint(false), + c.app.bool2Cint(dialogOptions.ShowHiddenFiles), + c.app.bool2Cint(dialogOptions.CanCreateDirectories), + c.app.bool2Cint(dialogOptions.ResolvesAliases), + c.app.bool2Cint(dialogOptions.TreatPackagesAsDirectories), + ) +} + +// OpenDirectoryDialog will open a dialog with the given title and filter +func (c *Client) OpenDirectoryDialog(dialogOptions runtime.OpenDialogOptions, callbackID string) { + filters := []string{} + if goruntime.GOOS == "darwin" { + for _, filter := range dialogOptions.Filters { + filters = append(filters, strings.Split(filter.Pattern, ",")...) + } + } + C.OpenDialog(c.app.app, + c.app.string2CString(callbackID), + c.app.string2CString(dialogOptions.Title), + c.app.string2CString(strings.Join(filters, ";")), + c.app.string2CString(dialogOptions.DefaultFilename), + c.app.string2CString(dialogOptions.DefaultDirectory), + c.app.bool2Cint(false), // Files + c.app.bool2Cint(true), // Directories + c.app.bool2Cint(false), // Multiple + c.app.bool2Cint(dialogOptions.ShowHiddenFiles), + c.app.bool2Cint(dialogOptions.CanCreateDirectories), + c.app.bool2Cint(dialogOptions.ResolvesAliases), + c.app.bool2Cint(dialogOptions.TreatPackagesAsDirectories), + ) +} + +// OpenMultipleFilesDialog will open a dialog with the given title and filter +func (c *Client) OpenMultipleFilesDialog(dialogOptions runtime.OpenDialogOptions, callbackID string) { + filters := []string{} + if goruntime.GOOS == "darwin" { + for _, filter := range dialogOptions.Filters { + filters = append(filters, strings.Split(filter.Pattern, ",")...) + } + } + C.OpenDialog(c.app.app, + c.app.string2CString(callbackID), + c.app.string2CString(dialogOptions.Title), + c.app.string2CString(strings.Join(filters, ";")), + c.app.string2CString(dialogOptions.DefaultFilename), + c.app.string2CString(dialogOptions.DefaultDirectory), + c.app.bool2Cint(dialogOptions.AllowFiles), + c.app.bool2Cint(dialogOptions.AllowDirectories), + c.app.bool2Cint(true), + c.app.bool2Cint(dialogOptions.ShowHiddenFiles), + c.app.bool2Cint(dialogOptions.CanCreateDirectories), + c.app.bool2Cint(dialogOptions.ResolvesAliases), + c.app.bool2Cint(dialogOptions.TreatPackagesAsDirectories), + ) +} + +// SaveDialog will open a dialog with the given title and filter +func (c *Client) SaveDialog(dialogOptions *runtime.SaveDialogOptions, callbackID string) { + filters := []string{} + if goruntime.GOOS == "darwin" { + for _, filter := range dialogOptions.Filters { + filters = append(filters, strings.Split(filter.Pattern, ",")...) + } + } + C.SaveDialog(c.app.app, + c.app.string2CString(callbackID), + c.app.string2CString(dialogOptions.Title), + c.app.string2CString(strings.Join(filters, ";")), + c.app.string2CString(dialogOptions.DefaultFilename), + c.app.string2CString(dialogOptions.DefaultDirectory), + c.app.bool2Cint(dialogOptions.ShowHiddenFiles), + c.app.bool2Cint(dialogOptions.CanCreateDirectories), + c.app.bool2Cint(dialogOptions.TreatPackagesAsDirectories), + ) +} + +// MessageDialog will open a message dialog with the given options +func (c *Client) MessageDialog(dialogOptions runtime.MessageDialogOptions, callbackID string) { + + // Sanity check button length + if len(dialogOptions.Buttons) > 4 { + c.app.logger.Error("Given %d message dialog buttons. Maximum is 4", len(dialogOptions.Buttons)) + return + } + + // Process buttons + buttons := []string{"", "", "", ""} + for i, button := range dialogOptions.Buttons { + buttons[i] = button + } + + C.MessageDialog(c.app.app, + c.app.string2CString(callbackID), + c.app.string2CString(string(dialogOptions.Type)), + c.app.string2CString(dialogOptions.Title), + c.app.string2CString(dialogOptions.Message), + c.app.string2CString(dialogOptions.Icon), + c.app.string2CString(buttons[0]), + c.app.string2CString(buttons[1]), + c.app.string2CString(buttons[2]), + c.app.string2CString(buttons[3]), + c.app.string2CString(dialogOptions.DefaultButton), + c.app.string2CString(dialogOptions.CancelButton)) +} + +func (c *Client) DarkModeEnabled(callbackID string) { + C.DarkModeEnabled(c.app.app, c.app.string2CString(callbackID)) +} + +func (c *Client) SetApplicationMenu(applicationMenuJSON string) { + C.SetApplicationMenu(c.app.app, c.app.string2CString(applicationMenuJSON)) +} + +func (c *Client) SetTrayMenu(trayMenuJSON string) { + C.SetTrayMenu(c.app.app, c.app.string2CString(trayMenuJSON)) +} + +func (c *Client) UpdateTrayMenuLabel(JSON string) { + C.UpdateTrayMenuLabel(c.app.app, c.app.string2CString(JSON)) +} + +func (c *Client) UpdateContextMenu(contextMenuJSON string) { + C.UpdateContextMenu(c.app.app, c.app.string2CString(contextMenuJSON)) +} + +func (c *Client) DeleteTrayMenuByID(id string) { + C.DeleteTrayMenuByID(c.app.app, c.app.string2CString(id)) +} diff --git a/v2/internal/ffenestri/ffenestri_client_windows.go b/v2/internal/ffenestri/ffenestri_client_windows.go new file mode 100644 index 000000000..542fbf79a --- /dev/null +++ b/v2/internal/ffenestri/ffenestri_client_windows.go @@ -0,0 +1,308 @@ +// +build windows + +package ffenestri + +/* +#include "ffenestri.h" +*/ +import "C" + +import ( + "encoding/json" + "github.com/leaanthony/go-common-file-dialog/cfd" + "github.com/wailsapp/wails/v2/pkg/runtime" + "golang.org/x/sys/windows" + "log" + "strconv" + "syscall" + + "github.com/wailsapp/wails/v2/internal/logger" +) + +// Client is our implementation of messageDispatcher.Client +type Client struct { + app *Application + logger logger.CustomLogger +} + +func newClient(app *Application) *Client { + return &Client{ + app: app, + logger: app.logger, + } +} + +// Quit the application +func (c *Client) Quit() { + c.app.logger.Trace("Got shutdown message") + C.Quit(c.app.app) +} + +// NotifyEvent will pass on the event message to the frontend +func (c *Client) NotifyEvent(message string) { + eventMessage := `window.wails._.Notify(` + strconv.Quote(message) + `);` + c.app.logger.Trace("eventMessage = %+v", eventMessage) + C.ExecJS(c.app.app, c.app.string2CString(eventMessage)) +} + +// CallResult contains the result of the call from JS +func (c *Client) CallResult(message string) { + callbackMessage := `window.wails._.Callback(` + strconv.Quote(message) + `);` + c.app.logger.Trace("callbackMessage = %+v", callbackMessage) + C.ExecJS(c.app.app, c.app.string2CString(callbackMessage)) +} + +// WindowSetTitle sets the window title to the given string +func (c *Client) WindowSetTitle(title string) { + C.SetTitle(c.app.app, c.app.string2CString(title)) +} + +// WindowFullscreen will set the window to be fullscreen +func (c *Client) WindowFullscreen() { + C.Fullscreen(c.app.app) +} + +// WindowUnFullscreen will unfullscreen the window +func (c *Client) WindowUnFullscreen() { + C.UnFullscreen(c.app.app) +} + +// WindowShow will show the window +func (c *Client) WindowShow() { + C.Show(c.app.app) +} + +// WindowHide will hide the window +func (c *Client) WindowHide() { + C.Hide(c.app.app) +} + +// WindowCenter will hide the window +func (c *Client) WindowCenter() { + C.Center(c.app.app) +} + +// WindowMaximise will maximise the window +func (c *Client) WindowMaximise() { + C.Maximise(c.app.app) +} + +// WindowMinimise will minimise the window +func (c *Client) WindowMinimise() { + C.Minimise(c.app.app) +} + +// WindowUnmaximise will unmaximise the window +func (c *Client) WindowUnmaximise() { + C.Unmaximise(c.app.app) +} + +// WindowUnminimise will unminimise the window +func (c *Client) WindowUnminimise() { + C.Unminimise(c.app.app) +} + +// WindowPosition will position the window to x,y on the +// monitor that the window is mostly on +func (c *Client) WindowPosition(x int, y int) { + C.SetPosition(c.app.app, C.int(x), C.int(y)) +} + +// WindowSize will resize the window to the given +// width and height +func (c *Client) WindowSize(width int, height int) { + C.SetSize(c.app.app, C.int(width), C.int(height)) +} + +// WindowSetMinSize sets the minimum window size +func (c *Client) WindowSetMinSize(width int, height int) { + C.SetMinWindowSize(c.app.app, C.int(width), C.int(height)) +} + +// WindowSetMaxSize sets the maximum window size +func (c *Client) WindowSetMaxSize(width int, height int) { + C.SetMaxWindowSize(c.app.app, C.int(width), C.int(height)) +} + +// WindowSetColour sets the window colour +func (c *Client) WindowSetColour(colour int) { + r, g, b, a := intToColour(colour) + C.SetColour(c.app.app, r, g, b, a) +} + +func convertFilters(filters []runtime.FileFilter) []cfd.FileFilter { + var result []cfd.FileFilter + for _, filter := range filters { + result = append(result, cfd.FileFilter(filter)) + } + return result +} + +// OpenFileDialog will open a dialog with the given title and filter +func (c *Client) OpenFileDialog(options runtime.OpenDialogOptions, callbackID string) { + config := cfd.DialogConfig{ + Folder: options.DefaultDirectory, + FileFilters: convertFilters(options.Filters), + FileName: options.DefaultFilename, + } + thisdialog, err := cfd.NewOpenFileDialog(config) + if err != nil { + log.Fatal(err) + } + thisdialog.SetParentWindowHandle(uintptr(C.GetWindowHandle(c.app.app))) + defer func(thisdialog cfd.OpenFileDialog) { + err := thisdialog.Release() + if err != nil { + log.Fatal(err) + } + }(thisdialog) + result, err := thisdialog.ShowAndGetResult() + if err != nil && err != cfd.ErrorCancelled { + log.Fatal(err) + } + + dispatcher.DispatchMessage("DO" + callbackID + "|" + result) +} + +// OpenDirectoryDialog will open a dialog with the given title and filter +func (c *Client) OpenDirectoryDialog(dialogOptions runtime.OpenDialogOptions, callbackID string) { + config := cfd.DialogConfig{ + Title: dialogOptions.Title, + Role: "PickFolder", + Folder: dialogOptions.DefaultDirectory, + } + thisDialog, err := cfd.NewSelectFolderDialog(config) + if err != nil { + log.Fatal() + } + thisDialog.SetParentWindowHandle(uintptr(C.GetWindowHandle(c.app.app))) + defer func(thisDialog cfd.SelectFolderDialog) { + err := thisDialog.Release() + if err != nil { + log.Fatal(err) + } + }(thisDialog) + result, err := thisDialog.ShowAndGetResult() + if err != nil && err != cfd.ErrorCancelled { + log.Fatal(err) + } + dispatcher.DispatchMessage("DD" + callbackID + "|" + result) +} + +// OpenMultipleFilesDialog will open a dialog with the given title and filter +func (c *Client) OpenMultipleFilesDialog(dialogOptions runtime.OpenDialogOptions, callbackID string) { + config := cfd.DialogConfig{ + Title: dialogOptions.Title, + Role: "OpenMultipleFiles", + FileFilters: convertFilters(dialogOptions.Filters), + FileName: dialogOptions.DefaultFilename, + Folder: dialogOptions.DefaultDirectory, + } + thisdialog, err := cfd.NewOpenMultipleFilesDialog(config) + if err != nil { + log.Fatal(err) + } + thisdialog.SetParentWindowHandle(uintptr(C.GetWindowHandle(c.app.app))) + defer func(thisdialog cfd.OpenMultipleFilesDialog) { + err := thisdialog.Release() + if err != nil { + log.Fatal(err) + } + }(thisdialog) + result, err := thisdialog.ShowAndGetResults() + if err != nil && err != cfd.ErrorCancelled { + log.Fatal(err) + } + resultJSON, err := json.Marshal(result) + if err != nil { + log.Fatal(err) + } + dispatcher.DispatchMessage("D*" + callbackID + "|" + string(resultJSON)) +} + +// SaveDialog will open a dialog with the given title and filter +func (c *Client) SaveDialog(dialogOptions runtime.SaveDialogOptions, callbackID string) { + saveDialog, err := cfd.NewSaveFileDialog(cfd.DialogConfig{ + Title: dialogOptions.Title, + Role: "SaveFile", + FileFilters: convertFilters(dialogOptions.Filters), + FileName: dialogOptions.DefaultFilename, + Folder: dialogOptions.DefaultDirectory, + }) + if err != nil { + log.Fatal(err) + } + saveDialog.SetParentWindowHandle(uintptr(C.GetWindowHandle(c.app.app))) + err = saveDialog.Show() + if err != nil { + log.Fatal(err) + } + result, err := saveDialog.GetResult() + if err != nil && err != cfd.ErrorCancelled { + log.Fatal(err) + } + dispatcher.DispatchMessage("DS" + callbackID + "|" + result) +} + +// MessageDialog will open a message dialog with the given options +func (c *Client) MessageDialog(options runtime.MessageDialogOptions, callbackID string) { + + title, err := syscall.UTF16PtrFromString(options.Title) + if err != nil { + log.Fatal(err) + } + message, err := syscall.UTF16PtrFromString(options.Message) + if err != nil { + log.Fatal(err) + } + var flags uint32 + switch options.Type { + case runtime.InfoDialog: + flags = windows.MB_OK | windows.MB_ICONINFORMATION + case runtime.ErrorDialog: + flags = windows.MB_ICONERROR | windows.MB_OK + case runtime.QuestionDialog: + flags = windows.MB_YESNO + case runtime.WarningDialog: + flags = windows.MB_OK | windows.MB_ICONWARNING + } + + button, _ := windows.MessageBox(windows.HWND(C.GetWindowHandle(c.app.app)), message, title, flags|windows.MB_SYSTEMMODAL) + // This maps MessageBox return values to strings + responses := []string{"", "Ok", "Cancel", "Abort", "Retry", "Ignore", "Yes", "No", "", "", "Try Again", "Continue"} + result := "Error" + if int(button) < len(responses) { + result = responses[button] + } + dispatcher.DispatchMessage("DM" + callbackID + "|" + result) +} + +// DarkModeEnabled sets the application to use dark mode +func (c *Client) DarkModeEnabled(callbackID string) { + C.DarkModeEnabled(c.app.app, c.app.string2CString(callbackID)) +} + +// SetApplicationMenu sets the application menu +func (c *Client) SetApplicationMenu(_ string) { + c.updateApplicationMenu() +} + +// SetTrayMenu sets the tray menu +func (c *Client) SetTrayMenu(trayMenuJSON string) { + C.SetTrayMenu(c.app.app, c.app.string2CString(trayMenuJSON)) +} + +// UpdateTrayMenuLabel updates a tray menu label +func (c *Client) UpdateTrayMenuLabel(JSON string) { + C.UpdateTrayMenuLabel(c.app.app, c.app.string2CString(JSON)) +} + +// UpdateContextMenu will update the current context menu +func (c *Client) UpdateContextMenu(contextMenuJSON string) { + C.UpdateContextMenu(c.app.app, c.app.string2CString(contextMenuJSON)) +} + +// DeleteTrayMenuByID will remove a tray menu based on the given id +func (c *Client) DeleteTrayMenuByID(id string) { + C.DeleteTrayMenuByID(c.app.app, c.app.string2CString(id)) +} diff --git a/v2/internal/ffenestri/ffenestri_darwin.c b/v2/internal/ffenestri/ffenestri_darwin.c new file mode 100644 index 000000000..1bdb49176 --- /dev/null +++ b/v2/internal/ffenestri/ffenestri_darwin.c @@ -0,0 +1,1817 @@ + +#ifdef FFENESTRI_DARWIN + +#include "ffenestri_darwin.h" +#include "menu_darwin.h" +#include "contextmenus_darwin.h" +#include "traymenustore_darwin.h" +#include "traymenu_darwin.h" + +// References to assets +#include "assets.h" +extern const unsigned char runtime; + +// Dialog icons +extern const unsigned char *defaultDialogIcons[]; +#include "userdialogicons.h" + +// MAIN DEBUG FLAG +int debug; + +// A cache for all our dialog icons +struct hashmap_s dialogIconCache; + +// Dispatch Method +typedef void (^dispatchMethod)(void); + +// Message Dialog +void MessageDialog(struct Application *app, char *callbackID, char *type, char *title, char *message, char *icon, char *button1, char *button2, char *button3, char *button4, char *defaultButton, char *cancelButton); + +TrayMenuStore *TrayMenuStoreSingleton; + +// dispatch will execute the given `func` pointer +void dispatch(dispatchMethod func) { + dispatch_async(dispatch_get_main_queue(), func); +} +// yes command simply returns YES! +BOOL yes(id self, SEL cmd) +{ + return YES; +} + +// no command simply returns NO! +BOOL no(id self, SEL cmd) +{ + return NO; +} + +// Prints a hashmap entry +int hashmap_log(void *const context, struct hashmap_element_s *const e) { + printf("%s: %p ", (char*)e->key, e->data); + return 0; +} + +void filelog(const char *message) { + FILE *fp = fopen("/tmp/wailslog.txt", "ab"); + if (fp != NULL) + { + fputs(message, fp); + fclose(fp); + } +} + +// The delegate class for tray menus +Class trayMenuDelegateClass; + +// Utility function to visualise a hashmap +void dumpHashmap(const char *name, struct hashmap_s *hashmap) { + printf("%s = { ", name); + if (0!=hashmap_iterate_pairs(hashmap, hashmap_log, NULL)) { + fprintf(stderr, "Failed to dump hashmap entries\n"); + } + printf("}\n"); +} + +extern void messageFromWindowCallback(const char *); +typedef void (*ffenestriCallback)(const char *); + +void HideMouse() { + msg_reg(c("NSCursor"), s("hide")); +} + +void ShowMouse() { + msg_reg(c("NSCursor"), s("unhide")); +} + +OSVersion getOSVersion() { + id processInfo = msg_reg(c("NSProcessInfo"), s("processInfo")); + return GET_OSVERSION(processInfo); +} + +struct Application { + + // Cocoa data + id application; + id delegate; + id windowDelegate; + id mainWindow; + id wkwebview; + id manager; + id config; + id mouseEvent; + id mouseDownMonitor; + id mouseUpMonitor; + int activationPolicy; + id pool; + + // Window Data + const char *title; + int width; + int height; + int minWidth; + int minHeight; + int maxWidth; + int maxHeight; + int resizable; + int devtools; + int fullscreen; + CGFloat red; + CGFloat green; + CGFloat blue; + CGFloat alpha; + int webviewIsTranparent; + const char *appearance; + int decorations; + int logLevel; + int hideWindowOnClose; + + // Features + int frame; + int startHidden; + int maximised; + int titlebarAppearsTransparent; + int hideTitle; + int hideTitleBar; + int fullSizeContent; + int useToolBar; + int hideToolbarSeparator; + int WindowIsTranslucent; + int hasURLHandlers; + const char *startupURL; + + // Menu + Menu *applicationMenu; + + // Context Menus + ContextMenuStore *contextMenuStore; + + // Callback + ffenestriCallback sendMessageToBackend; + + // Bindings + const char *bindings; + + // shutting down flag + bool shuttingDown; + + // Running flag + bool running; + +}; + +// Debug works like sprintf but mutes if the global debug flag is true +// Credit: https://stackoverflow.com/a/20639708 + +#define MAXMESSAGE 1024*10 +char logbuffer[MAXMESSAGE]; + +void Debug(struct Application *app, const char *message, ... ) { + if ( debug ) { + const char *temp = concat("LTFfenestri (C) | ", message); + va_list args; + va_start(args, message); + vsnprintf(logbuffer, MAXMESSAGE, temp, args); + app->sendMessageToBackend(&logbuffer[0]); + MEMFREE(temp); + va_end(args); + } +} + +void Error(struct Application *app, const char *message, ... ) { + const char *temp = concat("LEFfenestri (C) | ", message); + va_list args; + va_start(args, message); + vsnprintf(logbuffer, MAXMESSAGE, temp, args); + app->sendMessageToBackend(&logbuffer[0]); + MEMFREE(temp); + va_end(args); +} + +void Fatal(struct Application *app, const char *message, ... ) { + const char *temp = concat("LFFfenestri (C) | ", message); + va_list args; + va_start(args, message); + vsnprintf(logbuffer, MAXMESSAGE, temp, args); + app->sendMessageToBackend(&logbuffer[0]); + MEMFREE(temp); + va_end(args); +} + +// Requires NSString input EG lookupStringConstant(str("NSFontAttributeName")) +void* lookupStringConstant(id constantName) { + void ** dataPtr = CFBundleGetDataPointerForName(CFBundleGetBundleWithIdentifier((CFStringRef)str("com.apple.AppKit")), (CFStringRef) constantName); + return (dataPtr ? *dataPtr : nil); +} + +bool isRetina(struct Application *app) { + CGFloat scale = GET_BACKINGSCALEFACTOR(app->mainWindow); + if( (int)scale == 1 ) { + return false; + } + return true; +} + +void TitlebarAppearsTransparent(struct Application* app) { + app->titlebarAppearsTransparent = 1; +} + +void HideTitle(struct Application *app) { + app->hideTitle = 1; +} + +void HideTitleBar(struct Application *app) { + app->hideTitleBar = 1; +} + +void HideToolbarSeparator(struct Application *app) { + app->hideToolbarSeparator = 1; +} + +void UseToolbar(struct Application *app) { + app->useToolBar = 1; +} + +// WebviewIsTransparent will make the webview transparent +// revealing the Cocoa window underneath +void WebviewIsTransparent(struct Application *app) { + app->webviewIsTranparent = 1; +} + +// SetAppearance will set the window's Appearance to the +// given value +void SetAppearance(struct Application *app, const char *appearance) { + app->appearance = appearance; +} + + +void applyWindowColour(struct Application *app) { + // Apply the colour only if the window has been created + if( app->mainWindow != NULL ) { + ON_MAIN_THREAD( + id colour = ((id(*)(id, SEL, CGFloat, CGFloat, CGFloat, CGFloat))objc_msgSend)(c("NSColor"), s("colorWithCalibratedRed:green:blue:alpha:"), + (CGFloat)app->red / (CGFloat)255.0, + (CGFloat)app->green / (CGFloat)255.0, + (CGFloat)app->blue / (CGFloat)255.0, + (CGFloat)app->alpha / (CGFloat)255.0); + msg_id(app->mainWindow, s("setBackgroundColor:"), colour); + ); + } +} + +void SetColour(struct Application *app, int red, int green, int blue, int alpha) { + // Guard against calling during shutdown + if( app->shuttingDown ) return; + + app->red = (CGFloat)red; + app->green = (CGFloat)green; + app->blue = (CGFloat)blue; + app->alpha = (CGFloat)alpha; + + applyWindowColour(app); +} + +void FullSizeContent(struct Application *app) { + app->fullSizeContent = 1; +} + +void Hide(struct Application *app) { + // Guard against calling during shutdown + if( app->shuttingDown ) return; + + ON_MAIN_THREAD( + msg_reg(app->mainWindow, s("orderOut:")); + ); +} + +void Show(struct Application *app) { + // Guard against calling during shutdown + if( app->shuttingDown ) return; + + ON_MAIN_THREAD( + msg_id(app->mainWindow, s("makeKeyAndOrderFront:"), NULL); + msg_bool(app->application, s("activateIgnoringOtherApps:"), YES); + ); +} + +void WindowIsTranslucent(struct Application *app) { + app->WindowIsTranslucent = 1; +} + +// Sends messages to the backend +void messageHandler(id self, SEL cmd, id contentController, id message) { + struct Application *app = (struct Application *)objc_getAssociatedObject( + self, "application"); + const char *name = (const char *)msg_reg(msg_reg(message, s("name")), s("UTF8String")); + if( strcmp(name, "error") == 0 ) { + printf("There was a Javascript error. Please open the devtools for more information.\n"); + // Show app if we are in debug mode + if( debug ) { + Show(app); + MessageDialog(app, "", "error", "Javascript Error", "There was a Javascript error. Please open the devtools for more information.", "", "", "", "","","",""); + } + } else if( strcmp(name, "completed") == 0) { + // Delete handler + msg_id(app->manager, s("removeScriptMessageHandlerForName:"), str("completed")); + + // TODO: Notify backend we're ready and get them to call back for the Show() + if (app->startHidden == 0) { + Show(app); + } + + // TODO: Check this actually does reduce flicker + ((id(*)(id, SEL, id, id))objc_msgSend)(app->config, s("setValue:forKey:"), msg_bool(c("NSNumber"), s("numberWithBool:"), 0), str("suppressesIncrementalRendering")); + + // We are now running! + app->running = true; + + + // Notify backend we are ready (system startup) + const char *readyMessage = "SS"; + if( app->startupURL == NULL ) { + app->sendMessageToBackend("SS"); + return; + } + readyMessage = concat("SS", app->startupURL); + app->sendMessageToBackend(readyMessage); + MEMFREE(readyMessage); + + } else if( strcmp(name, "windowDrag") == 0 ) { + // Guard against null events + if( app->mouseEvent != NULL ) { + HideMouse(); + ON_MAIN_THREAD( + msg_id(app->mainWindow, s("performWindowDragWithEvent:"), app->mouseEvent); + ); + } + } else if( strcmp(name, "contextMenu") == 0 ) { + + // Did we get a context menu selector? + if( message == NULL) { + return; + } + + const char *contextMenuMessage = cstr(msg_reg(message, s("body"))); + + if( contextMenuMessage == NULL ) { + Debug(app, "EMPTY CONTEXT MENU MESSAGE!!\n"); + return; + } + + // Parse the message + JsonNode *contextMenuMessageJSON = json_decode(contextMenuMessage); + if( contextMenuMessageJSON == NULL ) { + Debug(app, "Error decoding context menu message: %s", contextMenuMessage); + return; + } + + // Get menu ID + JsonNode *contextMenuIDNode = json_find_member(contextMenuMessageJSON, "id"); + if( contextMenuIDNode == NULL ) { + Debug(app, "Error decoding context menu ID: %s", contextMenuMessage); + json_delete(contextMenuMessageJSON); + return; + } + if( contextMenuIDNode->tag != JSON_STRING ) { + Debug(app, "Error decoding context menu ID (Not a string): %s", contextMenuMessage); + json_delete(contextMenuMessageJSON); + return; + } + + // Get menu Data + JsonNode *contextMenuDataNode = json_find_member(contextMenuMessageJSON, "data"); + if( contextMenuDataNode == NULL ) { + Debug(app, "Error decoding context menu data: %s", contextMenuMessage); + json_delete(contextMenuMessageJSON); + return; + } + if( contextMenuDataNode->tag != JSON_STRING ) { + Debug(app, "Error decoding context menu data (Not a string): %s", contextMenuMessage); + json_delete(contextMenuMessageJSON); + return; + } + + // We need to copy these as the JSON node will be destroyed on this thread and the + // string data will become corrupt. These need to be freed by the context menu code. + const char* contextMenuID = STRCOPY(contextMenuIDNode->string_); + const char* contextMenuData = STRCOPY(contextMenuDataNode->string_); + + ON_MAIN_THREAD( + ShowContextMenu(app->contextMenuStore, app->mainWindow, contextMenuID, contextMenuData); + ); + + json_delete(contextMenuMessageJSON); + + } else { + // const char *m = (const char *)msg(msg(message, s("body")), s("UTF8String")); + const char *m = cstr(msg_reg(message, s("body"))); + app->sendMessageToBackend(m); + } +} + +// closeWindow is called when the close button is pressed +void closeWindow(id self, SEL cmd, id sender) { + struct Application *app = (struct Application *) objc_getAssociatedObject(self, "application"); + app->sendMessageToBackend("WC"); +} + +bool isDarkMode(struct Application *app) { + id userDefaults = msg_reg(c("NSUserDefaults"), s("standardUserDefaults")); + const char *mode = cstr(msg_id(userDefaults, s("stringForKey:"), str("AppleInterfaceStyle"))); + return ( mode != NULL && strcmp(mode, "Dark") == 0 ); +} + +void ExecJS(struct Application *app, const char *js) { + ON_MAIN_THREAD( + ((id(*)(id, SEL, id, id))objc_msgSend)(app->wkwebview, + s("evaluateJavaScript:completionHandler:"), + str(js), + NULL); + ); +} + +void willFinishLaunching(id self, SEL cmd, id sender) { + struct Application *app = (struct Application *) objc_getAssociatedObject(self, "application"); + // If there are URL Handlers, register a listener for them + if( app->hasURLHandlers ) { + id eventManager = msg_reg(c("NSAppleEventManager"), s("sharedAppleEventManager")); + ((id(*)(id, SEL, id, SEL, int, int))objc_msgSend)(eventManager, s("setEventHandler:andSelector:forEventClass:andEventID:"), self, s("getUrl:withReplyEvent:"), kInternetEventClass, kAEGetURL); + } + messageFromWindowCallback("Ej{\"name\":\"wails:launched\",\"data\":[]}"); +} + +void emitThemeChange(struct Application *app) { + bool currentThemeIsDark = isDarkMode(app); + if (currentThemeIsDark) { + messageFromWindowCallback("Ej{\"name\":\"wails:system:themechange\",\"data\":[true]}"); + } else { + messageFromWindowCallback("Ej{\"name\":\"wails:system:themechange\",\"data\":[false]}"); + } +} + +void themeChanged(id self, SEL cmd, id sender) { + struct Application *app = (struct Application *)objc_getAssociatedObject( + self, "application"); +// emitThemeChange(app); + bool currentThemeIsDark = isDarkMode(app); + if ( currentThemeIsDark ) { + ExecJS(app, "window.wails.Events.Emit( 'wails:system:themechange', true );"); + } else { + ExecJS(app, "window.wails.Events.Emit( 'wails:system:themechange', false );"); + } +} + +int releaseNSObject(void *const context, struct hashmap_element_s *const e) { + msg_reg(e->data, s("release")); + return -1; +} + +void destroyContextMenus(struct Application *app) { + DeleteContextMenuStore(app->contextMenuStore); +} + +void freeDialogIconCache(struct Application *app) { + // Release the dialog cache images + if( hashmap_num_entries(&dialogIconCache) > 0 ) { + if (0!=hashmap_iterate_pairs(&dialogIconCache, releaseNSObject, NULL)) { + Fatal(app, "failed to release hashmap entries!"); + } + } + + //Free radio groups hashmap + hashmap_destroy(&dialogIconCache); +} + +void DestroyApplication(struct Application *app) { + app->shuttingDown = true; + Debug(app, "Destroying Application"); + + // Free the bindings + if (app->bindings != NULL) { + MEMFREE(app->bindings); + } else { + Debug(app, "Almost a double free for app->bindings"); + } + + if( app->startupURL != NULL ) { + MEMFREE(app->startupURL); + } + + // Remove mouse monitors + if( app->mouseDownMonitor != NULL ) { + msg_id( c("NSEvent"), s("removeMonitor:"), app->mouseDownMonitor); + } + if( app->mouseUpMonitor != NULL ) { + msg_id( c("NSEvent"), s("removeMonitor:"), app->mouseUpMonitor); + } + + // Delete the application menu if we have one + if( app->applicationMenu != NULL ) { + DeleteMenu(app->applicationMenu); + } + + // Delete the tray menu store + DeleteTrayMenuStore(TrayMenuStoreSingleton); + + // Delete the context menu store + DeleteContextMenuStore(app->contextMenuStore); + + // Destroy the context menus + destroyContextMenus(app); + + // Free dialog icon cache + freeDialogIconCache(app); + + // Unload the tray Icons + UnloadTrayIcons(); + + // Remove script handlers + msg_id(app->manager, s("removeScriptMessageHandlerForName:"), str("contextMenu")); + msg_id(app->manager, s("removeScriptMessageHandlerForName:"), str("windowDrag")); + msg_id(app->manager, s("removeScriptMessageHandlerForName:"), str("external")); + msg_id(app->manager, s("removeScriptMessageHandlerForName:"), str("error")); + + // Close main window + if( app->windowDelegate != NULL ) { + msg_reg(app->windowDelegate, s("release")); + msg_id(app->mainWindow, s("setDelegate:"), NULL); + } + +// msg(app->mainWindow, s("close")); + + + Debug(app, "Finished Destroying Application"); +} + +// SetTitle sets the main window title to the given string +void SetTitle(struct Application *app, const char *title) { + // Guard against calling during shutdown + if( app->shuttingDown ) return; + + Debug(app, "SetTitle Called"); + ON_MAIN_THREAD( + msg_id(app->mainWindow, s("setTitle:"), str(title)); + ); +} + +void ToggleFullscreen(struct Application *app) { + ON_MAIN_THREAD( + app->fullscreen = !app->fullscreen; + MAIN_WINDOW_CALL("toggleFullScreen:"); + ); +} + +bool isFullScreen(struct Application *app) { + long mask = (long)msg_reg(app->mainWindow, s("styleMask")); + bool result = (mask & NSWindowStyleMaskFullscreen) == NSWindowStyleMaskFullscreen; + return result; +} + +// Fullscreen sets the main window to be fullscreen +void Fullscreen(struct Application *app) { + // Guard against calling during shutdown + if( app->shuttingDown ) return; + + Debug(app, "Fullscreen Called"); + if( ! isFullScreen(app) ) { + ToggleFullscreen(app); + } +} + +// UnFullscreen resets the main window after a fullscreen +void UnFullscreen(struct Application *app) { + // Guard against calling during shutdown + if( app->shuttingDown ) return; + + Debug(app, "UnFullscreen Called"); + if( isFullScreen(app) ) { + ToggleFullscreen(app); + } +} + +void Center(struct Application *app) { + // Guard against calling during shutdown + if( app->shuttingDown ) return; + + Debug(app, "Center Called"); + ON_MAIN_THREAD( + MAIN_WINDOW_CALL("center"); + ); +} + +void ToggleMaximise(struct Application *app) { + ON_MAIN_THREAD( + app->maximised = !app->maximised; + MAIN_WINDOW_CALL("zoom:"); + ); +} + +void Maximise(struct Application *app) { + // Guard against calling during shutdown + if( app->shuttingDown ) return; + + if( app->maximised == 0) { + ToggleMaximise(app); + } +} + +void Unmaximise(struct Application *app) { + // Guard against calling during shutdown + if( app->shuttingDown ) return; + + if( app->maximised == 1) { + ToggleMaximise(app); + } +} + +void Minimise(struct Application *app) { + // Guard against calling during shutdown + if( app->shuttingDown ) return; + + ON_MAIN_THREAD( + MAIN_WINDOW_CALL("miniaturize:"); + ); + } +void Unminimise(struct Application *app) { + // Guard against calling during shutdown + if( app->shuttingDown ) return; + + ON_MAIN_THREAD( + MAIN_WINDOW_CALL("deminiaturize:"); + ); +} + +id getCurrentScreen(struct Application *app) { + id screen = NULL; + screen = msg_reg(app->mainWindow, s("screen")); + if( screen == NULL ) { + screen = msg_reg(c("NSScreen"), u("mainScreen")); + } + return screen; +} + +void dumpFrame(struct Application *app, const char *message, CGRect frame) { + Debug(app, message); + Debug(app, "origin.x %f", frame.origin.x); + Debug(app, "origin.y %f", frame.origin.y); + Debug(app, "size.width %f", frame.size.width); + Debug(app, "size.height %f", frame.size.height); +} + +void SetSize(struct Application *app, int width, int height) { + // Guard against calling during shutdown + if( app->shuttingDown ) return; + + ON_MAIN_THREAD( + id screen = getCurrentScreen(app); + + // Get the rect for the window + CGRect frame = GET_FRAME(app->mainWindow); + + // Credit: https://github.com/patr0nus/DeskGap/blob/73c0ac9f2c73f55b6e81f64f6673a7962b5719cd/lib/src/platform/mac/util/NSScreen%2BGeometry.m + frame.origin.y = (frame.origin.y + frame.size.height) - (float)height; + frame.size.width = (float)width; + frame.size.height = (float)height; + + ((id(*)(id, SEL, CGRect, BOOL, BOOL))objc_msgSend)(app->mainWindow, s("setFrame:display:animate:"), frame, 1, 0); + ); +} + +void SetPosition(struct Application *app, int x, int y) { + // Guard against calling during shutdown + if( app->shuttingDown ) return; + + ON_MAIN_THREAD( + id screen = getCurrentScreen(app); + CGRect screenFrame = GET_FRAME(screen); + CGRect windowFrame = GET_FRAME(app->mainWindow); + + windowFrame.origin.x = screenFrame.origin.x + (float)x; + windowFrame.origin.y = (screenFrame.origin.y + screenFrame.size.height) - windowFrame.size.height - (float)y; + ((id(*)(id, SEL, CGRect, BOOL, BOOL))objc_msgSend)(app->mainWindow, s("setFrame:display:animate:"), windowFrame, 1, 0); + ); +} + +void processDialogButton(id alert, char *buttonTitle, char *cancelButton, char *defaultButton) { + // If this button is set + if( STR_HAS_CHARS(buttonTitle) ) { + id button = msg_id(alert, s("addButtonWithTitle:"), str(buttonTitle)); + if ( STREQ( buttonTitle, defaultButton) ) { + msg_id(button, s("setKeyEquivalent:"), str("\r")); + } + if ( STREQ( buttonTitle, cancelButton) ) { + msg_id(button, s("setKeyEquivalent:"), str("\033")); + } + } +} + +void MessageDialog(struct Application *app, char *callbackID, char *type, char *title, char *message, char *icon, char *button1, char *button2, char *button3, char *button4, char *defaultButton, char *cancelButton) { + // Guard against calling during shutdown + if( app->shuttingDown ) return; + + ON_MAIN_THREAD( + id alert = ALLOC_INIT("NSAlert"); + char *dialogType = type; + char *dialogIcon = type; + + // Default to info type + if( dialogType == NULL ) { + dialogType = "info"; + } + + // Set the dialog style + if( STREQ(dialogType, "info") || STREQ(dialogType, "question") ) { + msg_uint(alert, s("setAlertStyle:"), NSAlertStyleInformational); + } else if( STREQ(dialogType, "warning") ) { + msg_uint(alert, s("setAlertStyle:"), NSAlertStyleWarning); + } else if( STREQ(dialogType, "error") ) { + msg_uint(alert, s("setAlertStyle:"), NSAlertStyleCritical); + } + + // Set title if given + if( strlen(title) > 0 ) { + msg_id(alert, s("setMessageText:"), str(title)); + } + + // Set message if given + if( strlen(message) > 0) { + msg_id(alert, s("setInformativeText:"), str(message)); + } + + // Process buttons + processDialogButton(alert, button1, cancelButton, defaultButton); + processDialogButton(alert, button2, cancelButton, defaultButton); + processDialogButton(alert, button3, cancelButton, defaultButton); + processDialogButton(alert, button4, cancelButton, defaultButton); + + // Check for custom dialog icon + if( strlen(icon) > 0 ) { + dialogIcon = icon; + } + + // TODO: move dialog icons + methods to own file + + // Determine what dialog icon we are looking for + id dialogImage = NULL; + // Look for `name-theme2x` first + char *themeIcon = concat(dialogIcon, (isDarkMode(app) ? "-dark" : "-light") ); + if( isRetina(app) ) { + char *dialogIcon2x = concat(themeIcon, "2x"); + dialogImage = hashmap_get(&dialogIconCache, dialogIcon2x, strlen(dialogIcon2x)); +// if (dialogImage != NULL ) printf("Using %s\n", dialogIcon2x); + MEMFREE(dialogIcon2x); + + // Now look for non-themed icon `name2x` + if ( dialogImage == NULL ) { + dialogIcon2x = concat(dialogIcon, "2x"); + dialogImage = hashmap_get(&dialogIconCache, dialogIcon2x, strlen(dialogIcon2x)); +// if (dialogImage != NULL ) printf("Using %s\n", dialogIcon2x); + MEMFREE(dialogIcon2x); + } + } + + // If we don't have a retina icon, try the 1x name-theme icon + if( dialogImage == NULL ) { + dialogImage = hashmap_get(&dialogIconCache, themeIcon, strlen(themeIcon)); +// if (dialogImage != NULL ) printf("Using %s\n", themeIcon); + } + + // Free the theme icon memory + MEMFREE(themeIcon); + + // Finally try the name itself + if( dialogImage == NULL ) { + dialogImage = hashmap_get(&dialogIconCache, dialogIcon, strlen(dialogIcon)); +// if (dialogImage != NULL ) printf("Using %s\n", dialogIcon); + } + + if (dialogImage != NULL ) { + msg_id(alert, s("setIcon:"), dialogImage); + } + + // Run modal + char *buttonPressed; + long response = (long)msg_reg(alert, s("runModal")); + if( response == NSAlertFirstButtonReturn ) { + buttonPressed = button1; + } + else if( response == NSAlertSecondButtonReturn ) { + buttonPressed = button2; + } + else if( response == NSAlertThirdButtonReturn ) { + buttonPressed = button3; + } + else { + buttonPressed = button4; + } + + if ( STR_HAS_CHARS(callbackID) ) { + // Construct callback message. Format "DM|" + const char *callback = concat("DM", callbackID); + const char *header = concat(callback, "|"); + const char *responseMessage = concat(header, buttonPressed); + + // Send message to backend + app->sendMessageToBackend(responseMessage); + + // Free memory + MEMFREE(header); + MEMFREE(callback); + MEMFREE(responseMessage); + } + ); +} + +// OpenDialog opens a dialog to select files/directories +void OpenDialog(struct Application *app, char *callbackID, char *title, char *filters, char *defaultFilename, char *defaultDir, int allowFiles, int allowDirs, int allowMultiple, int showHiddenFiles, int canCreateDirectories, int resolvesAliases, int treatPackagesAsDirectories) { + // Guard against calling during shutdown + if( app->shuttingDown ) return; + + Debug(app, "OpenDialog Called with callback id: %s", callbackID); + + // Create an open panel + ON_MAIN_THREAD( + + // Create the dialog + id dialog = msg_reg(c("NSOpenPanel"), s("openPanel")); + + // Valid but appears to do nothing.... :/ + msg_id(dialog, s("setTitle:"), str(title)); + + // Filters + if( filters != NULL && strlen(filters) > 0) { + id filterString = msg_id_id(str(filters), s("stringByReplacingOccurrencesOfString:withString:"), str("*."), str("")); + filterString = msg_id_id(filterString, s("stringByReplacingOccurrencesOfString:withString:"), str(" "), str("")); + id filterList = msg_id(filterString, s("componentsSeparatedByString:"), str(",")); + msg_id(dialog, s("setAllowedFileTypes:"), filterList); + } else { + msg_bool(dialog, s("setAllowsOtherFileTypes:"), YES); + } + + // Default Directory + if( defaultDir != NULL && strlen(defaultDir) > 0 ) { + msg_id(dialog, s("setDirectoryURL:"), url(defaultDir)); + } + + // Default Filename + if( defaultFilename != NULL && strlen(defaultFilename) > 0 ) { + msg_id(dialog, s("setNameFieldStringValue:"), str(defaultFilename)); + } + + // Setup Options + msg_bool(dialog, s("setCanChooseFiles:"), allowFiles); + msg_bool(dialog, s("setCanChooseDirectories:"), allowDirs); + msg_bool(dialog, s("setAllowsMultipleSelection:"), allowMultiple); + msg_bool(dialog, s("setShowsHiddenFiles:"), showHiddenFiles); + msg_bool(dialog, s("setCanCreateDirectories:"), canCreateDirectories); + msg_bool(dialog, s("setResolvesAliases:"), resolvesAliases); + msg_bool(dialog, s("setTreatsFilePackagesAsDirectories:"), treatPackagesAsDirectories); + + // Setup callback handler + ((id(*)(id, SEL, id, void (^)(id)))objc_msgSend)(dialog, s("beginSheetModalForWindow:completionHandler:"), app->mainWindow, ^(id result) { + + // Create the response JSON object + JsonNode *response = json_mkarray(); + + // If the user selected some files + if( result == (id)1 ) { + // Grab the URLs returned + id urls = msg_reg(dialog, s("URLs")); + + // Iterate over all the selected files + long noOfResults = (long)msg_reg(urls, s("count")); + for( int index = 0; index < noOfResults; index++ ) { + + // Extract the filename + id url = msg_int(urls, s("objectAtIndex:"), index); + const char *filename = (const char *)msg_reg(msg_reg(url, s("path")), s("UTF8String")); + + // Add the the response array + json_append_element(response, json_mkstring(filename)); + } + } + + // Create JSON string and free json memory + char *encoded = json_stringify(response, ""); + json_delete(response); + + // Construct callback message. Format "D|" + const char *callback = concat("DO", callbackID); + const char *header = concat(callback, "|"); + const char *responseMessage = concat(header, encoded); + + // Send message to backend + app->sendMessageToBackend(responseMessage); + + // Free memory + MEMFREE(header); + MEMFREE(callback); + MEMFREE(responseMessage); + }); + + msg_id( c("NSApp"), s("runModalForWindow:"), app->mainWindow); + ); +} + +// SaveDialog opens a dialog to select files/directories +void SaveDialog(struct Application *app, char *callbackID, char *title, char *filters, char *defaultFilename, char *defaultDir, int showHiddenFiles, int canCreateDirectories, int treatPackagesAsDirectories) { + // Guard against calling during shutdown + if( app->shuttingDown ) return; + + Debug(app, "SaveDialog Called with callback id: %s", callbackID); + + // Create an open panel + ON_MAIN_THREAD( + + // Create the dialog + id dialog = msg_reg(c("NSSavePanel"), s("savePanel")); + + // Valid but appears to do nothing.... :/ + msg_id(dialog, s("setTitle:"), str(title)); + + // Filters + if( filters != NULL && strlen(filters) > 0) { + id filterString = msg_id_id(str(filters), s("stringByReplacingOccurrencesOfString:withString:"), str("*."), str("")); + filterString = msg_id_id(filterString, s("stringByReplacingOccurrencesOfString:withString:"), str(" "), str("")); + id filterList = msg_id(filterString, s("componentsSeparatedByString:"), str(",")); + msg_id(dialog, s("setAllowedFileTypes:"), filterList); + } else { + msg_bool(dialog, s("setAllowsOtherFileTypes:"), YES); + } + + // Default Directory + if( defaultDir != NULL && strlen(defaultDir) > 0 ) { + msg_id(dialog, s("setDirectoryURL:"), url(defaultDir)); + } + + // Default Filename + if( defaultFilename != NULL && strlen(defaultFilename) > 0 ) { + msg_id(dialog, s("setNameFieldStringValue:"), str(defaultFilename)); + } + + // Setup Options + msg_bool(dialog, s("setShowsHiddenFiles:"), showHiddenFiles); + msg_bool(dialog, s("setCanCreateDirectories:"), canCreateDirectories); + msg_bool(dialog, s("setTreatsFilePackagesAsDirectories:"), treatPackagesAsDirectories); + + // Setup callback handler + ((id(*)(id, SEL, id, void (^)(id)))objc_msgSend)(dialog, s("beginSheetModalForWindow:completionHandler:"), app->mainWindow, ^(id result) { + + // Default is blank + const char *filename = ""; + + // If the user selected some files + if( result == (id)1 ) { + // Grab the URL returned + id url = msg_reg(dialog, s("URL")); + filename = (const char *)msg_reg(msg_reg(url, s("path")), s("UTF8String")); + } + + // Construct callback message. Format "DS|" + const char *callback = concat("DS", callbackID); + const char *header = concat(callback, "|"); + const char *responseMessage = concat(header, filename); + + // Send message to backend + app->sendMessageToBackend(responseMessage); + + // Free memory + MEMFREE(header); + MEMFREE(callback); + MEMFREE(responseMessage); + }); + + msg_id( c("NSApp"), s("runModalForWindow:"), app->mainWindow); + ); +} + +const char *invoke = "window.wailsInvoke=function(message){window.webkit.messageHandlers.external.postMessage(message);};window.wailsDrag=function(message){window.webkit.messageHandlers.windowDrag.postMessage(message);};window.wailsContextMenuMessage=function(message){window.webkit.messageHandlers.contextMenu.postMessage(message);};"; + +// DisableFrame disables the window frame +void DisableFrame(struct Application *app) +{ + app->frame = 0; +} + +void setMinMaxSize(struct Application *app) +{ + // Guard against calling during shutdown + if( app->shuttingDown ) return; + + if (app->maxHeight > 0 && app->maxWidth > 0) + { + ((id(*)(id, SEL, CGSize))objc_msgSend)(app->mainWindow, s("setMaxSize:"), CGSizeMake(app->maxWidth, app->maxHeight)); + } + if (app->minHeight > 0 && app->minWidth > 0) + { + ((id(*)(id, SEL, CGSize))objc_msgSend)(app->mainWindow, s("setMinSize:"), CGSizeMake(app->minWidth, app->minHeight)); + } + + // Calculate if window needs resizing + int newWidth = app->width; + int newHeight = app->height; + + if (app->maxWidth > 0 && app->width > app->maxWidth) newWidth = app->maxWidth; + if (app->minWidth > 0 && app->width < app->minWidth) newWidth = app->minWidth; + if (app->maxHeight > 0 && app->height > app->maxHeight ) newHeight = app->maxHeight; + if (app->minHeight > 0 && app->height < app->minHeight ) newHeight = app->minHeight; + + // If we have any change, resize window + if ( newWidth != app->width || newHeight != app->height ) { + SetSize(app, newWidth, newHeight); + } +} + +void SetMinWindowSize(struct Application *app, int minWidth, int minHeight) +{ + // Guard against calling during shutdown + if( app->shuttingDown ) return; + + app->minWidth = minWidth; + app->minHeight = minHeight; + + // Apply if the window is created + if( app->mainWindow != NULL ) { + ON_MAIN_THREAD( + setMinMaxSize(app); + ); + } +} + +void SetMaxWindowSize(struct Application *app, int maxWidth, int maxHeight) +{ + // Guard against calling during shutdown + if( app->shuttingDown ) return; + + app->maxWidth = maxWidth; + app->maxHeight = maxHeight; + + // Apply if the window is created + if( app->mainWindow != NULL ) { + ON_MAIN_THREAD( + setMinMaxSize(app); + ); + } +} + + +void SetDebug(void *applicationPointer, int flag) { + debug = flag; +} + + + +// AddContextMenu sets the context menu map for this application +void AddContextMenu(struct Application *app, const char *contextMenuJSON) { + // Guard against calling during shutdown + if( app->shuttingDown ) return; + ON_MAIN_THREAD ( + AddContextMenuToStore(app->contextMenuStore, contextMenuJSON); + ); +} + +void UpdateContextMenu(struct Application *app, const char* contextMenuJSON) { + // Guard against calling during shutdown + if( app->shuttingDown ) return; + ON_MAIN_THREAD( + UpdateContextMenuInStore(app->contextMenuStore, contextMenuJSON); + ); +} + +void AddTrayMenu(struct Application *app, const char *trayMenuJSON) { + // Guard against calling during shutdown + if( app->shuttingDown ) return; + + ON_MAIN_THREAD( + AddTrayMenuToStore(TrayMenuStoreSingleton, trayMenuJSON); + ); +} + +void SetTrayMenu(struct Application *app, const char* trayMenuJSON) { + + // Guard against calling during shutdown + if( app->shuttingDown ) return; + + ON_MAIN_THREAD( + UpdateTrayMenuInStore(TrayMenuStoreSingleton, trayMenuJSON); + ); +} + +void DeleteTrayMenuByID(struct Application *app, const char *id) { + ON_MAIN_THREAD( + DeleteTrayMenuInStore(TrayMenuStoreSingleton, id); + ); +} + +void UpdateTrayMenuLabel(struct Application* app, const char* JSON) { + // Guard against calling during shutdown + if( app->shuttingDown ) return; + + ON_MAIN_THREAD( + UpdateTrayMenuLabelInStore(TrayMenuStoreSingleton, JSON); + ); +} + + +void SetBindings(struct Application *app, const char *bindings) { + const char* temp = concat("window.wailsbindings = \"", bindings); + const char* jscall = concat(temp, "\";"); + MEMFREE(temp); + app->bindings = jscall; +} + +void makeWindowBackgroundTranslucent(struct Application *app) { + id contentView = msg_reg(app->mainWindow, s("contentView")); + id effectView = msg_reg(c("NSVisualEffectView"), s("alloc")); + CGRect bounds = GET_BOUNDS(contentView); + effectView = ((id(*)(id, SEL, CGRect))objc_msgSend)(effectView, s("initWithFrame:"), bounds); + + msg_int(effectView, s("setAutoresizingMask:"), NSViewWidthSizable | NSViewHeightSizable); + msg_int(effectView, s("setBlendingMode:"), NSVisualEffectBlendingModeBehindWindow); + msg_int(effectView, s("setState:"), NSVisualEffectStateActive); + ((id(*)(id, SEL, id, int, id))objc_msgSend)(contentView, s("addSubview:positioned:relativeTo:"), effectView, NSWindowBelow, NULL); +} + +void enableBoolConfig(id config, const char *setting) { + ((id(*)(id, SEL, id, id))objc_msgSend)(msg_reg(config, s("preferences")), s("setValue:forKey:"), msg_bool(c("NSNumber"), s("numberWithBool:"), 1), str(setting)); +} + +void disableBoolConfig(id config, const char *setting) { + ((id(*)(id, SEL, id, id))objc_msgSend)(msg_reg(config, s("preferences")), s("setValue:forKey:"), msg_bool(c("NSNumber"), s("numberWithBool:"), 0), str(setting)); +} + +void processDecorations(struct Application *app) { + + int decorations = 0; + + if (app->frame == 1 ) { + if( app->hideTitleBar == 0) { + decorations |= NSWindowStyleMaskTitled; + } + decorations |= NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable; + } + + if (app->resizable) { + decorations |= NSWindowStyleMaskResizable; + } + + if (app->fullscreen) { + decorations |= NSWindowStyleMaskFullscreen; + } + + if( app->fullSizeContent || app->frame == 0) { + decorations |= NSWindowStyleMaskFullSizeContentView; + } + + app->decorations = decorations; +} + +void createApplication(struct Application *app) { + id application = msg_reg(c("NSApplication"), s("sharedApplication")); + app->application = application; + msg_int(application, s("setActivationPolicy:"), app->activationPolicy); +} + +void DarkModeEnabled(struct Application *app, const char *callbackID) { + // Guard against calling during shutdown + if( app->shuttingDown ) return; + + ON_MAIN_THREAD( + const char *result = isDarkMode(app) ? "T" : "F"; + + // Construct callback message. Format "SD|" + const char *callback = concat("SD", callbackID); + const char *header = concat(callback, "|"); + const char *responseMessage = concat(header, result); + // Send message to backend + app->sendMessageToBackend(responseMessage); + + // Free memory + MEMFREE(header); + MEMFREE(callback); + MEMFREE(responseMessage); + ); +} + +void getURL(id self, SEL selector, id event, id replyEvent) { + struct Application *app = (struct Application *)objc_getAssociatedObject(self, "application"); + id desc = msg_int(event, s("paramDescriptorForKeyword:"), keyDirectObject); + id url = msg_reg(desc, s("stringValue")); + const char* curl = cstr(url); + if( curl == NULL ) { + return; + } + + // If this was an incoming URL, but we aren't running yet + // save it to return when we complete + if( app->running != true ) { + app->startupURL = STRCOPY(curl); + return; + } + + const char* message = concat("UC", curl); + messageFromWindowCallback(message); + MEMFREE(message); +} + +void openURLs(id self, SEL selector, id event) { + filelog("\n\nI AM HERE!!!!!\n\n"); +} + + +void createDelegate(struct Application *app) { + + // Define delegate + Class appDelegate = objc_allocateClassPair((Class) c("NSResponder"), "AppDelegate", 0); + class_addProtocol(appDelegate, objc_getProtocol("NSTouchBarProvider")); + + class_addMethod(appDelegate, s("applicationShouldTerminateAfterLastWindowClosed:"), (IMP) no, "c@:@"); + class_addMethod(appDelegate, s("applicationWillFinishLaunching:"), (IMP) willFinishLaunching, "v@:@"); + + // All Menu Items use a common callback + class_addMethod(appDelegate, s("menuItemCallback:"), (IMP)menuItemCallback, "v@:@"); + + // If there are URL Handlers, register the callback method + if( app->hasURLHandlers ) { + class_addMethod(appDelegate, s("getUrl:withReplyEvent:"), (IMP) getURL, "i@:@@"); + } + + // Script handler + class_addMethod(appDelegate, s("userContentController:didReceiveScriptMessage:"), (IMP) messageHandler, "v@:@@"); + objc_registerClassPair(appDelegate); + + // Create delegate + id delegate = msg_reg((id)appDelegate, s("new")); + objc_setAssociatedObject(delegate, "application", (id)app, OBJC_ASSOCIATION_ASSIGN); + + // Theme change listener + class_addMethod(appDelegate, s("themeChanged:"), (IMP) themeChanged, "v@:@@"); + + // Get defaultCenter + id defaultCenter = msg_reg(c("NSDistributedNotificationCenter"), s("defaultCenter")); + ((id(*)(id, SEL, id, SEL, id, id))objc_msgSend)(defaultCenter, s("addObserver:selector:name:object:"), delegate, s("themeChanged:"), str("AppleInterfaceThemeChangedNotification"), NULL); + + app->delegate = delegate; + + msg_id(app->application, s("setDelegate:"), delegate); +} + +bool windowShouldClose(id self, SEL cmd, id sender) { + msg_reg(sender, s("orderOut:")); + return false; +} + +bool windowShouldExit(id self, SEL cmd, id sender) { + msg_reg(sender, s("orderOut:")); + messageFromWindowCallback("WC"); + return false; +} + +void createMainWindow(struct Application *app) { + // Create main window + id mainWindow = ALLOC("NSWindow"); + mainWindow = ((id(*)(id, SEL, CGRect, int, int, BOOL))objc_msgSend)(mainWindow, s("initWithContentRect:styleMask:backing:defer:"), + CGRectMake(0, 0, app->width, app->height), app->decorations, NSBackingStoreBuffered, NO); + msg_reg(mainWindow, s("autorelease")); + + // Set Appearance + if( app->appearance != NULL ) { + msg_id(mainWindow, s("setAppearance:"), + msg_id(c("NSAppearance"), s("appearanceNamed:"), str(app->appearance)) + ); + } + + // Set Title appearance + msg_bool(mainWindow, s("setTitlebarAppearsTransparent:"), app->titlebarAppearsTransparent ? YES : NO); + msg_int(mainWindow, s("setTitleVisibility:"), app->hideTitle); + + // Create window delegate to override windowShouldClose + Class delegateClass = objc_allocateClassPair((Class) c("NSObject"), "WindowDelegate", 0); + bool resultAddProtoc = class_addProtocol(delegateClass, objc_getProtocol("NSWindowDelegate")); + if( app->hideWindowOnClose ) { + class_replaceMethod(delegateClass, s("windowShouldClose:"), (IMP) windowShouldClose, "v@:@"); + } else { + class_replaceMethod(delegateClass, s("windowShouldClose:"), (IMP) windowShouldExit, "v@:@"); + } + app->windowDelegate = msg_reg((id)delegateClass, s("new")); + msg_id(mainWindow, s("setDelegate:"), app->windowDelegate); + + app->mainWindow = mainWindow; +} + +const char* getInitialState(struct Application *app) { + const char *result = ""; + if( isDarkMode(app) ) { + result = "window.wails.System.IsDarkMode.set(true);"; + } else { + result = "window.wails.System.IsDarkMode.set(false);"; + } + char buffer[999]; + snprintf(&buffer[0], sizeof(buffer), "window.wails.System.LogLevel.set(%d);", app->logLevel); + result = concat(result, &buffer[0]); + Debug(app, "initialstate = %s", result); + return result; +} + +void parseMenuRole(struct Application *app, id parentMenu, JsonNode *item) { + const char *roleName = item->string_; + + if ( STREQ(roleName, "appMenu") ) { + createDefaultAppMenu(parentMenu); + return; + } + if ( STREQ(roleName, "editMenu")) { + createDefaultEditMenu(parentMenu); + return; + } + if ( STREQ(roleName, "hide")) { + addMenuItem(parentMenu, "Hide Window", "hide:", "h", FALSE); + return; + } + if ( STREQ(roleName, "hideothers")) { + id hideOthers = addMenuItem(parentMenu, "Hide Others", "hideOtherApplications:", "h", FALSE); + msg_int(hideOthers, s("setKeyEquivalentModifierMask:"), (NSEventModifierFlagOption | NSEventModifierFlagCommand)); + return; + } + if ( STREQ(roleName, "unhide")) { + addMenuItem(parentMenu, "Show All", "unhideAllApplications:", "", FALSE); + return; + } + if ( STREQ(roleName, "front")) { + addMenuItem(parentMenu, "Bring All to Front", "arrangeInFront:", "", FALSE); + return; + } + if ( STREQ(roleName, "undo")) { + addMenuItem(parentMenu, "Undo", "undo:", "z", FALSE); + return; + } + if ( STREQ(roleName, "redo")) { + addMenuItem(parentMenu, "Redo", "redo:", "y", FALSE); + return; + } + if ( STREQ(roleName, "cut")) { + addMenuItem(parentMenu, "Cut", "cut:", "x", FALSE); + return; + } + if ( STREQ(roleName, "copy")) { + addMenuItem(parentMenu, "Copy", "copy:", "c", FALSE); + return; + } + if ( STREQ(roleName, "paste")) { + addMenuItem(parentMenu, "Paste", "paste:", "v", FALSE); + return; + } + if ( STREQ(roleName, "delete")) { + addMenuItem(parentMenu, "Delete", "delete:", "", FALSE); + return; + } + if( STREQ(roleName, "pasteandmatchstyle")) { + id pasteandmatchstyle = addMenuItem(parentMenu, "Paste and Match Style", "pasteandmatchstyle:", "v", FALSE); + msg_int(pasteandmatchstyle, s("setKeyEquivalentModifierMask:"), (NSEventModifierFlagOption | NSEventModifierFlagShift | NSEventModifierFlagCommand)); + } + if ( STREQ(roleName, "selectall")) { + addMenuItem(parentMenu, "Select All", "selectAll:", "a", FALSE); + return; + } + if ( STREQ(roleName, "minimize")) { + addMenuItem(parentMenu, "Minimize", "miniaturize:", "m", FALSE); + return; + } + if ( STREQ(roleName, "zoom")) { + addMenuItem(parentMenu, "Zoom", "performZoom:", "", FALSE); + return; + } + if ( STREQ(roleName, "quit")) { + addMenuItem(parentMenu, "Quit", "terminate:", "q", FALSE); + return; + } + if ( STREQ(roleName, "togglefullscreen")) { + addMenuItem(parentMenu, "Toggle Full Screen", "toggleFullScreen:", "f", FALSE); + return; + } + +} + +void dumpMemberList(const char *name, id *memberList) { + void *member = memberList[0]; + int count = 0; + printf("%s = %p -> [ ", name, memberList); + while( member != NULL ) { + printf("%p ", member); + count = count + 1; + member = memberList[count]; + } + printf("]\n"); +} + +// updateMenu replaces the current menu with the given one +void updateMenu(struct Application *app, const char *menuAsJSON) { + Debug(app, "Menu is now: %s", menuAsJSON); + ON_MAIN_THREAD ( + DeleteMenu(app->applicationMenu); + Menu* newMenu = NewApplicationMenu(menuAsJSON); + id menu = GetMenu(newMenu); + app->applicationMenu = newMenu; + msg_id(msg_reg(c("NSApplication"), s("sharedApplication")), s("setMainMenu:"), menu); + ); +} + +// SetApplicationMenu sets the initial menu for the application +void SetApplicationMenu(struct Application *app, const char *menuAsJSON) { + // Guard against calling during shutdown + if( app->shuttingDown ) return; + + if ( app->applicationMenu == NULL ) { + app->applicationMenu = NewApplicationMenu(menuAsJSON); + return; + } + + // Update menu + ON_MAIN_THREAD ( + updateMenu(app, menuAsJSON); + ); +} + +void processDialogIcons(struct hashmap_s *hashmap, const unsigned char *dialogIcons[]) { + + unsigned int count = 0; + while( 1 ) { + const unsigned char *name = dialogIcons[count++]; + if( name == 0x00 ) { + break; + } + const unsigned char *lengthAsString = dialogIcons[count++]; + if( name == 0x00 ) { + break; + } + const unsigned char *data = dialogIcons[count++]; + if( data == 0x00 ) { + break; + } + int length = atoi((const char *)lengthAsString); + + // Create the icon and add to the hashmap + id imageData = ((id(*)(id, SEL, const unsigned char *, int))objc_msgSend)(c("NSData"), s("dataWithBytes:length:"), data, length); + id dialogImage = ALLOC("NSImage"); + msg_reg(dialogImage, s("autorelease")); + msg_id(dialogImage, s("initWithData:"), imageData); + hashmap_put(hashmap, (const char *)name, strlen((const char *)name), dialogImage); + } + +} + +void processUserDialogIcons(struct Application *app) { + + // Allocate the Dialog icon hashmap + if( 0 != hashmap_create((const unsigned)4, &dialogIconCache)) { + // Couldn't allocate map + Fatal(app, "Not enough memory to allocate dialogIconCache!"); + return; + } + + processDialogIcons(&dialogIconCache, defaultDialogIcons); + processDialogIcons(&dialogIconCache, userDialogIcons); + +} + +void TrayMenuWillOpen(id self, SEL selector, id menu) { + // Extract tray menu id from menu + id trayMenuIDStr = objc_getAssociatedObject(menu, "trayMenuID"); + const char* trayMenuID = cstr(trayMenuIDStr); + const char *message = concat("Mo", trayMenuID); + messageFromWindowCallback(message); + MEMFREE(message); +} + +void TrayMenuDidClose(id self, SEL selector, id menu) { + // Extract tray menu id from menu + id trayMenuIDStr = objc_getAssociatedObject(menu, "trayMenuID"); + const char* trayMenuID = cstr(trayMenuIDStr); + const char *message = concat("Mc", trayMenuID); + messageFromWindowCallback(message); + MEMFREE(message); +} + +void createTrayMenuDelegate() { + // Define delegate + trayMenuDelegateClass = objc_allocateClassPair((Class) c("NSObject"), "MenuDelegate", 0); + class_addProtocol(trayMenuDelegateClass, objc_getProtocol("NSMenuDelegate")); + class_addMethod(trayMenuDelegateClass, s("menuWillOpen:"), (IMP) TrayMenuWillOpen, "v@:@"); + class_addMethod(trayMenuDelegateClass, s("menuDidClose:"), (IMP) TrayMenuDidClose, "v@:@"); + + // Script handler + objc_registerClassPair(trayMenuDelegateClass); +} + + +void Run(struct Application *app, int argc, char **argv) { + + // Process window decorations + processDecorations(app); + + // Create the application + createApplication(app); + + // Define delegate + createDelegate(app); + + // Define tray delegate + createTrayMenuDelegate(); + + // Create the main window + createMainWindow(app); + + // Create Content View + id contentView = msg_reg( ALLOC("NSView"), s("init") ); + msg_id(app->mainWindow, s("setContentView:"), contentView); + + // Set the main window title + SetTitle(app, app->title); + + // Center Window + Center(app); + + // Set Colour + applyWindowColour(app); + + // Process translucency + if (app->WindowIsTranslucent) { + makeWindowBackgroundTranslucent(app); + } + + // We set it to be invisible by default. It will become visible when everything has initialised + msg_bool(app->mainWindow, s("setIsVisible:"), NO); + + // Setup webview + id config = msg_reg(c("WKWebViewConfiguration"), s("new")); + ((id(*)(id, SEL, id, id))objc_msgSend)(config, s("setValue:forKey:"), msg_bool(c("NSNumber"), s("numberWithBool:"), 1), str("suppressesIncrementalRendering")); + if (app->devtools) { + Debug(app, "Enabling devtools"); + enableBoolConfig(config, "developerExtrasEnabled"); + } + app->config = config; + + id manager = msg_reg(config, s("userContentController")); + msg_id_id(manager, s("addScriptMessageHandler:name:"), app->delegate, str("external")); + msg_id_id(manager, s("addScriptMessageHandler:name:"), app->delegate, str("completed")); + msg_id_id(manager, s("addScriptMessageHandler:name:"), app->delegate, str("error")); + app->manager = manager; + + id wkwebview = msg_reg(c("WKWebView"), s("alloc")); + app->wkwebview = wkwebview; + + ((id(*)(id, SEL, CGRect, id))objc_msgSend)(wkwebview, s("initWithFrame:configuration:"), CGRectMake(0, 0, 0, 0), config); + + msg_id(contentView, s("addSubview:"), wkwebview); + msg_int(wkwebview, s("setAutoresizingMask:"), NSViewWidthSizable | NSViewHeightSizable); + CGRect contentViewBounds = GET_BOUNDS(contentView); + ((id(*)(id, SEL, CGRect))objc_msgSend)(wkwebview, s("setFrame:"), contentViewBounds ); + + // Disable damn smart quotes + // Credit: https://stackoverflow.com/a/31640511 + id userDefaults = msg_reg(c("NSUserDefaults"), s("standardUserDefaults")); + ((id(*)(id, SEL, BOOL, id))objc_msgSend)(userDefaults, s("setBool:forKey:"), false, str("NSAutomaticQuoteSubstitutionEnabled")); + + // Setup drag message handler + msg_id_id(manager, s("addScriptMessageHandler:name:"), app->delegate, str("windowDrag")); + // Add mouse event hooks + app->mouseDownMonitor = ((id(*)(id, SEL, int, id (^)(id)))objc_msgSend)(c("NSEvent"), u("addLocalMonitorForEventsMatchingMask:handler:"), NSEventMaskLeftMouseDown, ^(id incomingEvent) { + // Make sure the mouse click was in the window, not the tray + id window = msg_reg(incomingEvent, s("window")); + if (window == app->mainWindow) { + app->mouseEvent = incomingEvent; + } + return incomingEvent; + }); + app->mouseUpMonitor = ((id(*)(id, SEL, int, id (^)(id)))objc_msgSend)(c("NSEvent"), u("addLocalMonitorForEventsMatchingMask:handler:"), NSEventMaskLeftMouseUp, ^(id incomingEvent) { + app->mouseEvent = NULL; + ShowMouse(); + return incomingEvent; + }); + + // Setup context menu message handler + msg_id_id(manager, s("addScriptMessageHandler:name:"), app->delegate, str("contextMenu")); + + // Toolbar + if( app->useToolBar ) { + Debug(app, "Setting Toolbar"); + id toolbar = msg_reg(c("NSToolbar"),s("alloc")); + msg_id(toolbar, s("initWithIdentifier:"), str("wails.toolbar")); + msg_reg(toolbar, s("autorelease")); + + // Separator + if( app->hideToolbarSeparator ) { + msg_bool(toolbar, s("setShowsBaselineSeparator:"), NO); + } + + msg_id(app->mainWindow, s("setToolbar:"), toolbar); + } + + // Fix up resizing + if (app->resizable == 0) { + app->minHeight = app->maxHeight = app->height; + app->minWidth = app->maxWidth = app->width; + } + setMinMaxSize(app); + + // Load HTML + id html = msg_id(c("NSURL"), s("URLWithString:"), str((const char*)assets[0])); + msg_id(wkwebview, s("loadRequest:"), msg_id(c("NSURLRequest"), s("requestWithURL:"), html)); + + Debug(app, "Loading Internal Code"); + // We want to evaluate the internal code plus runtime before the assets + const char *temp = concat(invoke, app->bindings); + const char *internalCode = concat(temp, (const char*)&runtime); + MEMFREE(temp); + + // Add code that sets up the initial state, EG: State Stores. + const char *initialState = getInitialState(app); + temp = concat(internalCode, initialState); + MEMFREE(initialState); + MEMFREE(internalCode); + internalCode = temp; + + // Loop over assets and build up one giant Mother Of All Evals + int index = 1; + while(1) { + // Get next asset pointer + const unsigned char *asset = assets[index]; + + // If we have no more assets, break + if (asset == 0x00) { + break; + } + + temp = concat(internalCode, (const char *)asset); + MEMFREE(internalCode); + internalCode = temp; + index++; + }; + + // Disable context menu if not in debug mode + if( debug != 1 ) { + temp = concat(internalCode, "wails._.DisableDefaultContextMenu();"); + MEMFREE(internalCode); + internalCode = temp; + } + + // class_addMethod(delegateClass, s("applicationWillFinishLaunching:"), (IMP) willFinishLaunching, "@@:@"); + // Include callback after evaluation + temp = concat(internalCode, "webkit.messageHandlers.completed.postMessage(true);"); + MEMFREE(internalCode); + internalCode = temp; + + // const char *viewportScriptString = "var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); meta.setAttribute('initial-scale', '1.0'); meta.setAttribute('maximum-scale', '1.0'); meta.setAttribute('minimum-scale', '1.0'); meta.setAttribute('user-scalable', 'no'); document.getElementsByTagName('head')[0].appendChild(meta);"; + // ExecJS(app, viewportScriptString); + + + // This evaluates the MOAE once the Dom has finished loading + msg_id(manager, + s("addUserScript:"), + ((id(*)(id, SEL, id, int, int))objc_msgSend)(msg_reg(c("WKUserScript"), s("alloc")), + s("initWithSource:injectionTime:forMainFrameOnly:"), + str(internalCode), + 1, + 1)); + + + // Emit theme change event to notify of current system them + emitThemeChange(app); + + // If we want the webview to be transparent... + if( app->webviewIsTranparent == 1 ) { + ((id(*)(id, SEL, id, id))objc_msgSend)(wkwebview, s("setValue:forKey:"), msg_bool(c("NSNumber"), s("numberWithBool:"), 0), str("drawsBackground")); + } + + // If we have an application menu, process it + if( app->applicationMenu != NULL ) { + id menu = GetMenu(app->applicationMenu); + msg_id(msg_reg(c("NSApplication"), s("sharedApplication")), s("setMainMenu:"), menu); + } + + // Setup initial trays + ShowTrayMenusInStore(TrayMenuStoreSingleton); + + // Process dialog icons + processUserDialogIcons(app); + + // Finally call run + Debug(app, "Run called"); + msg_reg(app->application, s("run")); + + DestroyApplication(app); + + MEMFREE(internalCode); +} + +void SetActivationPolicy(struct Application* app, int policy) { + app->activationPolicy = policy; +} + +void HasURLHandlers(struct Application* app) { + app->hasURLHandlers = 1; +} + +// Quit will stop the cocoa application and free up all the memory +// used by the application +void Quit(struct Application *app) { + Debug(app, "Quit Called"); + msg_id(app->application, s("stop:"), NULL); +} + +id createImageFromBase64Data(const char *data, bool isTemplateImage) { + id nsdata = ALLOC("NSData"); + id imageData = ((id(*)(id, SEL, id, int))objc_msgSend)(nsdata, s("initWithBase64EncodedString:options:"), str(data), 0); + + // If it's not valid base64 data, use the broken image + if ( imageData == NULL ) { + imageData = ((id(*)(id, SEL, id, int))objc_msgSend)(nsdata, s("initWithBase64EncodedString:options:"), str(BrokenImage), 0); + } + id result = ALLOC("NSImage"); + msg_reg(result, s("autorelease")); + msg_id(result, s("initWithData:"), imageData); + msg_reg(nsdata, s("release")); + msg_reg(imageData, s("release")); + + if( isTemplateImage ) { + msg_bool(result, s("setTemplate:"), YES); + } + + return result; +} + +void* NewApplication(const char *title, int width, int height, int resizable, int devtools, int fullscreen, int startHidden, int logLevel, int hideWindowOnClose) { + + // Load the tray icons + LoadTrayIcons(); + + // Setup main application struct + struct Application *result = malloc(sizeof(struct Application)); + result->title = title; + result->width = width; + result->height = height; + result->minWidth = 0; + result->minHeight = 0; + result->maxWidth = 0; + result->maxHeight = 0; + result->resizable = resizable; + result->devtools = devtools; + result->fullscreen = fullscreen; + result->maximised = 0; + result->startHidden = startHidden; + result->decorations = 0; + result->logLevel = logLevel; + result->hideWindowOnClose = hideWindowOnClose; + + result->mainWindow = NULL; + result->mouseEvent = NULL; + result->mouseDownMonitor = NULL; + result->mouseUpMonitor = NULL; + + // Features + result->frame = 1; + result->hideTitle = 0; + result->hideTitleBar = 0; + result->fullSizeContent = 0; + result->useToolBar = 0; + result->hideToolbarSeparator = 0; + result->appearance = NULL; + result->WindowIsTranslucent = 0; + + // Window data + result->delegate = NULL; + + // Menu + result->applicationMenu = NULL; + + // Tray + TrayMenuStoreSingleton = NewTrayMenuStore(); + + // Context Menus + result->contextMenuStore = NewContextMenuStore(); + + // Window delegate + result->windowDelegate = NULL; + + // Window Appearance + result->titlebarAppearsTransparent = 0; + result->webviewIsTranparent = 0; + + result->sendMessageToBackend = (ffenestriCallback) messageFromWindowCallback; + + result->shuttingDown = false; + + result->activationPolicy = NSApplicationActivationPolicyRegular; + + result->hasURLHandlers = 0; + + result->startupURL = NULL; + + result->running = false; + + result->pool = msg_reg(c("NSAutoreleasePool"), s("new")); + + return (void*) result; +} + + +#endif diff --git a/v2/internal/ffenestri/ffenestri_darwin.go b/v2/internal/ffenestri/ffenestri_darwin.go new file mode 100644 index 000000000..02d7471b1 --- /dev/null +++ b/v2/internal/ffenestri/ffenestri_darwin.go @@ -0,0 +1,99 @@ +package ffenestri + +/* +#cgo darwin CFLAGS: -DFFENESTRI_DARWIN=1 +#cgo darwin LDFLAGS: -framework WebKit -framework CoreFoundation -lobjc + +#include "ffenestri.h" +#include "ffenestri_darwin.h" + +*/ +import "C" + +func (a *Application) processPlatformSettings() error { + + mac := a.config.Mac + titlebar := mac.TitleBar + + // HideTitle + if titlebar.HideTitle { + C.HideTitle(a.app) + } + + // HideTitleBar + if titlebar.HideTitleBar { + C.HideTitleBar(a.app) + } + + // Full Size Content + if titlebar.FullSizeContent { + C.FullSizeContent(a.app) + } + + // Toolbar + if titlebar.UseToolbar { + C.UseToolbar(a.app) + } + + if titlebar.HideToolbarSeparator { + C.HideToolbarSeparator(a.app) + } + + if titlebar.TitlebarAppearsTransparent { + C.TitlebarAppearsTransparent(a.app) + } + + // Process window Appearance + if mac.Appearance != "" { + C.SetAppearance(a.app, a.string2CString(string(mac.Appearance))) + } + + // Set activation policy + C.SetActivationPolicy(a.app, C.int(mac.ActivationPolicy)) + + // Check if the webview should be transparent + if mac.WebviewIsTransparent { + C.WebviewIsTransparent(a.app) + } + + // Check if window should be translucent + if mac.WindowIsTranslucent { + C.WindowIsTranslucent(a.app) + } + + // Process menu + //applicationMenu := options.GetApplicationMenu(a.config) + applicationMenu := a.menuManager.GetApplicationMenuJSON() + if applicationMenu != "" { + C.SetApplicationMenu(a.app, a.string2CString(applicationMenu)) + } + + // Process tray + trays, err := a.menuManager.GetTrayMenus() + if err != nil { + return err + } + if trays != nil { + for _, tray := range trays { + C.AddTrayMenu(a.app, a.string2CString(tray)) + } + } + + // Process context menus + contextMenus, err := a.menuManager.GetContextMenus() + if err != nil { + return err + } + if contextMenus != nil { + for _, contextMenu := range contextMenus { + C.AddContextMenu(a.app, a.string2CString(contextMenu)) + } + } + + // Process URL Handlers + if a.config.Mac.URLHandlers != nil { + C.HasURLHandlers(a.app) + } + + return nil +} diff --git a/v2/internal/ffenestri/ffenestri_darwin.h b/v2/internal/ffenestri/ffenestri_darwin.h new file mode 100644 index 000000000..fd00338a4 --- /dev/null +++ b/v2/internal/ffenestri/ffenestri_darwin.h @@ -0,0 +1,154 @@ + +#ifndef FFENESTRI_DARWIN_H +#define FFENESTRI_DARWIN_H + + +#define OBJC_OLD_DISPATCH_PROTOTYPES 1 +#include +#include +#include +#include "json.h" +#include "hashmap.h" +#include "stdlib.h" + +typedef struct { + long maj; + long min; + long patch; +} OSVersion; + +// Macros to make it slightly more sane +#define msg objc_msgSend +#define msg_reg ((id(*)(id, SEL))objc_msgSend) +#define msg_id ((id(*)(id, SEL, id))objc_msgSend) +#define msg_id_id ((id(*)(id, SEL, id, id))objc_msgSend) +#define msg_bool ((id(*)(id, SEL, BOOL))objc_msgSend) +#define msg_int ((id(*)(id, SEL, int))objc_msgSend) +#define msg_uint ((id(*)(id, SEL, unsigned int))objc_msgSend) +#define msg_float ((id(*)(id, SEL, float))objc_msgSend) +#define kInternetEventClass 'GURL' +#define kAEGetURL 'GURL' +#define keyDirectObject '----' + +#define c(str) (id)objc_getClass(str) +#define s(str) sel_registerName(str) +#define u(str) sel_getUid(str) +#define str(input) ((id(*)(id, SEL, const char *))objc_msgSend)(c("NSString"), s("stringWithUTF8String:"), input) +#define strunicode(input) ((id(*)(id, SEL, id, unsigned short))objc_msgSend)(c("NSString"), s("stringWithFormat:"), str("%C"), (unsigned short)input) +#define cstr(input) (const char *)msg_reg(input, s("UTF8String")) +#define url(input) msg_id(c("NSURL"), s("fileURLWithPath:"), str(input)) +#define ALLOC(classname) msg_reg(c(classname), s("alloc")) +#define ALLOC_INIT(classname) msg_reg(msg_reg(c(classname), s("alloc")), s("init")) + +#if defined (__aarch64__) +#define GET_FRAME(receiver) ((CGRect(*)(id, SEL))objc_msgSend)(receiver, s("frame")) +#define GET_BOUNDS(receiver) ((CGRect(*)(id, SEL))objc_msgSend)(receiver, s("bounds")) +#define GET_OSVERSION(receiver) ((OSVersion(*)(id, SEL))objc_msgSend)(processInfo, s("operatingSystemVersion")); +#endif + +#if defined (__x86_64__) +#define GET_FRAME(receiver) ((CGRect(*)(id, SEL))objc_msgSend_stret)(receiver, s("frame")) +#define GET_BOUNDS(receiver) ((CGRect(*)(id, SEL))objc_msgSend_stret)(receiver, s("bounds")) +#define GET_OSVERSION(receiver) ((OSVersion(*)(id, SEL))objc_msgSend_stret)(processInfo, s("operatingSystemVersion")); +#endif + +#define GET_BACKINGSCALEFACTOR(receiver) ((CGFloat(*)(id, SEL))objc_msgSend)(receiver, s("backingScaleFactor")) + +#define ON_MAIN_THREAD(str) dispatch( ^{ str; } ) +#define MAIN_WINDOW_CALL(str) msg_reg(app->mainWindow, s((str))) + +#define NSBackingStoreBuffered 2 + +#define NSWindowStyleMaskBorderless 0 +#define NSWindowStyleMaskTitled 1 +#define NSWindowStyleMaskClosable 2 +#define NSWindowStyleMaskMiniaturizable 4 +#define NSWindowStyleMaskResizable 8 +#define NSWindowStyleMaskFullscreen 1 << 14 + +#define NSVisualEffectMaterialWindowBackground 12 +#define NSVisualEffectBlendingModeBehindWindow 0 +#define NSVisualEffectStateFollowsWindowActiveState 0 +#define NSVisualEffectStateActive 1 +#define NSVisualEffectStateInactive 2 + +#define NSViewWidthSizable 2 +#define NSViewHeightSizable 16 + +#define NSWindowBelow -1 +#define NSWindowAbove 1 + +#define NSSquareStatusItemLength -2.0 +#define NSVariableStatusItemLength -1.0 + +#define NSWindowTitleHidden 1 +#define NSWindowStyleMaskFullSizeContentView 1 << 15 + +#define NSEventModifierFlagCommand 1 << 20 +#define NSEventModifierFlagOption 1 << 19 +#define NSEventModifierFlagControl 1 << 18 +#define NSEventModifierFlagShift 1 << 17 + +#define NSControlStateValueMixed -1 +#define NSControlStateValueOff 0 +#define NSControlStateValueOn 1 + +#define NSApplicationActivationPolicyRegular 0 +#define NSApplicationActivationPolicyAccessory 1 +#define NSApplicationActivationPolicyProhibited 2 + +// Unbelievably, if the user swaps their button preference +// then right buttons are reported as left buttons +#define NSEventMaskLeftMouseDown 1 << 1 +#define NSEventMaskLeftMouseUp 1 << 2 +#define NSEventMaskRightMouseDown 1 << 3 +#define NSEventMaskRightMouseUp 1 << 4 + +#define NSEventTypeLeftMouseDown 1 +#define NSEventTypeLeftMouseUp 2 +#define NSEventTypeRightMouseDown 3 +#define NSEventTypeRightMouseUp 4 + +#define NSNoImage 0 +#define NSImageOnly 1 +#define NSImageLeft 2 +#define NSImageRight 3 +#define NSImageBelow 4 +#define NSImageAbove 5 +#define NSImageOverlaps 6 + +#define NSAlertStyleWarning 0 +#define NSAlertStyleInformational 1 +#define NSAlertStyleCritical 2 + +#define NSAlertFirstButtonReturn 1000 +#define NSAlertSecondButtonReturn 1001 +#define NSAlertThirdButtonReturn 1002 + +#define BrokenImage "iVBORw0KGgoAAAANSUhEUgAAABAAAAASCAMAAABl5a5YAAABj1BMVEWopan///+koqSWk5P9/v3///////////+AgACMiovz8/PB0fG9z+3i4+WysbGBfX1Erh80rACLiYqBxolEsDhHlDEbqQDDx+CNho7W1tj4+/bw+O3P5Mn4/f/W1tbK6sX////b2dn////////////8/Pz6+vro6Ojj4+P////G1PL////EzNydmp2cmZnd3eDF1PHs8v/o8P/Q3vrS3vfE0vCdmpqZkpr19/3N2vXI1vPH1fOgnqDg6frP3PbCytvHx8irqq6HhIZtuGtjnlZetU1Xs0NWskBNsi7w9v/d6P7w9P3S4Pzr8Pvl7PrY5PrU4PjQ3fjD1Ozo6Om30NjGzNi7ubm34K+UxKmbnaWXlJeUjpSPi4tppF1TtjxSsTf2+f7L2PTr7e3H2+3V7+q+0uXg4OPg4eLR1uG7z+Hg4ODGzODV2N7V1trP5dmxzs65vcfFxMWq0cKxxr+/vr+0s7apxbWaxrCv2qao05+dlp2Uuo2Dn4F8vIB6xnyAoHmAym9zqGpctENLryNFsgoblJpnAAAAKnRSTlP+hP7+5ZRmYgL+/f39/f39/f38/Pz8/Pv69+7j083My8GocnBPTTMWEgjxeITOAAABEklEQVQY0y3KZXuCYBiG4ceYuu7u3nyVAaKOMBBQ7O5Yd3f3fvheDnd9u8/jBkGwNxP6sjOWVQvY/ftrzfT6bd3yEhCnYZqiaYoKiwX/gXkFiHySTcUTLJMsZ9v8nQvgssWYOEKedKpcOO6CUXD5IlGEY5hLUbyDAAZ6HRf1bnkoavOsFQibg+Q4nuNYL+ON5PHD5nBaraRVyxnzGf6BJzUi2QQCQgMyk8tleL7dg1owpJ17D5IkvV100EingeOopPyo6vfAuXF+9hbDTknZCIaUoeK4efKwG4iT6xDewd7imGlid7gGwv37b6Oh9jwaTdOf/Tc1qH7UZVmuP6G5qZfBr9cAGNy4KiDd4tXIs7tS+QO9aUKvPAIKuQAAAABJRU5ErkJggg==" + +struct Application; +int releaseNSObject(void *const context, struct hashmap_element_s *const e); +void TitlebarAppearsTransparent(struct Application* app); +void HideTitle(struct Application* app); +void HideTitleBar(struct Application* app); +void FullSizeContent(struct Application* app); +void UseToolbar(struct Application* app); +void HideToolbarSeparator(struct Application* app); +void DisableFrame(struct Application* app); +void SetAppearance(struct Application* app, const char *); +void WebviewIsTransparent(struct Application* app); +void WindowIsTranslucent(struct Application* app); +void SetTray(struct Application* app, const char *, const char *, const char *); +//void SetContextMenus(struct Application* app, const char *); +void AddTrayMenu(struct Application* app, const char *); + +void SetActivationPolicy(struct Application* app, int policy); + +void* lookupStringConstant(id constantName); + +void HasURLHandlers(struct Application* app); + +id createImageFromBase64Data(const char *data, bool isTemplateImage); + +#endif \ No newline at end of file diff --git a/v2/internal/ffenestri/ffenestri_linux.c b/v2/internal/ffenestri/ffenestri_linux.c new file mode 100644 index 000000000..ab6b6032b --- /dev/null +++ b/v2/internal/ffenestri/ffenestri_linux.c @@ -0,0 +1,995 @@ + +#ifndef __FFENESTRI_LINUX_H__ +#define __FFENESTRI_LINUX_H__ + +#include "common.h" +#include "gtk/gtk.h" +#include "webkit2/webkit2.h" +#include +#include +#include +#include +#include + +// References to assets +extern const unsigned char runtime; + +#include "icon.h" +#include "assets.h" + +// Constants +#define PRIMARY_MOUSE_BUTTON 1 +#define MIDDLE_MOUSE_BUTTON 2 +#define SECONDARY_MOUSE_BUTTON 3 + +// MAIN DEBUG FLAG +int debug; + +// Debug works like sprintf but mutes if the global debug flag is true +// Credit: https://stackoverflow.com/a/20639708 +void Debug(char *message, ...) +{ + if (debug) + { + char *temp = concat("TRACE | Ffenestri (C) | ", message); + message = concat(temp, "\n"); + free(temp); + va_list args; + va_start(args, message); + vprintf(message, args); + free(message); + va_end(args); + } +} + +extern void messageFromWindowCallback(const char *); +typedef void (*ffenestriCallback)(const char *); + +struct Application +{ + + // Gtk Data + GtkApplication *application; + GtkWindow *mainWindow; + GtkWidget *webView; + int signalInvoke; + int signalWindowDrag; + int signalButtonPressed; + int signalButtonReleased; + int signalLoadChanged; + + // Saves the events for the drag mouse button + GdkEventButton *dragButtonEvent; + + // The number of the default drag button + int dragButton; + + // Window Data + const char *title; + char *id; + int width; + int height; + int resizable; + int devtools; + int startHidden; + int fullscreen; + int minWidth; + int minHeight; + int maxWidth; + int maxHeight; + int frame; + + // User Data + char *HTML; + + // Callback + ffenestriCallback sendMessageToBackend; + + // Bindings + const char *bindings; + + // Lock - used for sync operations (Should we be using g_mutex?) + int lock; +}; + +void *NewApplication(const char *title, int width, int height, int resizable, int devtools, int fullscreen, int startHidden) +{ + // Setup main application struct + struct Application *result = malloc(sizeof(struct Application)); + result->title = title; + result->width = width; + result->height = height; + result->resizable = resizable; + result->devtools = devtools; + result->fullscreen = fullscreen; + result->minWidth = 0; + result->minHeight = 0; + result->maxWidth = 0; + result->maxHeight = 0; + result->frame = 1; + result->startHidden = startHidden; + + // Default drag button is PRIMARY + result->dragButton = PRIMARY_MOUSE_BUTTON; + + result->sendMessageToBackend = (ffenestriCallback)messageFromWindowCallback; + + // Create a unique ID based on the current unix timestamp + char temp[11]; + sprintf(&temp[0], "%d", (int)time(NULL)); + result->id = concat("wails.app", &temp[0]); + + // Create the main GTK application + GApplicationFlags flags = G_APPLICATION_FLAGS_NONE; + result->application = gtk_application_new(result->id, flags); + + // Return the application struct + return (void *)result; +} + +void DestroyApplication(struct Application *app) +{ + Debug("Destroying Application"); + + g_application_quit(G_APPLICATION(app->application)); + + // Release the GTK ID string + if (app->id != NULL) + { + free(app->id); + app->id = NULL; + } + else + { + Debug("Almost a double free for app->id"); + } + + // Free the bindings + if (app->bindings != NULL) + { + free((void *)app->bindings); + app->bindings = NULL; + } + else + { + Debug("Almost a double free for app->bindings"); + } + + // Disconnect signal handlers + WebKitUserContentManager *manager = webkit_web_view_get_user_content_manager((WebKitWebView *)app->webView); + g_signal_handler_disconnect(manager, app->signalInvoke); + if( app->frame == 0) { + g_signal_handler_disconnect(manager, app->signalWindowDrag); + g_signal_handler_disconnect(app->webView, app->signalButtonPressed); + g_signal_handler_disconnect(app->webView, app->signalButtonReleased); + } + g_signal_handler_disconnect(app->webView, app->signalLoadChanged); + + // Release the main GTK Application + if (app->application != NULL) + { + g_object_unref(app->application); + app->application = NULL; + } + else + { + Debug("Almost a double free for app->application"); + } + Debug("Finished Destroying Application"); +} + +// Quit will stop the gtk application and free up all the memory +// used by the application +void Quit(struct Application *app) +{ + Debug("Quit Called"); + gtk_window_close((GtkWindow *)app->mainWindow); + g_application_quit((GApplication *)app->application); + DestroyApplication(app); +} + +// SetTitle sets the main window title to the given string +void SetTitle(struct Application *app, const char *title) +{ + gtk_window_set_title(app->mainWindow, title); +} + +// Fullscreen sets the main window to be fullscreen +void Fullscreen(struct Application *app) +{ + gtk_window_fullscreen(app->mainWindow); +} + +// UnFullscreen resets the main window after a fullscreen +void UnFullscreen(struct Application *app) +{ + gtk_window_unfullscreen(app->mainWindow); +} + +void setMinMaxSize(struct Application *app) +{ + GdkGeometry size; + size.min_width = size.min_height = size.max_width = size.max_height = 0; + int flags = 0; + if (app->maxHeight > 0 && app->maxWidth > 0) + { + size.max_height = app->maxHeight; + size.max_width = app->maxWidth; + flags |= GDK_HINT_MAX_SIZE; + } + if (app->minHeight > 0 && app->minWidth > 0) + { + size.min_height = app->minHeight; + size.min_width = app->minWidth; + flags |= GDK_HINT_MIN_SIZE; + } + gtk_window_set_geometry_hints(app->mainWindow, NULL, &size, flags); +} + +char *fileDialogInternal(struct Application *app, GtkFileChooserAction chooserAction, char **args) { + GtkFileChooserNative *native; + GtkFileChooserAction action = chooserAction; + gint res; + char *filename; + + char *title = args[0]; + char *filter = args[1]; + + native = gtk_file_chooser_native_new(title, + app->mainWindow, + action, + "_Open", + "_Cancel"); + + GtkFileChooser *chooser = GTK_FILE_CHOOSER(native); + + // If we have filters, process them + if (filter[0] != '\0') { + GtkFileFilter *file_filter = gtk_file_filter_new(); + gchar **filters = g_strsplit(filter, ",", -1); + gint i; + for(i = 0; filters && filters[i]; i++) { + gtk_file_filter_add_pattern(file_filter, filters[i]); + // Debug("Adding filter pattern: %s\n", filters[i]); + } + gtk_file_filter_set_name(file_filter, filter); + gtk_file_chooser_add_filter(chooser, file_filter); + g_strfreev(filters); + } + + res = gtk_native_dialog_run(GTK_NATIVE_DIALOG(native)); + if (res == GTK_RESPONSE_ACCEPT) + { + filename = gtk_file_chooser_get_filename(chooser); + } + + g_object_unref(native); + + return filename; +} + +// openFileDialogInternal opens a dialog to select a file +// NOTE: The result is a string that will need to be freed! +char *openFileDialogInternal(struct Application *app, char **args) +{ + return fileDialogInternal(app, GTK_FILE_CHOOSER_ACTION_OPEN, args); +} + +// saveFileDialogInternal opens a dialog to select a file +// NOTE: The result is a string that will need to be freed! +char *saveFileDialogInternal(struct Application *app, char **args) +{ + return fileDialogInternal(app, GTK_FILE_CHOOSER_ACTION_SAVE, args); +} + + +// openDirectoryDialogInternal opens a dialog to select a directory +// NOTE: The result is a string that will need to be freed! +char *openDirectoryDialogInternal(struct Application *app, char **args) +{ + return fileDialogInternal(app, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, args); +} + +void SetMinWindowSize(struct Application *app, int minWidth, int minHeight) +{ + app->minWidth = minWidth; + app->minHeight = minHeight; +} + +void SetMaxWindowSize(struct Application *app, int maxWidth, int maxHeight) +{ + app->maxWidth = maxWidth; + app->maxHeight = maxHeight; +} + +// SetColour sets the colour of the webview to the given colour string +void SetColour(struct Application *app, int red, int green, int blue, int alpha) +{ +// GdkRGBA rgba; +// rgba. +// gboolean result = gdk_rgba_parse(&rgba, colourString); +// if (result == FALSE) +// { +// return 0; +// } +// // Debug("Setting webview colour to: %s", colourString); +// webkit_web_view_get_background_color((WebKitWebView *)(app->webView), &rgba); +} + +// DisableFrame disables the window frame +void DisableFrame(struct Application *app) +{ + app->frame = 0; +} + +void syncCallback(GObject *source_object, + GAsyncResult *res, + void *data) +{ + struct Application *app = (struct Application *)data; + app->lock = 0; +} + +void syncEval(struct Application *app, const gchar *script) +{ + + WebKitWebView *webView = (WebKitWebView *)(app->webView); + + // wait for lock to free + while (app->lock == 1) + { + g_main_context_iteration(0, true); + } + // Set lock + app->lock = 1; + + webkit_web_view_run_javascript( + webView, + script, + NULL, syncCallback, (void*)app); + + while (app->lock == 1) + { + g_main_context_iteration(0, true); + } +} + +void asyncEval(WebKitWebView *webView, const gchar *script) +{ + webkit_web_view_run_javascript( + webView, + script, + NULL, NULL, NULL); +} + +typedef void (*dispatchMethod)(struct Application *app, void *); + +struct dispatchData +{ + struct Application *app; + dispatchMethod method; + void *args; +}; + +gboolean executeMethod(gpointer data) +{ + struct dispatchData *d = (struct dispatchData *)data; + (d->method)(d->app, d->args); + g_free(d); + return FALSE; +} + +void ExecJS(struct Application *app, char *js) +{ + struct dispatchData *data = (struct dispatchData *)g_new(struct dispatchData, 1); + data->method = (dispatchMethod)syncEval; + data->args = js; + data->app = app; + + gdk_threads_add_idle(executeMethod, data); +} + +typedef char *(*dialogMethod)(struct Application *app, void *); + +struct dialogCall +{ + struct Application *app; + dialogMethod method; + void *args; + void *filter; + char *result; + int done; +}; + +gboolean executeMethodWithReturn(gpointer data) +{ + struct dialogCall *d = (struct dialogCall *)data; + + d->result = (d->method)(d->app, d->args); + d->done = 1; + return FALSE; +} + +char *OpenFileDialog(struct Application *app, char *title, char *filter) +{ + struct dialogCall *data = (struct dialogCall *)g_new(struct dialogCall, 1); + data->result = NULL; + data->done = 0; + data->method = (dialogMethod)openFileDialogInternal; + const char* dialogArgs[]={ title, filter }; + data->args = dialogArgs; + data->app = app; + + gdk_threads_add_idle(executeMethodWithReturn, data); + + while (data->done == 0) + { + usleep(100000); + } + g_free(data); + return data->result; +} + +char *SaveFileDialog(struct Application *app, char *title, char *filter) +{ + struct dialogCall *data = (struct dialogCall *)g_new(struct dialogCall, 1); + data->result = NULL; + data->done = 0; + data->method = (dialogMethod)saveFileDialogInternal; + const char* dialogArgs[]={ title, filter }; + data->args = dialogArgs; + data->app = app; + + gdk_threads_add_idle(executeMethodWithReturn, data); + + while (data->done == 0) + { + usleep(100000); + } + Debug("Dialog done"); + Debug("Result = %s\n", data->result); + + g_free(data); + // Fingers crossed this wasn't freed by g_free above + return data->result; +} + +char *OpenDirectoryDialog(struct Application *app, char *title, char *filter) +{ + struct dialogCall *data = (struct dialogCall *)g_new(struct dialogCall, 1); + data->result = NULL; + data->done = 0; + data->method = (dialogMethod)openDirectoryDialogInternal; + const char* dialogArgs[]={ title, filter }; + data->args = dialogArgs; + data->app = app; + + gdk_threads_add_idle(executeMethodWithReturn, data); + + while (data->done == 0) + { + usleep(100000); + } + Debug("Directory Dialog done"); + Debug("Result = %s\n", data->result); + g_free(data); + // Fingers crossed this wasn't freed by g_free above + return data->result; +} + +// Sets the icon to the XPM stored in icon +void setIcon(struct Application *app) +{ + GdkPixbuf *appIcon = gdk_pixbuf_new_from_xpm_data((const char **)icon); + gtk_window_set_icon(app->mainWindow, appIcon); +} + +static void load_finished_cb(WebKitWebView *webView, + WebKitLoadEvent load_event, + struct Application *app) +{ + switch (load_event) + { + // case WEBKIT_LOAD_STARTED: + // /* New load, we have now a provisional URI */ + // // printf("Start downloading %s\n", webkit_web_view_get_uri(web_view)); + // /* Here we could start a spinner or update the + // * location bar with the provisional URI */ + // break; + // case WEBKIT_LOAD_REDIRECTED: + // // printf("Redirected to: %s\n", webkit_web_view_get_uri(web_view)); + // break; + // case WEBKIT_LOAD_COMMITTED: + // /* The load is being performed. Current URI is + // * the final one and it won't change unless a new + // * load is requested or a navigation within the + // * same page is performed */ + // // printf("Loading: %s\n", webkit_web_view_get_uri(web_view)); + // break; + case WEBKIT_LOAD_FINISHED: + /* Load finished, we can now stop the spinner */ + // printf("Finished loading: %s\n", webkit_web_view_get_uri(web_view)); + + // Bindings + Debug("Binding Methods"); + syncEval(app, app->bindings); + + // Setup IPC commands + Debug("Setting up IPC methods"); + const char *invoke = "window.wailsInvoke=function(message){window.webkit.messageHandlers.external.postMessage(message);};window.wailsDrag=function(message){window.webkit.messageHandlers.windowDrag.postMessage(message);};window.wailsContextMenuMessage=function(message){window.webkit.messageHandlers.contextMenu.postMessage(message);};"; + syncEval(app, invoke); + + // Runtime + Debug("Setting up Wails runtime"); + syncEval(app, &runtime); + + // Loop over assets + int index = 1; + while (1) + { + // Get next asset pointer + const char *asset = assets[index]; + + // If we have no more assets, break + if (asset == 0x00) + { + break; + } + + // sync eval the asset + syncEval(app, asset); + index++; + }; + + // Set the icon + setIcon(app); + + // Setup fullscreen + if (app->fullscreen) + { + Debug("Going fullscreen"); + Fullscreen(app); + } + + // Setup resize + gtk_window_resize(GTK_WINDOW(app->mainWindow), app->width, app->height); + + if (app->resizable) + { + gtk_window_set_default_size(GTK_WINDOW(app->mainWindow), app->width, app->height); + } + else + { + gtk_widget_set_size_request(GTK_WIDGET(app->mainWindow), app->width, app->height); + gtk_window_resize(GTK_WINDOW(app->mainWindow), app->width, app->height); + // Fix the min/max to the window size for good measure + app->minHeight = app->maxHeight = app->height; + app->minWidth = app->maxWidth = app->width; + } + gtk_window_set_resizable(GTK_WINDOW(app->mainWindow), app->resizable ? TRUE : FALSE); + setMinMaxSize(app); + + // Centre by default + gtk_window_set_position(app->mainWindow, GTK_WIN_POS_CENTER); + + // Show window and focus + if( app->startHidden == 0) { + gtk_widget_show_all(GTK_WIDGET(app->mainWindow)); + gtk_widget_grab_focus(app->webView); + } + break; + } +} + +static gboolean disable_context_menu_cb( + WebKitWebView *web_view, + WebKitContextMenu *context_menu, + GdkEvent *event, + WebKitHitTestResult *hit_test_result, + gpointer user_data) +{ + return TRUE; +} + +static void printEvent(const char *message, GdkEventButton *event) +{ + Debug("%s: [button:%d] [x:%f] [y:%f] [time:%d]", + message, + event->button, + event->x_root, + event->y_root, + event->time); +} + + +static void dragWindow(WebKitUserContentManager *contentManager, + WebKitJavascriptResult *result, + struct Application *app) +{ + // If we get this message erroneously, ignore + if (app->dragButtonEvent == NULL) + { + return; + } + + // Ignore non-toplevel widgets + GtkWidget *window = gtk_widget_get_toplevel(GTK_WIDGET(app->webView)); + if (!GTK_IS_WINDOW(window)) + { + return; + } + + // Initiate the drag + printEvent("Starting drag with event", app->dragButtonEvent); + + gtk_window_begin_move_drag(app->mainWindow, + app->dragButton, + app->dragButtonEvent->x_root, + app->dragButtonEvent->y_root, + app->dragButtonEvent->time); + // Clear the event + app->dragButtonEvent = NULL; + + return; +} + +gboolean buttonPress(GtkWidget *widget, GdkEventButton *event, struct Application *app) +{ + if (event->type == GDK_BUTTON_PRESS && event->button == app->dragButton) + { + app->dragButtonEvent = event; + } + return FALSE; +} + +gboolean buttonRelease(GtkWidget *widget, GdkEventButton *event, struct Application *app) +{ + if (event->type == GDK_BUTTON_RELEASE && event->button == app->dragButton) + { + app->dragButtonEvent = NULL; + } + return FALSE; +} + +static void sendMessageToBackend(WebKitUserContentManager *contentManager, + WebKitJavascriptResult *result, + struct Application *app) +{ +#if WEBKIT_MAJOR_VERSION >= 2 && WEBKIT_MINOR_VERSION >= 22 + JSCValue *value = webkit_javascript_result_get_js_value(result); + char *message = jsc_value_to_string(value); +#else + JSGlobalContextRef context = webkit_javascript_result_get_global_context(result); + JSValueRef value = webkit_javascript_result_get_value(result); + JSStringRef js = JSValueToStringCopy(context, value, NULL); + size_t messageSize = JSStringGetMaximumUTF8CStringSize(js); + char *message = g_new(char, messageSize); + JSStringGetUTF8CString(js, message, messageSize); + JSStringRelease(js); +#endif + app->sendMessageToBackend(message); + g_free(message); +} + +void SetDebug(struct Application *app, int flag) +{ + debug = flag; +} + +// getCurrentMonitorGeometry gets the geometry of the monitor +// that the window is mostly on. +GdkRectangle getCurrentMonitorGeometry(GtkWindow *window) { + // Get the monitor that the window is currently on + GdkDisplay *display = gtk_widget_get_display(GTK_WIDGET(window)); + GdkWindow *gdk_window = gtk_widget_get_window(GTK_WIDGET(window)); + GdkMonitor *monitor = gdk_display_get_monitor_at_window (display, gdk_window); + + // Get the geometry of the monitor + GdkRectangle result; + gdk_monitor_get_geometry (monitor,&result); + + return result; +} + +/******************* + * Window Position * + *******************/ + +// Position holds an x/y corrdinate +struct Position { + int x; + int y; +}; + +// Internal call for setting the position of the window. +void setPositionInternal(struct Application *app, struct Position *pos) { + + // Get the monitor geometry + GdkRectangle m = getCurrentMonitorGeometry(app->mainWindow); + + // Move the window relative to the monitor + gtk_window_move(app->mainWindow, m.x + pos->x, m.y + pos->y); + + // Free memory + free(pos); +} + +// SetPosition sets the position of the window to the given x/y +// coordinates. The x/y values are relative to the monitor +// the window is mostly on. +void SetPosition(struct Application *app, int x, int y) { + struct dispatchData *data = (struct dispatchData *)g_new(struct dispatchData, 1); + data->method = (dispatchMethod)setPositionInternal; + struct Position *pos = malloc(sizeof(struct Position)); + pos->x = x; + pos->y = y; + data->args = pos; + data->app = app; + + gdk_threads_add_idle(executeMethod, data); +} + +/*************** + * Window Size * + ***************/ + +// Size holds a width/height +struct Size { + int width; + int height; +}; + +// Internal call for setting the size of the window. +void setSizeInternal(struct Application *app, struct Size *size) { + gtk_window_resize(app->mainWindow, size->width, size->height); + free(size); +} + +// SetSize sets the size of the window to the given width/height +void SetSize(struct Application *app, int width, int height) { + struct dispatchData *data = (struct dispatchData *)g_new(struct dispatchData, 1); + data->method = (dispatchMethod)setSizeInternal; + struct Size *size = malloc(sizeof(struct Size)); + size->width = width; + size->height = height; + data->args = size; + data->app = app; + + gdk_threads_add_idle(executeMethod, data); +} + + +// centerInternal will center the main window on the monitor it is mostly in +void centerInternal(struct Application *app) +{ + // Get the geometry of the monitor + GdkRectangle m = getCurrentMonitorGeometry(app->mainWindow); + + // Get the window width/height + int windowWidth, windowHeight; + gtk_window_get_size(app->mainWindow, &windowWidth, &windowHeight); + + // Place the window at the center of the monitor + gtk_window_move(app->mainWindow, ((m.width - windowWidth) / 2) + m.x, ((m.height - windowHeight) / 2) + m.y); +} + +// Center the window +void Center(struct Application *app) { + + // Setup a call to centerInternal on the main thread + struct dispatchData *data = (struct dispatchData *)g_new(struct dispatchData, 1); + data->method = (dispatchMethod)centerInternal; + data->app = app; + + // Add call to main thread + gdk_threads_add_idle(executeMethod, data); +} + +// hideInternal hides the main window +void hideInternal(struct Application *app) { + gtk_widget_hide (GTK_WIDGET(app->mainWindow)); +} + +// Hide places the hideInternal method onto the main thread for execution +void Hide(struct Application *app) { + + // Setup a call to hideInternal on the main thread + struct dispatchData *data = (struct dispatchData *)g_new(struct dispatchData, 1); + data->method = (dispatchMethod)hideInternal; + data->app = app; + + // Add call to main thread + gdk_threads_add_idle(executeMethod, data); +} + +// showInternal shows the main window +void showInternal(struct Application *app) { + gtk_widget_show_all(GTK_WIDGET(app->mainWindow)); + gtk_widget_grab_focus(app->webView); +} + +// Show places the showInternal method onto the main thread for execution +void Show(struct Application *app) { + struct dispatchData *data = (struct dispatchData *)g_new(struct dispatchData, 1); + data->method = (dispatchMethod)showInternal; + data->app = app; + + gdk_threads_add_idle(executeMethod, data); +} + + +// maximiseInternal maximises the main window +void maximiseInternal(struct Application *app) { + gtk_window_maximize(GTK_WINDOW(app->mainWindow)); +} + +// Maximise places the maximiseInternal method onto the main thread for execution +void Maximise(struct Application *app) { + + // Setup a call to maximiseInternal on the main thread + struct dispatchData *data = (struct dispatchData *)g_new(struct dispatchData, 1); + data->method = (dispatchMethod)maximiseInternal; + data->app = app; + + // Add call to main thread + gdk_threads_add_idle(executeMethod, data); +} + +// unmaximiseInternal unmaximises the main window +void unmaximiseInternal(struct Application *app) { + gtk_window_unmaximize(GTK_WINDOW(app->mainWindow)); +} + +// Unmaximise places the unmaximiseInternal method onto the main thread for execution +void Unmaximise(struct Application *app) { + + // Setup a call to unmaximiseInternal on the main thread + struct dispatchData *data = (struct dispatchData *)g_new(struct dispatchData, 1); + data->method = (dispatchMethod)unmaximiseInternal; + data->app = app; + + // Add call to main thread + gdk_threads_add_idle(executeMethod, data); +} + + +void DarkModeEnabled(struct Application* app, char *callbackID) {} +void SetApplicationMenu(struct Application* app, const char *menuJSON) {} +void AddTrayMenu(struct Application* app, const char *menuTrayJSON) {} +void SetTrayMenu(struct Application* app, const char *menuTrayJSON) {} +void DeleteTrayMenuByID(struct Application* app, const char *id) {} +void UpdateTrayMenuLabel(struct Application* app, const char* JSON) {} +void AddContextMenu(struct Application* app, char *contextMenuJSON) {} +void UpdateContextMenu(struct Application* app, char *contextMenuJSON) {} +void WebviewIsTransparent(struct Application* app) {} +void WindowIsTranslucent(struct Application* app) {} +void OpenDialog(struct Application* app, char *callbackID, char *title, char *filters, char *defaultFilename, char *defaultDir, int allowFiles, int allowDirs, int allowMultiple, int showHiddenFiles, int canCreateDirectories, int resolvesAliases, int treatPackagesAsDirectories) {} +void SaveDialog(struct Application* app, char *callbackID, char *title, char *filters, char *defaultFilename, char *defaultDir, int showHiddenFiles, int canCreateDirectories, int treatPackagesAsDirectories) {} +void MessageDialog(struct Application* app, char *callbackID, char *type, char *title, char *message, char *icon, char *button1, char *button2, char *button3, char *button4, char *defaultButton, char *cancelButton) {} + + +// minimiseInternal minimises the main window +void minimiseInternal(struct Application *app) { + gtk_window_iconify(app->mainWindow); +} + +// Minimise places the minimiseInternal method onto the main thread for execution +void Minimise(struct Application *app) { + + // Setup a call to minimiseInternal on the main thread + struct dispatchData *data = (struct dispatchData *)g_new(struct dispatchData, 1); + data->method = (dispatchMethod)minimiseInternal; + data->app = app; + + // Add call to main thread + gdk_threads_add_idle(executeMethod, data); +} + +// unminimiseInternal unminimises the main window +void unminimiseInternal(struct Application *app) { + gtk_window_present(app->mainWindow); +} + +// Unminimise places the unminimiseInternal method onto the main thread for execution +void Unminimise(struct Application *app) { + + // Setup a call to unminimiseInternal on the main thread + struct dispatchData *data = (struct dispatchData *)g_new(struct dispatchData, 1); + data->method = (dispatchMethod)unminimiseInternal; + data->app = app; + + // Add call to main thread + gdk_threads_add_idle(executeMethod, data); +} + + +void SetBindings(struct Application *app, const char *bindings) +{ + const char *temp = concat("window.wailsbindings = \"", bindings); + const char *jscall = concat(temp, "\";"); + free((void *)temp); + app->bindings = jscall; +} + +// This is called when the close button on the window is pressed +gboolean close_button_pressed(GtkWidget *widget, + GdkEvent *event, + struct Application *app) +{ + app->sendMessageToBackend("WC"); // Window Close + return TRUE; +} + +static void setupWindow(struct Application *app) +{ + + // Create the window + GtkWidget *mainWindow = gtk_application_window_new(app->application); + // Save reference + app->mainWindow = GTK_WINDOW(mainWindow); + + // Setup frame + gtk_window_set_decorated((GtkWindow *)mainWindow, app->frame); + + // Setup title + gtk_window_set_title(GTK_WINDOW(mainWindow), app->title); + + // Setup script handler + WebKitUserContentManager *contentManager = webkit_user_content_manager_new(); + + // Setup the invoke handler + webkit_user_content_manager_register_script_message_handler(contentManager, "external"); + app->signalInvoke = g_signal_connect(contentManager, "script-message-received::external", G_CALLBACK(sendMessageToBackend), app); + + // Setup the window drag handler if this is a frameless app + if ( app->frame == 0 ) { + webkit_user_content_manager_register_script_message_handler(contentManager, "windowDrag"); + app->signalWindowDrag = g_signal_connect(contentManager, "script-message-received::windowDrag", G_CALLBACK(dragWindow), app); + // Setup the mouse handlers + app->signalButtonPressed = g_signal_connect(app->webView, "button-press-event", G_CALLBACK(buttonPress), app); + app->signalButtonReleased = g_signal_connect(app->webView, "button-release-event", G_CALLBACK(buttonRelease), app); + } + GtkWidget *webView = webkit_web_view_new_with_user_content_manager(contentManager); + + // Save reference + app->webView = webView; + + // Add the webview to the window + gtk_container_add(GTK_CONTAINER(mainWindow), webView); + + + // Load default HTML + app->signalLoadChanged = g_signal_connect(G_OBJECT(webView), "load-changed", G_CALLBACK(load_finished_cb), app); + + // Load the user's HTML + // assets[0] is the HTML because the asset array is bundled like that by convention + webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webView), assets[0]); + + // Check if we want to enable the dev tools + if (app->devtools) + { + WebKitSettings *settings = webkit_web_view_get_settings(WEBKIT_WEB_VIEW(webView)); + // webkit_settings_set_enable_write_console_messages_to_stdout(settings, true); + webkit_settings_set_enable_developer_extras(settings, true); + } + else + { + g_signal_connect(G_OBJECT(webView), "context-menu", G_CALLBACK(disable_context_menu_cb), app); + } + + // Listen for close button signal + g_signal_connect(GTK_WIDGET(mainWindow), "delete-event", G_CALLBACK(close_button_pressed), app); +} + +static void activate(GtkApplication* _, struct Application *app) +{ + setupWindow(app); +} + +void Run(struct Application *app, int argc, char **argv) +{ + g_signal_connect(app->application, "activate", G_CALLBACK(activate), app); + g_application_run(G_APPLICATION(app->application), argc, argv); +} + +#endif diff --git a/v2/internal/ffenestri/ffenestri_linux.go b/v2/internal/ffenestri/ffenestri_linux.go new file mode 100644 index 000000000..ca7abe7a1 --- /dev/null +++ b/v2/internal/ffenestri/ffenestri_linux.go @@ -0,0 +1,17 @@ +package ffenestri + +/* +#cgo linux CFLAGS: -DFFENESTRI_LINUX=1 +#cgo linux pkg-config: gtk+-3.0 webkit2gtk-4.0 + + +#include "ffenestri.h" +#include "ffenestri_linux.h" + +*/ +import "C" + +func (a *Application) processPlatformSettings() error { + + return nil +} diff --git a/v2/internal/ffenestri/ffenestri_linux.h b/v2/internal/ffenestri/ffenestri_linux.h new file mode 100644 index 000000000..26902d334 --- /dev/null +++ b/v2/internal/ffenestri/ffenestri_linux.h @@ -0,0 +1,6 @@ + +#ifndef FFENESTRI_LINUX_H +#define FFENESTRI_LINUX_H + + +#endif \ No newline at end of file diff --git a/v2/internal/ffenestri/ffenestri_windows.cpp b/v2/internal/ffenestri/ffenestri_windows.cpp new file mode 100644 index 000000000..91500774f --- /dev/null +++ b/v2/internal/ffenestri/ffenestri_windows.cpp @@ -0,0 +1,906 @@ +// Some code may be inspired by or directly used from Webview (c) zserge. +// License included in README.md + +#include "ffenestri_windows.h" +#include "shellscalingapi.h" +#include "wv2ComHandler_windows.h" +#include +#include +#include +#include +#include +#include "windows/WebView2.h" +#include +#include "effectstructs_windows.h" +#include + +int debug = 0; +DWORD mainThread; + +#define WS_EX_NOREDIRECTIONBITMAP 0x00200000L + +// --- Assets +extern const unsigned char runtime; +extern const unsigned char *defaultDialogIcons[]; + +// dispatch will execute the given `func` pointer +void dispatch(dispatchFunction func) { + PostThreadMessage(mainThread, WM_APP, 0, (LPARAM) new dispatchFunction(func)); +} + +void processKeyPress(UINT key) { + // Get state of Control + bool controlPressed = GetKeyState(VK_CONTROL) >> 15 != 0; + bool altPressed = GetKeyState(VK_MENU) >> 15 != 0; + bool shiftPressed = GetKeyState(VK_SHIFT) >> 15 != 0; + + // Save the modifier keys + BYTE modState = 0; + if ( GetKeyState(VK_CONTROL) >> 15 != 0 ) { modState |= 1; } + if ( GetKeyState(VK_MENU) >> 15 != 0 ) { modState |= 2; } + if ( GetKeyState(VK_SHIFT) >> 15 != 0 ) { modState |= 4; } + if ( GetKeyState(VK_LWIN) >> 15 != 0 ) { modState |= 8; } + if ( GetKeyState(VK_RWIN) >> 15 != 0 ) { modState |= 8; } + + // Notify app of keypress + handleKeypressInGo(key, modState); +} + + +LPWSTR cstrToLPWSTR(const char *cstr) { + int wchars_num = MultiByteToWideChar( CP_UTF8 , 0 , cstr , -1, NULL , 0 ); + wchar_t* wstr = new wchar_t[wchars_num+1]; + MultiByteToWideChar( CP_UTF8 , 0 , cstr , -1, wstr , wchars_num ); + return wstr; +} + +// Credit: https://stackoverflow.com/a/9842450 +char* LPWSTRToCstr(LPWSTR input) { + int length = WideCharToMultiByte(CP_UTF8, 0, input, -1, 0, 0, NULL, NULL); + char* output = new char[length]; + WideCharToMultiByte(CP_UTF8, 0, input, -1, output , length, NULL, NULL); + return output; +} + + +// Credit: https://building.enlyze.com/posts/writing-win32-apps-like-its-2020-part-3/ +typedef int (__cdecl *PGetDpiForMonitor)(HMONITOR, MONITOR_DPI_TYPE,UINT*,UINT*); +void getDPIForWindow(struct Application *app) +{ + HMODULE hShcore = LoadLibraryW(L"shcore"); + if (hShcore) + { + PGetDpiForMonitor pGetDpiForMonitor = reinterpret_cast(GetProcAddress(hShcore, "GetDpiForMonitor")); + if (pGetDpiForMonitor) + { + HMONITOR hMonitor = MonitorFromWindow(app->window, MONITOR_DEFAULTTOPRIMARY); + pGetDpiForMonitor(hMonitor, (MONITOR_DPI_TYPE)0, &app->dpix, &app->dpiy); + } + } else { + // We couldn't get the window's DPI above, so get the DPI of the primary monitor + // using an API that is available in all Windows versions. + HDC hScreenDC = GetDC(0); + app->dpix = GetDeviceCaps(hScreenDC, LOGPIXELSX); + app->dpiy = GetDeviceCaps(hScreenDC, LOGPIXELSY); + ReleaseDC(0, hScreenDC); + } +} + +struct Application *NewApplication(const char *title, int width, int height, int resizable, int devtools, int fullscreen, int startHidden, int logLevel, int hideWindowOnClose) { + + // Create application + struct Application *result = (struct Application*)malloc(sizeof(struct Application)); + + result->window = nullptr; + result->webview = nullptr; + result->webviewController = nullptr; + + result->title = title; + result->width = width; + result->height = height; + result->resizable = resizable; + result->devtools = devtools; + result->fullscreen = fullscreen; + result->startHidden = startHidden; + result->logLevel = logLevel; + result->hideWindowOnClose = hideWindowOnClose; + result->webviewIsTranparent = false; + result->WindowIsTranslucent = false; + result->disableWindowIcon = false; + + // Min/Max Width/Height + result->minWidth = 0; + result->minHeight = 0; + result->maxWidth = 0; + result->maxHeight = 0; + + // Default colour + result->backgroundColour.R = 255; + result->backgroundColour.G = 255; + result->backgroundColour.B = 255; + result->backgroundColour.A = 255; + + // Have a frame by default + result->frame = 1; + + // Capture Main Thread + mainThread = GetCurrentThreadId(); + + // Startup url + result->startupURL = nullptr; + + // Used to remember the window location when going fullscreen + result->previousPlacement = { sizeof(result->previousPlacement) }; + + // DPI + result->dpix = result->dpiy = 0; + + return result; +} + +void* GetWindowHandle(struct Application *app) { + return (void*)app->window; +} + +void SetMinWindowSize(struct Application* app, int minWidth, int minHeight) { + app->minWidth = (LONG)minWidth; + app->minHeight = (LONG)minHeight; +} + +void SetMaxWindowSize(struct Application* app, int maxWidth, int maxHeight) { + app->maxWidth = (LONG)maxWidth; + app->maxHeight = (LONG)maxHeight; +} + +void SetBindings(struct Application *app, const char *bindings) { + std::string temp = std::string("window.wailsbindings = \"") + std::string(bindings) + std::string("\";"); + app->bindings = new char[temp.length()+1]; + memcpy(app->bindings, temp.c_str(), temp.length()+1); +} + +void performShutdown(struct Application *app) { + if( app->startupURL != nullptr ) { + delete[] app->startupURL; + } + messageFromWindowCallback("WC"); +} + +// Credit: https://gist.github.com/ysc3839/b08d2bff1c7dacde529bed1d37e85ccf +void enableTranslucentBackground(struct Application *app) { + HMODULE hUser = GetModuleHandleA("user32.dll"); + if (hUser) + { + pfnSetWindowCompositionAttribute setWindowCompositionAttribute = (pfnSetWindowCompositionAttribute)GetProcAddress(hUser, "SetWindowCompositionAttribute"); + if (setWindowCompositionAttribute) + { + ACCENT_POLICY accent = { ACCENT_ENABLE_BLURBEHIND, 0, 0, 0 }; + WINDOWCOMPOSITIONATTRIBDATA data; + data.Attrib = WCA_ACCENT_POLICY; + data.pvData = &accent; + data.cbData = sizeof(accent); + setWindowCompositionAttribute(app->window, &data); + } + } +} + +LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { + + struct Application *app = (struct Application *)GetWindowLongPtr(hwnd, GWLP_USERDATA); + + switch(msg) { + + case WM_CREATE: { + createApplicationMenu(hwnd); + break; + } + case WM_COMMAND: + menuClicked(LOWORD(wParam)); + break; + + case WM_CLOSE: { + DestroyWindow( app->window ); + break; + } + case WM_DESTROY: { + if( app->hideWindowOnClose ) { + Hide(app); + } else { + PostQuitMessage(0); + } + break; + } + case WM_SIZE: { + if ( app == NULL ) { + return 0; + } + if( app->webviewController != nullptr) { + RECT bounds; + GetClientRect(app->window, &bounds); + app->webviewController->put_Bounds(bounds); + } + break; + } + case WM_KEYDOWN: + // This is needed because webview2 is sometimes not in focus + // https://github.com/MicrosoftEdge/WebView2Feedback/issues/1541 + processKeyPress(wParam); + break; + case WM_GETMINMAXINFO: { + // Exit early if this is called before the window is created. + if ( app == NULL ) { + return 0; + } + + // update DPI + getDPIForWindow(app); + double DPIScaleX = app->dpix/96.0; + double DPIScaleY = app->dpiy/96.0; + + RECT rcWind; + POINT ptDiff; + GetWindowRect(hwnd, &rcWind); + + int widthExtra = (rcWind.right - rcWind.left); + int heightExtra = (rcWind.bottom - rcWind.top); + + LPMINMAXINFO mmi = (LPMINMAXINFO) lParam; + if (app->minWidth > 0 && app->minHeight > 0) { + mmi->ptMinTrackSize.x = app->minWidth * DPIScaleX; + mmi->ptMinTrackSize.y = app->minHeight * DPIScaleY; + } + if (app->maxWidth > 0 && app->maxHeight > 0) { + mmi->ptMaxSize.x = app->maxWidth * DPIScaleX; + mmi->ptMaxSize.y = app->maxHeight * DPIScaleY; + mmi->ptMaxTrackSize.x = app->maxWidth * DPIScaleX; + mmi->ptMaxTrackSize.y = app->maxHeight * DPIScaleY; + } + return 0; + } + default: + return DefWindowProc(hwnd, msg, wParam, lParam); + } + return 0; +} + +void init(struct Application *app, const char* js) { + LPCWSTR wjs = cstrToLPWSTR(js); + app->webview->AddScriptToExecuteOnDocumentCreated(wjs, nullptr); + delete[] wjs; +} + +void execJS(struct Application* app, const char *script) { + LPWSTR s = cstrToLPWSTR(script); + app->webview->ExecuteScript(s, nullptr); + delete[] s; +} + +void loadAssets(struct Application* app) { + + // setup window.wailsInvoke + std::string initialCode = std::string("window.wailsInvoke=function(m){window.chrome.webview.postMessage(m)};"); + + // Load bindings + initialCode += std::string(app->bindings); + delete[] app->bindings; + + // Load runtime + initialCode += std::string((const char*)&runtime); + + int index = 1; + while(1) { + // Get next asset pointer + const unsigned char *asset = assets[index]; + + // If we have no more assets, break + if (asset == 0x00) { + break; + } + + initialCode += std::string((const char*)asset); + index++; + }; + + // Disable context menu if not in debug mode + if( debug != 1 ) { + initialCode += std::string("wails._.DisableDefaultContextMenu();"); + } + + initialCode += std::string("window.wailsInvoke('completed');"); + + // Keep a copy of the code + app->initialCode = new char[initialCode.length()+1]; + memcpy(app->initialCode, initialCode.c_str(), initialCode.length()+1); + + execJS(app, app->initialCode); + + // Show app if we need to + if( app->startHidden == false ) { + Show(app); + } +} + +// This is called when all our assets are loaded into the DOM +void completed(struct Application* app) { + delete[] app->initialCode; + app->initialCode = nullptr; + + // Process whether window should show by default + int startVisibility = SW_SHOWNORMAL; + if ( app->startHidden == 1 ) { + startVisibility = SW_HIDE; + } + + // Fix for webview2 bug: https://github.com/MicrosoftEdge/WebView2Feedback/issues/1077 + // Will be fixed in next stable release + app->webviewController->put_IsVisible(false); + app->webviewController->put_IsVisible(true); + + // Private setTitle as we're on the main thread + if( app->frame == 1) { + setTitle(app, app->title); + } + + ShowWindow(app->window, startVisibility); + UpdateWindow(app->window); + SetFocus(app->window); + + if( app->startupURL == nullptr ) { + messageFromWindowCallback("SS"); + return; + } + std::string readyMessage = std::string("SS") + std::string(app->startupURL); + messageFromWindowCallback(readyMessage.c_str()); +} + +// +bool initWebView2(struct Application *app, int debugEnabled, messageCallback cb) { + + debug = debugEnabled; + + CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + std::atomic_flag flag = ATOMIC_FLAG_INIT; + flag.test_and_set(); + + char currentExePath[MAX_PATH]; + GetModuleFileNameA(NULL, currentExePath, MAX_PATH); + char *currentExeName = PathFindFileNameA(currentExePath); + + std::wstring_convert> wideCharConverter; + std::wstring userDataFolder = + wideCharConverter.from_bytes(std::getenv("APPDATA")); + std::wstring currentExeNameW = wideCharConverter.from_bytes(currentExeName); + + ICoreWebView2Controller *controller; + ICoreWebView2* webview; + + HRESULT res = CreateCoreWebView2EnvironmentWithOptions( + nullptr, (userDataFolder + L"/" + currentExeNameW).c_str(), nullptr, + new wv2ComHandler(app, app->window, cb, + [&](ICoreWebView2Controller *webviewController) { + controller = webviewController; + controller->get_CoreWebView2(&webview); + webview->AddRef(); + ICoreWebView2Settings* settings; + webview->get_Settings(&settings); + if ( debugEnabled == 0 ) { + settings->put_AreDefaultContextMenusEnabled(FALSE); + } + // Fix for invisible webview + if( app->startHidden ) {} + controller->MoveFocus(COREWEBVIEW2_MOVE_FOCUS_REASON_PROGRAMMATIC); + flag.clear(); + })); + if (!SUCCEEDED(res)) + { + switch (res) + { + case HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND): + { + MessageBox( + app->window, + L"Couldn't find Edge installation. " + "Do you have a version installed that's compatible with this " + "WebView2 SDK version?", + nullptr, MB_OK); + } + break; + case HRESULT_FROM_WIN32(ERROR_FILE_EXISTS): + { + MessageBox( + app->window, L"User data folder cannot be created because a file with the same name already exists.", nullptr, MB_OK); + } + break; + case E_ACCESSDENIED: + { + MessageBox( + app->window, L"Unable to create user data folder, Access Denied.", nullptr, MB_OK); + } + break; + case E_FAIL: + { + MessageBox( + app->window, L"Edge runtime unable to start", nullptr, MB_OK); + } + break; + default: + { + MessageBox(app->window, L"Failed to create WebView2 environment", nullptr, MB_OK); + } + } + } + + if (res != S_OK) { + CoUninitialize(); + return false; + } + + MSG msg = {}; + while (flag.test_and_set() && GetMessage(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + app->webviewController = controller; + app->webview = webview; + + // Resize WebView to fit the bounds of the parent window + RECT bounds; + GetClientRect(app->window, &bounds); + app->webviewController->put_Bounds(bounds); + + // Let the backend know we have initialised + app->webview->AddScriptToExecuteOnDocumentCreated(L"window.chrome.webview.postMessage('initialised');", nullptr); + // Load the HTML + LPCWSTR html = (LPCWSTR) cstrToLPWSTR((char*)assets[0]); + app->webview->Navigate(html); + + if( app->webviewIsTranparent ) { + wchar_t szBuff[64]; + ICoreWebView2Controller2 *wc2; + wc2 = nullptr; + app->webviewController->QueryInterface(IID_ICoreWebView2Controller2, (void**)&wc2); + + COREWEBVIEW2_COLOR wvColor; + wvColor.R = app->backgroundColour.R; + wvColor.G = app->backgroundColour.G; + wvColor.B = app->backgroundColour.B; + wvColor.A = app->backgroundColour.A == 0 ? 0 : 255; + if( app->WindowIsTranslucent ) { + wvColor.A = 0; + } + HRESULT result = wc2->put_DefaultBackgroundColor(wvColor); + if (!SUCCEEDED(result)) + { + switch (result) + { + case HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND): + { + MessageBox( + app->window, + L"Couldn't find Edge installation. " + "Do you have a version installed that's compatible with this " + "WebView2 SDK version?", + nullptr, MB_OK); + } + break; + case HRESULT_FROM_WIN32(ERROR_FILE_EXISTS): + { + MessageBox( + app->window, L"User data folder cannot be created because a file with the same name already exists.", nullptr, MB_OK); + } + break; + case E_ACCESSDENIED: + { + MessageBox( + app->window, L"Unable to create user data folder, Access Denied.", nullptr, MB_OK); + } + break; + case E_FAIL: + { + MessageBox( + app->window, L"Edge runtime unable to start", nullptr, MB_OK); + } + break; + default: + { + MessageBox(app->window, L"Failed to create WebView2 environment", nullptr, MB_OK); + } + } + } + + } + + messageFromWindowCallback("Ej{\"name\":\"wails:launched\",\"data\":[]}"); + + return true; +} + +void initialCallback(std::string message) { + printf("MESSAGE=%s\n", message); +} + +void Run(struct Application* app, int argc, char **argv) { + + // Register the window class. + const wchar_t CLASS_NAME[] = L"Ffenestri"; + + WNDCLASSEX wc = { }; + + wc.cbSize = sizeof(WNDCLASSEX); + wc.lpfnWndProc = WndProc; + wc.hInstance = GetModuleHandle(NULL); + wc.lpszClassName = CLASS_NAME; + + if( app->disableWindowIcon == false ) { + wc.hIcon = LoadIcon(wc.hInstance, MAKEINTRESOURCE(100)); + wc.hIconSm = LoadIcon(wc.hInstance, MAKEINTRESOURCE(100)); + } + + // Configure translucency + DWORD dwExStyle = 0; + if ( app->WindowIsTranslucent) { + dwExStyle = WS_EX_NOREDIRECTIONBITMAP; + wc.hbrBackground = CreateSolidBrush(RGB(255,255,255)); + } + + RegisterClassEx(&wc); + + // Process window style + DWORD windowStyle = WS_OVERLAPPEDWINDOW | WS_THICKFRAME | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX; + + if (app->resizable == 0) { + windowStyle &= ~WS_MAXIMIZEBOX; + windowStyle &= ~WS_THICKFRAME; + } + if ( app->frame == 0 ) { + windowStyle &= ~WS_OVERLAPPEDWINDOW; + windowStyle &= ~WS_CAPTION; + windowStyle |= WS_POPUP; + } + + // Create the window. + app->window = CreateWindowEx( + dwExStyle, // Optional window styles. + CLASS_NAME, // Window class + L"", // Window text + windowStyle, // Window style + + // Size and position + CW_USEDEFAULT, CW_USEDEFAULT, app->width, app->height, + + NULL, // Parent window + NULL, // Menu + wc.hInstance, // Instance handle + NULL // Additional application data + ); + + if (app->window == NULL) + { + return; + } + + if ( app->fullscreen ) { + fullscreen(app); + } + + // Credit: https://stackoverflow.com/a/35482689 + if( app->disableWindowIcon && app->frame == 1 ) { + int extendedStyle = GetWindowLong(app->window, GWL_EXSTYLE); + SetWindowLong(app->window, GWL_EXSTYLE, extendedStyle | WS_EX_DLGMODALFRAME); + SetWindowPos(nullptr, nullptr, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER); + } + + if ( app->WindowIsTranslucent ) { + + // Enable the translucent background effect + enableTranslucentBackground(app); + + // Setup transparency of main window. This allows the blur to show through. + SetLayeredWindowAttributes(app->window,RGB(255,255,255),0,LWA_COLORKEY); + } + + // Store application pointer in window handle + SetWindowLongPtr(app->window, GWLP_USERDATA, (LONG_PTR)app); + + // private center() as we are on main thread + center(app); + + // Add webview2 + initWebView2(app, debug, initialCallback); + + + // Main event loop + MSG msg; + BOOL res; + while ((res = GetMessage(&msg, NULL, 0, 0)) != -1) { + if (msg.hwnd) { + TranslateMessage(&msg); + DispatchMessage(&msg); + continue; + } + if (msg.message == WM_APP) { + dispatchFunction *f = (dispatchFunction*) msg.lParam; + (*f)(); + delete(f); + } else if (msg.message == WM_QUIT) { + performShutdown(app); + return; + } + } +} + +void SetDebug(struct Application* app, int flag) { + debug = flag; +} + +void ExecJS(struct Application* app, const char *script) { + ON_MAIN_THREAD( + execJS(app, script); + ); +} + +void hide(struct Application* app) { + ShowWindow(app->window, SW_HIDE); +} + +void Hide(struct Application* app) { + ON_MAIN_THREAD( + hide(app); + ); +} + +void show(struct Application* app) { + ShowWindow(app->window, SW_SHOW); +} + +void Show(struct Application* app) { + ON_MAIN_THREAD( + show(app); + ); +} + +void DisableWindowIcon(struct Application* app) { + app->disableWindowIcon = true; +} + +void center(struct Application* app) { + + HMONITOR currentMonitor = MonitorFromWindow(app->window, MONITOR_DEFAULTTONEAREST); + MONITORINFO info = {0}; + info.cbSize = sizeof(info); + GetMonitorInfoA(currentMonitor, &info); + RECT workRect = info.rcWork; + LONG screenMiddleW = (workRect.right - workRect.left) / 2; + LONG screenMiddleH = (workRect.bottom - workRect.top) / 2; + RECT winRect; + if (app->frame == 1) { + GetWindowRect(app->window, &winRect); + } else { + GetClientRect(app->window, &winRect); + } + LONG winWidth = winRect.right - winRect.left; + LONG winHeight = winRect.bottom - winRect.top; + + LONG windowX = screenMiddleW - (winWidth / 2); + LONG windowY = screenMiddleH - (winHeight / 2); + + SetWindowPos(app->window, HWND_TOP, windowX, windowY, winWidth, winHeight, SWP_NOSIZE); +} + +void Center(struct Application* app) { + ON_MAIN_THREAD( + center(app); + ); +} + +UINT getWindowPlacement(struct Application* app) { + WINDOWPLACEMENT lpwndpl; + lpwndpl.length = sizeof(WINDOWPLACEMENT); + BOOL result = GetWindowPlacement(app->window, &lpwndpl); + if( result == 0 ) { + // TODO: Work out what this call failing means + return -1; + } + return lpwndpl.showCmd; +} + +int isMaximised(struct Application* app) { + return getWindowPlacement(app) == SW_SHOWMAXIMIZED; +} + +void maximise(struct Application* app) { + ShowWindow(app->window, SW_MAXIMIZE); +} + +void Maximise(struct Application* app) { + ON_MAIN_THREAD( + maximise(app); + ); +} + +void unmaximise(struct Application* app) { + ShowWindow(app->window, SW_RESTORE); +} + +void Unmaximise(struct Application* app) { + ON_MAIN_THREAD( + unmaximise(app); + ); +} + + +void ToggleMaximise(struct Application* app) { + if(isMaximised(app)) { + return Unmaximise(app); + } + return Maximise(app); +} + +int isMinimised(struct Application* app) { + return getWindowPlacement(app) == SW_SHOWMINIMIZED; +} + +void minimise(struct Application* app) { + ShowWindow(app->window, SW_MINIMIZE); +} + +void Minimise(struct Application* app) { + ON_MAIN_THREAD( + minimise(app); + ); +} + +void unminimise(struct Application* app) { + ShowWindow(app->window, SW_RESTORE); +} + +void Unminimise(struct Application* app) { + ON_MAIN_THREAD( + unminimise(app); + ); +} + +void ToggleMinimise(struct Application* app) { + if(isMinimised(app)) { + return Unminimise(app); + } + return Minimise(app); +} + +void SetColour(struct Application* app, int red, int green, int blue, int alpha) { + app->backgroundColour.R = red; + app->backgroundColour.G = green; + app->backgroundColour.B = blue; + app->backgroundColour.A = alpha; +} + +void SetSize(struct Application* app, int width, int height) { + if( app->maxWidth > 0 && width > app->maxWidth ) { + width = app->maxWidth; + } + if ( app->maxHeight > 0 && height > app->maxHeight ) { + height = app->maxHeight; + } + SetWindowPos(app->window, nullptr, 0, 0, width, height, SWP_NOMOVE); +} + +void setPosition(struct Application* app, int x, int y) { + HMONITOR currentMonitor = MonitorFromWindow(app->window, MONITOR_DEFAULTTONEAREST); + MONITORINFO info = {0}; + info.cbSize = sizeof(info); + GetMonitorInfoA(currentMonitor, &info); + RECT workRect = info.rcWork; + LONG newX = workRect.left + x; + LONG newY = workRect.top + y; + + SetWindowPos(app->window, HWND_TOP, newX, newY, 0, 0, SWP_NOSIZE); +} + +void SetPosition(struct Application* app, int x, int y) { + ON_MAIN_THREAD( + setPosition(app, x, y); + ); +} + +void Quit(struct Application* app) { + // Override the hide window on close flag + app->hideWindowOnClose = 0; + ON_MAIN_THREAD( + DestroyWindow(app->window); + ); +} + + +// Credit: https://stackoverflow.com/a/6693107 +void setTitle(struct Application* app, const char *title) { + LPCTSTR text = cstrToLPWSTR(title); + SetWindowText(app->window, text); + delete[] text; +} + +void SetTitle(struct Application* app, const char *title) { + ON_MAIN_THREAD( + setTitle(app, title); + ); +} + +void fullscreen(struct Application* app) { + + // Ensure we aren't in fullscreen + if (app->isFullscreen) return; + + app->isFullscreen = true; + app->previousWindowStyle = GetWindowLong(app->window, GWL_STYLE); + MONITORINFO mi = { sizeof(mi) }; + if (GetWindowPlacement(app->window, &(app->previousPlacement)) && GetMonitorInfo(MonitorFromWindow(app->window, MONITOR_DEFAULTTOPRIMARY), &mi)) { + SetWindowLong(app->window, GWL_STYLE, app->previousWindowStyle & ~WS_OVERLAPPEDWINDOW); + SetWindowPos(app->window, HWND_TOP, + mi.rcMonitor.left, + mi.rcMonitor.top, + mi.rcMonitor.right - mi.rcMonitor.left, + mi.rcMonitor.bottom - mi.rcMonitor.top, + SWP_NOOWNERZORDER | SWP_FRAMECHANGED); + } +} + +void Fullscreen(struct Application* app) { + ON_MAIN_THREAD( + fullscreen(app); + show(app); + ); +} + +void unfullscreen(struct Application* app) { + if (app->isFullscreen) { + SetWindowLong(app->window, GWL_STYLE, app->previousWindowStyle); + SetWindowPlacement(app->window, &(app->previousPlacement)); + SetWindowPos(app->window, NULL, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | + SWP_NOOWNERZORDER | SWP_FRAMECHANGED); + app->isFullscreen = false; + } +} + +void UnFullscreen(struct Application* app) { + ON_MAIN_THREAD( + unfullscreen(app); + ); +} + +void DisableFrame(struct Application* app) { + app->frame = 0; +} + +// WebviewIsTransparent will make the webview transparent +// revealing the window underneath +void WebviewIsTransparent(struct Application *app) { + app->webviewIsTranparent = true; +} + +void WindowIsTranslucent(struct Application *app) { + app->WindowIsTranslucent = true; +} + + +void OpenDialog(struct Application* app, char *callbackID, char *title, char *filters, char *defaultFilename, char *defaultDir, int allowFiles, int allowDirs, int allowMultiple, int showHiddenFiles, int canCreateDirectories, int resolvesAliases, int treatPackagesAsDirectories) { +} +void SaveDialog(struct Application* app, char *callbackID, char *title, char *filters, char *defaultFilename, char *defaultDir, int showHiddenFiles, int canCreateDirectories, int treatPackagesAsDirectories) { +} +void MessageDialog(struct Application* app, char *callbackID, char *type, char *title, char *message, char *icon, char *button1, char *button2, char *button3, char *button4, char *defaultButton, char *cancelButton) { +} +void DarkModeEnabled(struct Application* app, char *callbackID) { +} +void SetApplicationMenu(struct Application* app, const char *applicationMenuJSON) { +} +void AddTrayMenu(struct Application* app, const char *menuTrayJSON) { +} +void SetTrayMenu(struct Application* app, const char *menuTrayJSON) { +} +void DeleteTrayMenuByID(struct Application* app, const char *id) { +} +void UpdateTrayMenuLabel(struct Application* app, const char* JSON) { +} +void AddContextMenu(struct Application* app, char *contextMenuJSON) { +} +void UpdateContextMenu(struct Application* app, char *contextMenuJSON) { +} \ No newline at end of file diff --git a/v2/internal/ffenestri/ffenestri_windows.go b/v2/internal/ffenestri/ffenestri_windows.go new file mode 100644 index 000000000..ce5d821f3 --- /dev/null +++ b/v2/internal/ffenestri/ffenestri_windows.go @@ -0,0 +1,198 @@ +package ffenestri + +import "C" + +/* + +#cgo windows CXXFLAGS: -std=c++11 +#cgo windows,amd64 LDFLAGS: -lgdi32 -lole32 -lShlwapi -luser32 -loleaut32 -ldwmapi + +#include "ffenestri.h" + +extern void DisableWindowIcon(struct Application* app); + +*/ +import "C" +import ( + "github.com/ztrue/tracerr" + "os" + + "github.com/wailsapp/wails/v2/pkg/menu" +) + +// Setup the global caches +var globalCheckboxCache = NewCheckboxCache() +var globalRadioGroupCache = NewRadioGroupCache() +var globalRadioGroupMap = NewRadioGroupMap() +var globalApplicationMenu *Menu + +type menuType string + +const ( + appMenuType menuType = "ApplicationMenu" + contextMenuType + trayMenuType +) + +func (a *Application) processPlatformSettings() error { + + menuManager = a.menuManager + config := a.config.Windows + if config == nil { + return nil + } + + // Check if the webview should be transparent + if config.WebviewIsTransparent { + C.WebviewIsTransparent(a.app) + } + + if config.WindowIsTranslucent { + C.WindowIsTranslucent(a.app) + } + + if config.DisableWindowIcon { + C.DisableWindowIcon(a.app) + } + + // Unfortunately, we need to store this in the package variable so the C callback can see it + applicationMenu = a.menuManager.GetProcessedApplicationMenu() + + // + //// Process tray + //trays, err := a.menuManager.GetTrayMenus() + //if err != nil { + // return err + //} + //if trays != nil { + // for _, tray := range trays { + // C.AddTrayMenu(a.app, a.string2CString(tray)) + // } + //} + // + //// Process context menus + //contextMenus, err := a.menuManager.GetContextMenus() + //if err != nil { + // return err + //} + //if contextMenus != nil { + // for _, contextMenu := range contextMenus { + // C.AddContextMenu(a.app, a.string2CString(contextMenu)) + // } + //} + // + //// Process URL Handlers + //if a.config.Mac.URLHandlers != nil { + // C.HasURLHandlers(a.app) + //} + + return nil +} + +func (c *Client) updateApplicationMenu() { + applicationMenu = c.app.menuManager.GetProcessedApplicationMenu() + createApplicationMenu(uintptr(C.GetWindowHandle(c.app.app))) +} + +/* --------------------------------------------------------------------------------- + +Application Menu +---------------- +There's only 1 application menu and this is where we create it. This method +is called from C after the window is created and the WM_CREATE message has +been sent. + +*/ + +func checkFatal(err error) { + if err != nil { + tracerr.PrintSourceColor(err) + globalRadioGroupCache.Dump() + globalRadioGroupMap.Dump() + os.Exit(1) + } +} + +//export createApplicationMenu +func createApplicationMenu(hwnd uintptr) { + + if applicationMenu == nil { + return + } + + var err error + window := win32Window(hwnd) + + if globalApplicationMenu != nil { + checkFatal(globalApplicationMenu.Destroy()) + } + + globalApplicationMenu, err = createMenu(applicationMenu, appMenuType) + checkFatal(err) + + err = setWindowMenu(window, globalApplicationMenu.menu) + checkFatal(err) +} + +//export handleKeypressInGo +func handleKeypressInGo(keycode uint16, modifiers uint8) { + //fmt.Printf("Key code: %#x\n", keycode) + menuID, menuType := getCallbackForKeyPress(keycode, modifiers) + if menuID == "" { + return + } + err := menuManager.ProcessClick(menuID, "", string(menuType), "") + if err != nil { + println(err.Error()) + } +} + +/* +This method is called by C when a menu item is pressed +*/ + +//export menuClicked +func menuClicked(id uint32) { + win32MenuID := win32MenuItemID(id) + //println("Got click from menu id", win32MenuID) + + // Get the menu from the cache + menuItemDetails := getMenuCacheEntry(win32MenuID) + wailsMenuID := wailsMenuItemID(menuItemDetails.item.ID) + + //println("Got click from menu id", win32MenuID, "- wails menu ID", wailsMenuID) + //spew.Dump(menuItemDetails) + + switch menuItemDetails.item.Type { + case menu.CheckboxType: + + // Determine if the menu is set or not + res, _, err := win32GetMenuState.Call(uintptr(menuItemDetails.parent), uintptr(id), uintptr(MF_BYCOMMAND)) + if int(res) == -1 { + checkFatal(err) + } + + flag := MF_CHECKED + if uint32(res) == MF_CHECKED { + flag = MF_UNCHECKED + } + + for _, menuid := range globalCheckboxCache.win32MenuIDsForWailsMenuID(wailsMenuID) { + //println("setting menuid", menuid, "with flag", flag) + menuItemDetails := getMenuCacheEntry(menuid) + res, _, err = win32CheckMenuItem.Call(uintptr(menuItemDetails.parent), uintptr(menuid), uintptr(flag)) + if int(res) == -1 { + checkFatal(err) + } + } + case menu.RadioType: + err := selectRadioItemFromWailsMenuID(wailsMenuID, win32MenuID) + checkFatal(err) + } + + // Print the click error - it's not fatal + err := menuManager.ProcessClick(menuItemDetails.item.ID, "", string(menuItemDetails.menuType), "") + if err != nil { + println(err.Error()) + } +} diff --git a/v2/internal/ffenestri/ffenestri_windows.h b/v2/internal/ffenestri/ffenestri_windows.h new file mode 100644 index 000000000..1e39bea10 --- /dev/null +++ b/v2/internal/ffenestri/ffenestri_windows.h @@ -0,0 +1,95 @@ + +#ifndef _FFENESTRI_WINDOWS_H +#define _FFENESTRI_WINDOWS_H + +#define WIN32_LEAN_AND_MEAN +#define UNICODE 1 + +#include "ffenestri.h" +#include +#include +#include +#include +#include "windows/WebView2.h" + +#include "assets.h" + +// TODO: +//#include "userdialogicons.h" + + +struct Application{ + // Window specific + HWND window; + ICoreWebView2 *webview; + ICoreWebView2Controller* webviewController; + + // Application + const char *title; + int width; + int height; + int resizable; + int devtools; + int fullscreen; + int startHidden; + int logLevel; + int hideWindowOnClose; + int minSizeSet; + LONG minWidth; + LONG minHeight; + int maxSizeSet; + LONG maxWidth; + LONG maxHeight; + int frame; + char *startupURL; + bool webviewIsTranparent; + bool WindowIsTranslucent; + COREWEBVIEW2_COLOR backgroundColour; + bool disableWindowIcon; + + // Used by fullscreen/unfullscreen + bool isFullscreen; + WINDOWPLACEMENT previousPlacement; + DWORD previousWindowStyle; + + // placeholders + char* bindings; + char* initialCode; + + // DPI + UINT dpix; + UINT dpiy; +}; + +#define ON_MAIN_THREAD(code) dispatch( [=]{ code; } ) + +typedef std::function dispatchFunction; +typedef std::function messageCallback; +typedef std::function comHandlerCallback; + +void center(struct Application*); +void setTitle(struct Application* app, const char *title); +void fullscreen(struct Application* app); +void unfullscreen(struct Application* app); +char* LPWSTRToCstr(LPWSTR input); + +// called when the DOM is ready +void loadAssets(struct Application* app); + +// called when the application assets have been loaded into the DOM +void completed(struct Application* app); + +// Processes the given keycode +void processKeyPress(UINT key); + +// Callback +extern "C" { + void DisableWindowIcon(struct Application* app); + void messageFromWindowCallback(const char *); + void* GetWindowHandle(struct Application*); + void createApplicationMenu(HWND hwnd); + void menuClicked(UINT id); + void handleKeypressInGo(UINT, BYTE); +} + +#endif \ No newline at end of file diff --git a/v2/internal/ffenestri/hashmap.h b/v2/internal/ffenestri/hashmap.h new file mode 100644 index 000000000..0278bc3d6 --- /dev/null +++ b/v2/internal/ffenestri/hashmap.h @@ -0,0 +1,518 @@ +/* + The latest version of this library is available on GitHub; + https://github.com/sheredom/hashmap.h +*/ + +/* + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a compiled + binary, for any purpose, commercial or non-commercial, and by any + means. + + In jurisdictions that recognize copyright laws, the author or authors + of this software dedicate any and all copyright interest in the + software to the public domain. We make this dedication for the benefit + of the public at large and to the detriment of our heirs and + successors. We intend this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights to this + software under copyright law. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + For more information, please refer to +*/ +#ifndef SHEREDOM_HASHMAP_H_INCLUDED +#define SHEREDOM_HASHMAP_H_INCLUDED + +#if defined(_MSC_VER) +// Workaround a bug in the MSVC runtime where it uses __cplusplus when not +// defined. +#pragma warning(push, 0) +#pragma warning(disable : 4668) +#endif +#include +#include + +#if (defined(_MSC_VER) && defined(__AVX__)) || \ + (!defined(_MSC_VER) && defined(__SSE4_2__)) +#define HASHMAP_SSE42 +#endif + +#if defined(HASHMAP_SSE42) +#include +#endif + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +#if defined(_MSC_VER) +#pragma warning(push) +// Stop MSVC complaining about not inlining functions. +#pragma warning(disable : 4710) +// Stop MSVC complaining about inlining functions! +#pragma warning(disable : 4711) +#elif defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +#endif + +#if defined(_MSC_VER) +#define HASHMAP_USED +#elif defined(__GNUC__) +#define HASHMAP_USED __attribute__((used)) +#else +#define HASHMAP_USED +#endif + +/* We need to keep keys and values. */ +struct hashmap_element_s { + const char *key; + unsigned key_len; + int in_use; + void *data; +}; + +/* A hashmap has some maximum size and current size, as well as the data to + * hold. */ +struct hashmap_s { + unsigned table_size; + unsigned size; + struct hashmap_element_s *data; +}; + +#define HASHMAP_MAX_CHAIN_LENGTH (8) + +#if defined(__cplusplus) +extern "C" { +#endif + +/// @brief Create a hashmap. +/// @param initial_size The initial size of the hashmap. Must be a power of two. +/// @param out_hashmap The storage for the created hashmap. +/// @return On success 0 is returned. +/// +/// Note that the initial size of the hashmap must be a power of two, and +/// creation of the hashmap will fail if this is not the case. +static int hashmap_create(const unsigned initial_size, + struct hashmap_s *const out_hashmap) HASHMAP_USED; + +/// @brief Put an element into the hashmap. +/// @param hashmap The hashmap to insert into. +/// @param key The string key to use. +/// @param len The length of the string key. +/// @param value The value to insert. +/// @return On success 0 is returned. +/// +/// The key string slice is not copied when creating the hashmap entry, and thus +/// must remain a valid pointer until the hashmap entry is removed or the +/// hashmap is destroyed. +static int hashmap_put(struct hashmap_s *const hashmap, const char *const key, + const unsigned len, void *const value) HASHMAP_USED; + +/// @brief Get an element from the hashmap. +/// @param hashmap The hashmap to get from. +/// @param key The string key to use. +/// @param len The length of the string key. +/// @return The previously set element, or NULL if none exists. +static void *hashmap_get(const struct hashmap_s *const hashmap, + const char *const key, + const unsigned len) HASHMAP_USED; + +/// @brief Remove an element from the hashmap. +/// @param hashmap The hashmap to remove from. +/// @param key The string key to use. +/// @param len The length of the string key. +/// @return On success 0 is returned. +static int hashmap_remove(struct hashmap_s *const hashmap, + const char *const key, + const unsigned len) HASHMAP_USED; + +/// @brief Iterate over all the elements in a hashmap. +/// @param hashmap The hashmap to iterate over. +/// @param f The function pointer to call on each element. +/// @param context The context to pass as the first argument to f. +/// @return If the entire hashmap was iterated then 0 is returned. Otherwise if +/// the callback function f returned non-zero then non-zero is returned. +static int hashmap_iterate(const struct hashmap_s *const hashmap, + int (*f)(void *const context, void *const value), + void *const context) HASHMAP_USED; + +/// @brief Iterate over all the elements in a hashmap. +/// @param hashmap The hashmap to iterate over. +/// @param f The function pointer to call on each element. +/// @param context The context to pass as the first argument to f. +/// @return If the entire hashmap was iterated then 0 is returned. +/// Otherwise if the callback function f returned positive then the positive +/// value is returned. If the callback function returns -1, the current item +/// is removed and iteration continues. +static int hashmap_iterate_pairs(struct hashmap_s *const hashmap, + int (*f)(void *const, struct hashmap_element_s *const), + void *const context) HASHMAP_USED; + +/// @brief Get the size of the hashmap. +/// @param hashmap The hashmap to get the size of. +/// @return The size of the hashmap. +static unsigned +hashmap_num_entries(const struct hashmap_s *const hashmap) HASHMAP_USED; + +/// @brief Destroy the hashmap. +/// @param hashmap The hashmap to destroy. +static void hashmap_destroy(struct hashmap_s *const hashmap) HASHMAP_USED; + +static unsigned hashmap_crc32_helper(const char *const s, + const unsigned len) HASHMAP_USED; +static unsigned +hashmap_hash_helper_int_helper(const struct hashmap_s *const m, + const char *const keystring, + const unsigned len) HASHMAP_USED; +static int hashmap_match_helper(const struct hashmap_element_s *const element, + const char *const key, + const unsigned len) HASHMAP_USED; +static int hashmap_hash_helper(const struct hashmap_s *const m, + const char *const key, const unsigned len, + unsigned *const out_index) HASHMAP_USED; +static int hashmap_rehash_iterator(void *const new_hash, + struct hashmap_element_s *const e) HASHMAP_USED; +static int hashmap_rehash_helper(struct hashmap_s *const m) HASHMAP_USED; + +#if defined(__cplusplus) +} +#endif + +#if defined(__cplusplus) +#define HASHMAP_CAST(type, x) static_cast(x) +#define HASHMAP_PTR_CAST(type, x) reinterpret_cast(x) +#define HASHMAP_NULL NULL +#else +#define HASHMAP_CAST(type, x) ((type)x) +#define HASHMAP_PTR_CAST(type, x) ((type)x) +#define HASHMAP_NULL 0 +#endif + +int hashmap_create(const unsigned initial_size, + struct hashmap_s *const out_hashmap) { + if (0 == initial_size || 0 != (initial_size & (initial_size - 1))) { + return 1; + } + + out_hashmap->data = + HASHMAP_CAST(struct hashmap_element_s *, + calloc(initial_size, sizeof(struct hashmap_element_s))); + if (!out_hashmap->data) { + return 1; + } + + out_hashmap->table_size = initial_size; + out_hashmap->size = 0; + + return 0; +} + +int hashmap_put(struct hashmap_s *const m, const char *const key, + const unsigned len, void *const value) { + unsigned int index; + + /* Find a place to put our value. */ + while (!hashmap_hash_helper(m, key, len, &index)) { + if (hashmap_rehash_helper(m)) { + return 1; + } + } + + /* Set the data. */ + m->data[index].data = value; + m->data[index].key = key; + m->data[index].key_len = len; + m->data[index].in_use = 1; + m->size++; + + return 0; +} + +void *hashmap_get(const struct hashmap_s *const m, const char *const key, + const unsigned len) { + unsigned int curr; + unsigned int i; + + /* Find data location */ + curr = hashmap_hash_helper_int_helper(m, key, len); + + /* Linear probing, if necessary */ + for (i = 0; i < HASHMAP_MAX_CHAIN_LENGTH; i++) { + if (m->data[curr].in_use) { + if (hashmap_match_helper(&m->data[curr], key, len)) { + return m->data[curr].data; + } + } + + curr = (curr + 1) % m->table_size; + } + + /* Not found */ + return HASHMAP_NULL; +} + +int hashmap_remove(struct hashmap_s *const m, const char *const key, + const unsigned len) { + unsigned int i; + unsigned int curr; + + /* Find key */ + curr = hashmap_hash_helper_int_helper(m, key, len); + + /* Linear probing, if necessary */ + for (i = 0; i < HASHMAP_MAX_CHAIN_LENGTH; i++) { + if (m->data[curr].in_use) { + if (hashmap_match_helper(&m->data[curr], key, len)) { + /* Blank out the fields including in_use */ + memset(&m->data[curr], 0, sizeof(struct hashmap_element_s)); + + /* Reduce the size */ + m->size--; + return 0; + } + } + curr = (curr + 1) % m->table_size; + } + + return 1; +} + +int hashmap_iterate(const struct hashmap_s *const m, + int (*f)(void *const, void *const), void *const context) { + unsigned int i; + + /* Linear probing */ + for (i = 0; i < m->table_size; i++) { + if (m->data[i].in_use) { + if (!f(context, m->data[i].data)) { + return 1; + } + } + } + return 0; +} + +int hashmap_iterate_pairs(struct hashmap_s *const hashmap, + int (*f)(void *const, struct hashmap_element_s *const), + void *const context) { + unsigned int i; + struct hashmap_element_s *p; + int r; + + /* Linear probing */ + for (i = 0; i < hashmap->table_size; i++) { + p=&hashmap->data[i]; + if (p->in_use) { + r=f(context, p); + switch (r) + { + case -1: /* remove item */ + memset(p, 0, sizeof(struct hashmap_element_s)); + hashmap->size--; + break; + case 0: /* continue iterating */ + break; + default: /* early exit */ + return 1; + } + } + } + return 0; +} + +void hashmap_destroy(struct hashmap_s *const m) { + free(m->data); + memset(m, 0, sizeof(struct hashmap_s)); +} + +unsigned hashmap_num_entries(const struct hashmap_s *const m) { + return m->size; +} + +unsigned hashmap_crc32_helper(const char *const s, const unsigned len) { + unsigned i; + unsigned crc32val = 0; + +#if defined(HASHMAP_SSE42) + for (i = 0; i < len; i++) { + crc32val = _mm_crc32_u8(crc32val, HASHMAP_CAST(unsigned char, s[i])); + } + + return crc32val; +#else + // Using polynomial 0x11EDC6F41 to match SSE 4.2's crc function. + static const unsigned crc32_tab[] = { + 0x00000000U, 0xF26B8303U, 0xE13B70F7U, 0x1350F3F4U, 0xC79A971FU, + 0x35F1141CU, 0x26A1E7E8U, 0xD4CA64EBU, 0x8AD958CFU, 0x78B2DBCCU, + 0x6BE22838U, 0x9989AB3BU, 0x4D43CFD0U, 0xBF284CD3U, 0xAC78BF27U, + 0x5E133C24U, 0x105EC76FU, 0xE235446CU, 0xF165B798U, 0x030E349BU, + 0xD7C45070U, 0x25AFD373U, 0x36FF2087U, 0xC494A384U, 0x9A879FA0U, + 0x68EC1CA3U, 0x7BBCEF57U, 0x89D76C54U, 0x5D1D08BFU, 0xAF768BBCU, + 0xBC267848U, 0x4E4DFB4BU, 0x20BD8EDEU, 0xD2D60DDDU, 0xC186FE29U, + 0x33ED7D2AU, 0xE72719C1U, 0x154C9AC2U, 0x061C6936U, 0xF477EA35U, + 0xAA64D611U, 0x580F5512U, 0x4B5FA6E6U, 0xB93425E5U, 0x6DFE410EU, + 0x9F95C20DU, 0x8CC531F9U, 0x7EAEB2FAU, 0x30E349B1U, 0xC288CAB2U, + 0xD1D83946U, 0x23B3BA45U, 0xF779DEAEU, 0x05125DADU, 0x1642AE59U, + 0xE4292D5AU, 0xBA3A117EU, 0x4851927DU, 0x5B016189U, 0xA96AE28AU, + 0x7DA08661U, 0x8FCB0562U, 0x9C9BF696U, 0x6EF07595U, 0x417B1DBCU, + 0xB3109EBFU, 0xA0406D4BU, 0x522BEE48U, 0x86E18AA3U, 0x748A09A0U, + 0x67DAFA54U, 0x95B17957U, 0xCBA24573U, 0x39C9C670U, 0x2A993584U, + 0xD8F2B687U, 0x0C38D26CU, 0xFE53516FU, 0xED03A29BU, 0x1F682198U, + 0x5125DAD3U, 0xA34E59D0U, 0xB01EAA24U, 0x42752927U, 0x96BF4DCCU, + 0x64D4CECFU, 0x77843D3BU, 0x85EFBE38U, 0xDBFC821CU, 0x2997011FU, + 0x3AC7F2EBU, 0xC8AC71E8U, 0x1C661503U, 0xEE0D9600U, 0xFD5D65F4U, + 0x0F36E6F7U, 0x61C69362U, 0x93AD1061U, 0x80FDE395U, 0x72966096U, + 0xA65C047DU, 0x5437877EU, 0x4767748AU, 0xB50CF789U, 0xEB1FCBADU, + 0x197448AEU, 0x0A24BB5AU, 0xF84F3859U, 0x2C855CB2U, 0xDEEEDFB1U, + 0xCDBE2C45U, 0x3FD5AF46U, 0x7198540DU, 0x83F3D70EU, 0x90A324FAU, + 0x62C8A7F9U, 0xB602C312U, 0x44694011U, 0x5739B3E5U, 0xA55230E6U, + 0xFB410CC2U, 0x092A8FC1U, 0x1A7A7C35U, 0xE811FF36U, 0x3CDB9BDDU, + 0xCEB018DEU, 0xDDE0EB2AU, 0x2F8B6829U, 0x82F63B78U, 0x709DB87BU, + 0x63CD4B8FU, 0x91A6C88CU, 0x456CAC67U, 0xB7072F64U, 0xA457DC90U, + 0x563C5F93U, 0x082F63B7U, 0xFA44E0B4U, 0xE9141340U, 0x1B7F9043U, + 0xCFB5F4A8U, 0x3DDE77ABU, 0x2E8E845FU, 0xDCE5075CU, 0x92A8FC17U, + 0x60C37F14U, 0x73938CE0U, 0x81F80FE3U, 0x55326B08U, 0xA759E80BU, + 0xB4091BFFU, 0x466298FCU, 0x1871A4D8U, 0xEA1A27DBU, 0xF94AD42FU, + 0x0B21572CU, 0xDFEB33C7U, 0x2D80B0C4U, 0x3ED04330U, 0xCCBBC033U, + 0xA24BB5A6U, 0x502036A5U, 0x4370C551U, 0xB11B4652U, 0x65D122B9U, + 0x97BAA1BAU, 0x84EA524EU, 0x7681D14DU, 0x2892ED69U, 0xDAF96E6AU, + 0xC9A99D9EU, 0x3BC21E9DU, 0xEF087A76U, 0x1D63F975U, 0x0E330A81U, + 0xFC588982U, 0xB21572C9U, 0x407EF1CAU, 0x532E023EU, 0xA145813DU, + 0x758FE5D6U, 0x87E466D5U, 0x94B49521U, 0x66DF1622U, 0x38CC2A06U, + 0xCAA7A905U, 0xD9F75AF1U, 0x2B9CD9F2U, 0xFF56BD19U, 0x0D3D3E1AU, + 0x1E6DCDEEU, 0xEC064EEDU, 0xC38D26C4U, 0x31E6A5C7U, 0x22B65633U, + 0xD0DDD530U, 0x0417B1DBU, 0xF67C32D8U, 0xE52CC12CU, 0x1747422FU, + 0x49547E0BU, 0xBB3FFD08U, 0xA86F0EFCU, 0x5A048DFFU, 0x8ECEE914U, + 0x7CA56A17U, 0x6FF599E3U, 0x9D9E1AE0U, 0xD3D3E1ABU, 0x21B862A8U, + 0x32E8915CU, 0xC083125FU, 0x144976B4U, 0xE622F5B7U, 0xF5720643U, + 0x07198540U, 0x590AB964U, 0xAB613A67U, 0xB831C993U, 0x4A5A4A90U, + 0x9E902E7BU, 0x6CFBAD78U, 0x7FAB5E8CU, 0x8DC0DD8FU, 0xE330A81AU, + 0x115B2B19U, 0x020BD8EDU, 0xF0605BEEU, 0x24AA3F05U, 0xD6C1BC06U, + 0xC5914FF2U, 0x37FACCF1U, 0x69E9F0D5U, 0x9B8273D6U, 0x88D28022U, + 0x7AB90321U, 0xAE7367CAU, 0x5C18E4C9U, 0x4F48173DU, 0xBD23943EU, + 0xF36E6F75U, 0x0105EC76U, 0x12551F82U, 0xE03E9C81U, 0x34F4F86AU, + 0xC69F7B69U, 0xD5CF889DU, 0x27A40B9EU, 0x79B737BAU, 0x8BDCB4B9U, + 0x988C474DU, 0x6AE7C44EU, 0xBE2DA0A5U, 0x4C4623A6U, 0x5F16D052U, + 0xAD7D5351U}; + + for (i = 0; i < len; i++) { + crc32val = crc32_tab[(HASHMAP_CAST(unsigned char, crc32val) ^ + HASHMAP_CAST(unsigned char, s[i]))] ^ + (crc32val >> 8); + } + return crc32val; +#endif +} + +unsigned hashmap_hash_helper_int_helper(const struct hashmap_s *const m, + const char *const keystring, + const unsigned len) { + unsigned key = hashmap_crc32_helper(keystring, len); + + /* Robert Jenkins' 32 bit Mix Function */ + key += (key << 12); + key ^= (key >> 22); + key += (key << 4); + key ^= (key >> 9); + key += (key << 10); + key ^= (key >> 2); + key += (key << 7); + key ^= (key >> 12); + + /* Knuth's Multiplicative Method */ + key = (key >> 3) * 2654435761; + + return key % m->table_size; +} + +int hashmap_match_helper(const struct hashmap_element_s *const element, + const char *const key, const unsigned len) { + return (element->key_len == len) && (0 == memcmp(element->key, key, len)); +} + +int hashmap_hash_helper(const struct hashmap_s *const m, const char *const key, + const unsigned len, unsigned *const out_index) { + unsigned int curr; + unsigned int i; + + /* If full, return immediately */ + if (m->size >= m->table_size) { + return 0; + } + + /* Find the best index */ + curr = hashmap_hash_helper_int_helper(m, key, len); + + /* Linear probing */ + for (i = 0; i < HASHMAP_MAX_CHAIN_LENGTH; i++) { + if (!m->data[curr].in_use) { + *out_index = curr; + return 1; + } + + if (m->data[curr].in_use && + hashmap_match_helper(&m->data[curr], key, len)) { + *out_index = curr; + return 1; + } + + curr = (curr + 1) % m->table_size; + } + + return 0; +} + +int hashmap_rehash_iterator(void *const new_hash, + struct hashmap_element_s *const e) { + int temp=hashmap_put(HASHMAP_PTR_CAST(struct hashmap_s *, new_hash), + e->key, e->key_len, e->data); + if (0table_size; + + struct hashmap_s new_hash; + + int flag = hashmap_create(new_size, &new_hash); + if (0!=flag) { + return flag; + } + + /* copy the old elements to the new table */ + flag = hashmap_iterate_pairs(m, hashmap_rehash_iterator, HASHMAP_PTR_CAST(void *, &new_hash)); + if (0!=flag) { + return flag; + } + + hashmap_destroy(m); + /* put new hash into old hash structure by copying */ + memcpy(m, &new_hash, sizeof(struct hashmap_s)); + + return 0; +} + +#if defined(_MSC_VER) +#pragma warning(pop) +#elif defined(__clang__) +#pragma clang diagnostic pop +#endif + +#endif \ No newline at end of file diff --git a/v2/internal/ffenestri/json.c b/v2/internal/ffenestri/json.c new file mode 100644 index 000000000..d62ff9a03 --- /dev/null +++ b/v2/internal/ffenestri/json.c @@ -0,0 +1,1403 @@ +// +build !windows + +/* + Copyright (C) 2011 Joseph A. Adams (joeyadams3.14159@gmail.com) + All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + Source: http://git.ozlabs.org/?p=ccan;a=tree;f=ccan/json;hb=HEAD +*/ + +#include "json.h" + +#include +#include +#include +#include +#include + +#define out_of_memory() do { \ + fprintf(stderr, "Out of memory.\n"); \ + exit(EXIT_FAILURE); \ + } while (0) + +/* Sadly, strdup is not portable. */ +static char *json_strdup(const char *str) +{ + char *ret = (char*) malloc(strlen(str) + 1); + if (ret == NULL) + out_of_memory(); + strcpy(ret, str); + return ret; +} + +/* String buffer */ + +typedef struct +{ + char *cur; + char *end; + char *start; +} SB; + +static void sb_init(SB *sb) +{ + sb->start = (char*) malloc(17); + if (sb->start == NULL) + out_of_memory(); + sb->cur = sb->start; + sb->end = sb->start + 16; +} + +/* sb and need may be evaluated multiple times. */ +#define sb_need(sb, need) do { \ + if ((sb)->end - (sb)->cur < (need)) \ + sb_grow(sb, need); \ + } while (0) + +static void sb_grow(SB *sb, int need) +{ + size_t length = sb->cur - sb->start; + size_t alloc = sb->end - sb->start; + + do { + alloc *= 2; + } while (alloc < length + need); + + sb->start = (char*) realloc(sb->start, alloc + 1); + if (sb->start == NULL) + out_of_memory(); + sb->cur = sb->start + length; + sb->end = sb->start + alloc; +} + +static void sb_put(SB *sb, const char *bytes, int count) +{ + sb_need(sb, count); + memcpy(sb->cur, bytes, count); + sb->cur += count; +} + +#define sb_putc(sb, c) do { \ + if ((sb)->cur >= (sb)->end) \ + sb_grow(sb, 1); \ + *(sb)->cur++ = (c); \ + } while (0) + +static void sb_puts(SB *sb, const char *str) +{ + sb_put(sb, str, strlen(str)); +} + +static char *sb_finish(SB *sb) +{ + *sb->cur = 0; + assert(sb->start <= sb->cur && strlen(sb->start) == (size_t)(sb->cur - sb->start)); + return sb->start; +} + +static void sb_free(SB *sb) +{ + free(sb->start); +} + +/* + * Unicode helper functions + * + * These are taken from the ccan/charset module and customized a bit. + * Putting them here means the compiler can (choose to) inline them, + * and it keeps ccan/json from having a dependency. + */ + +/* + * Type for Unicode codepoints. + * We need our own because wchar_t might be 16 bits. + */ +typedef uint32_t uchar_t; + +/* + * Validate a single UTF-8 character starting at @s. + * The string must be null-terminated. + * + * If it's valid, return its length (1 thru 4). + * If it's invalid or clipped, return 0. + * + * This function implements the syntax given in RFC3629, which is + * the same as that given in The Unicode Standard, Version 6.0. + * + * It has the following properties: + * + * * All codepoints U+0000..U+10FFFF may be encoded, + * except for U+D800..U+DFFF, which are reserved + * for UTF-16 surrogate pair encoding. + * * UTF-8 byte sequences longer than 4 bytes are not permitted, + * as they exceed the range of Unicode. + * * The sixty-six Unicode "non-characters" are permitted + * (namely, U+FDD0..U+FDEF, U+xxFFFE, and U+xxFFFF). + */ +static int utf8_validate_cz(const char *s) +{ + unsigned char c = *s++; + + if (c <= 0x7F) { /* 00..7F */ + return 1; + } else if (c <= 0xC1) { /* 80..C1 */ + /* Disallow overlong 2-byte sequence. */ + return 0; + } else if (c <= 0xDF) { /* C2..DF */ + /* Make sure subsequent byte is in the range 0x80..0xBF. */ + if (((unsigned char)*s++ & 0xC0) != 0x80) + return 0; + + return 2; + } else if (c <= 0xEF) { /* E0..EF */ + /* Disallow overlong 3-byte sequence. */ + if (c == 0xE0 && (unsigned char)*s < 0xA0) + return 0; + + /* Disallow U+D800..U+DFFF. */ + if (c == 0xED && (unsigned char)*s > 0x9F) + return 0; + + /* Make sure subsequent bytes are in the range 0x80..0xBF. */ + if (((unsigned char)*s++ & 0xC0) != 0x80) + return 0; + if (((unsigned char)*s++ & 0xC0) != 0x80) + return 0; + + return 3; + } else if (c <= 0xF4) { /* F0..F4 */ + /* Disallow overlong 4-byte sequence. */ + if (c == 0xF0 && (unsigned char)*s < 0x90) + return 0; + + /* Disallow codepoints beyond U+10FFFF. */ + if (c == 0xF4 && (unsigned char)*s > 0x8F) + return 0; + + /* Make sure subsequent bytes are in the range 0x80..0xBF. */ + if (((unsigned char)*s++ & 0xC0) != 0x80) + return 0; + if (((unsigned char)*s++ & 0xC0) != 0x80) + return 0; + if (((unsigned char)*s++ & 0xC0) != 0x80) + return 0; + + return 4; + } else { /* F5..FF */ + return 0; + } +} + +/* Validate a null-terminated UTF-8 string. */ +static bool utf8_validate(const char *s) +{ + int len; + + for (; *s != 0; s += len) { + len = utf8_validate_cz(s); + if (len == 0) + return false; + } + + return true; +} + +/* + * Read a single UTF-8 character starting at @s, + * returning the length, in bytes, of the character read. + * + * This function assumes input is valid UTF-8, + * and that there are enough characters in front of @s. + */ +static int utf8_read_char(const char *s, uchar_t *out) +{ + const unsigned char *c = (const unsigned char*) s; + + assert(utf8_validate_cz(s)); + + if (c[0] <= 0x7F) { + /* 00..7F */ + *out = c[0]; + return 1; + } else if (c[0] <= 0xDF) { + /* C2..DF (unless input is invalid) */ + *out = ((uchar_t)c[0] & 0x1F) << 6 | + ((uchar_t)c[1] & 0x3F); + return 2; + } else if (c[0] <= 0xEF) { + /* E0..EF */ + *out = ((uchar_t)c[0] & 0xF) << 12 | + ((uchar_t)c[1] & 0x3F) << 6 | + ((uchar_t)c[2] & 0x3F); + return 3; + } else { + /* F0..F4 (unless input is invalid) */ + *out = ((uchar_t)c[0] & 0x7) << 18 | + ((uchar_t)c[1] & 0x3F) << 12 | + ((uchar_t)c[2] & 0x3F) << 6 | + ((uchar_t)c[3] & 0x3F); + return 4; + } +} + +/* + * Write a single UTF-8 character to @s, + * returning the length, in bytes, of the character written. + * + * @unicode must be U+0000..U+10FFFF, but not U+D800..U+DFFF. + * + * This function will write up to 4 bytes to @out. + */ +static int utf8_write_char(uchar_t unicode, char *out) +{ + unsigned char *o = (unsigned char*) out; + + assert(unicode <= 0x10FFFF && !(unicode >= 0xD800 && unicode <= 0xDFFF)); + + if (unicode <= 0x7F) { + /* U+0000..U+007F */ + *o++ = unicode; + return 1; + } else if (unicode <= 0x7FF) { + /* U+0080..U+07FF */ + *o++ = 0xC0 | unicode >> 6; + *o++ = 0x80 | (unicode & 0x3F); + return 2; + } else if (unicode <= 0xFFFF) { + /* U+0800..U+FFFF */ + *o++ = 0xE0 | unicode >> 12; + *o++ = 0x80 | (unicode >> 6 & 0x3F); + *o++ = 0x80 | (unicode & 0x3F); + return 3; + } else { + /* U+10000..U+10FFFF */ + *o++ = 0xF0 | unicode >> 18; + *o++ = 0x80 | (unicode >> 12 & 0x3F); + *o++ = 0x80 | (unicode >> 6 & 0x3F); + *o++ = 0x80 | (unicode & 0x3F); + return 4; + } +} + +/* + * Compute the Unicode codepoint of a UTF-16 surrogate pair. + * + * @uc should be 0xD800..0xDBFF, and @lc should be 0xDC00..0xDFFF. + * If they aren't, this function returns false. + */ +static bool from_surrogate_pair(uint16_t uc, uint16_t lc, uchar_t *unicode) +{ + if (uc >= 0xD800 && uc <= 0xDBFF && lc >= 0xDC00 && lc <= 0xDFFF) { + *unicode = 0x10000 + ((((uchar_t)uc & 0x3FF) << 10) | (lc & 0x3FF)); + return true; + } else { + return false; + } +} + +/* + * Construct a UTF-16 surrogate pair given a Unicode codepoint. + * + * @unicode must be U+10000..U+10FFFF. + */ +static void to_surrogate_pair(uchar_t unicode, uint16_t *uc, uint16_t *lc) +{ + uchar_t n; + + assert(unicode >= 0x10000 && unicode <= 0x10FFFF); + + n = unicode - 0x10000; + *uc = ((n >> 10) & 0x3FF) | 0xD800; + *lc = (n & 0x3FF) | 0xDC00; +} + +#define is_space(c) ((c) == '\t' || (c) == '\n' || (c) == '\r' || (c) == ' ') +#define is_digit(c) ((c) >= '0' && (c) <= '9') + +static bool parse_value (const char **sp, JsonNode **out); +static bool parse_string (const char **sp, char **out); +static bool parse_number (const char **sp, double *out); +static bool parse_array (const char **sp, JsonNode **out); +static bool parse_object (const char **sp, JsonNode **out); +static bool parse_hex16 (const char **sp, uint16_t *out); + +static bool expect_literal (const char **sp, const char *str); +static void skip_space (const char **sp); + +static void emit_value (SB *out, const JsonNode *node); +static void emit_value_indented (SB *out, const JsonNode *node, const char *space, int indent_level); +static void emit_string (SB *out, const char *str); +static void emit_number (SB *out, double num); +static void emit_array (SB *out, const JsonNode *array); +static void emit_array_indented (SB *out, const JsonNode *array, const char *space, int indent_level); +static void emit_object (SB *out, const JsonNode *object); +static void emit_object_indented (SB *out, const JsonNode *object, const char *space, int indent_level); + +static int write_hex16(char *out, uint16_t val); + +static JsonNode *mknode(JsonTag tag); +static void append_node(JsonNode *parent, JsonNode *child); +static void prepend_node(JsonNode *parent, JsonNode *child); +static void append_member(JsonNode *object, char *key, JsonNode *value); + +/* Assertion-friendly validity checks */ +static bool tag_is_valid(unsigned int tag); +static bool number_is_valid(const char *num); + +JsonNode *json_decode(const char *json) +{ + const char *s = json; + JsonNode *ret; + + skip_space(&s); + if (!parse_value(&s, &ret)) + return NULL; + + skip_space(&s); + if (*s != 0) { + json_delete(ret); + return NULL; + } + + return ret; +} + +char *json_encode(const JsonNode *node) +{ + return json_stringify(node, NULL); +} + +char *json_encode_string(const char *str) +{ + SB sb; + sb_init(&sb); + + emit_string(&sb, str); + + return sb_finish(&sb); +} + +char *json_stringify(const JsonNode *node, const char *space) +{ + SB sb; + sb_init(&sb); + + if (space != NULL) + emit_value_indented(&sb, node, space, 0); + else + emit_value(&sb, node); + + return sb_finish(&sb); +} + +void json_delete(JsonNode *node) +{ + if (node != NULL) { + json_remove_from_parent(node); + + switch (node->tag) { + case JSON_STRING: + free(node->string_); + break; + case JSON_ARRAY: + case JSON_OBJECT: + { + JsonNode *child, *next; + for (child = node->children.head; child != NULL; child = next) { + next = child->next; + json_delete(child); + } + break; + } + default:; + } + + free(node); + } +} + +bool json_validate(const char *json) +{ + const char *s = json; + + skip_space(&s); + if (!parse_value(&s, NULL)) + return false; + + skip_space(&s); + if (*s != 0) + return false; + + return true; +} + +// We return the number of elements or -1 if there was a problem +int json_array_length(JsonNode *array) { + + int result = 0; + + // The node should not be null and it should be an array + if (array == NULL || array->tag != JSON_ARRAY) + return -1; + + // Loop and count! + JsonNode *element; + json_foreach(element, array) { + result++; + } + + return result; +} + +JsonNode *json_find_element(JsonNode *array, int index) +{ + JsonNode *element; + int i = 0; + + if (array == NULL || array->tag != JSON_ARRAY) + return NULL; + + json_foreach(element, array) { + if (i == index) + return element; + i++; + } + + return NULL; +} + +JsonNode *json_find_member(JsonNode *object, const char *name) +{ + JsonNode *member; + + if (object == NULL || object->tag != JSON_OBJECT) + return NULL; + + json_foreach(member, object) + if (strcmp(member->key, name) == 0) + return member; + + return NULL; +} + +JsonNode *json_first_child(const JsonNode *node) +{ + if (node != NULL && (node->tag == JSON_ARRAY || node->tag == JSON_OBJECT)) + return node->children.head; + return NULL; +} + +static JsonNode *mknode(JsonTag tag) +{ + JsonNode *ret = (JsonNode*) calloc(1, sizeof(JsonNode)); + if (ret == NULL) + out_of_memory(); + ret->tag = tag; + return ret; +} + +JsonNode *json_mknull(void) +{ + return mknode(JSON_NULL); +} + +JsonNode *json_mkbool(bool b) +{ + JsonNode *ret = mknode(JSON_BOOL); + ret->bool_ = b; + return ret; +} + +static JsonNode *mkstring(char *s) +{ + JsonNode *ret = mknode(JSON_STRING); + ret->string_ = s; + return ret; +} + +JsonNode *json_mkstring(const char *s) +{ + return mkstring(json_strdup(s)); +} + +JsonNode *json_mknumber(double n) +{ + JsonNode *node = mknode(JSON_NUMBER); + node->number_ = n; + return node; +} + +JsonNode *json_mkarray(void) +{ + return mknode(JSON_ARRAY); +} + +JsonNode *json_mkobject(void) +{ + return mknode(JSON_OBJECT); +} + +static void append_node(JsonNode *parent, JsonNode *child) +{ + child->parent = parent; + child->prev = parent->children.tail; + child->next = NULL; + + if (parent->children.tail != NULL) + parent->children.tail->next = child; + else + parent->children.head = child; + parent->children.tail = child; +} + +static void prepend_node(JsonNode *parent, JsonNode *child) +{ + child->parent = parent; + child->prev = NULL; + child->next = parent->children.head; + + if (parent->children.head != NULL) + parent->children.head->prev = child; + else + parent->children.tail = child; + parent->children.head = child; +} + +static void append_member(JsonNode *object, char *key, JsonNode *value) +{ + value->key = key; + append_node(object, value); +} + +void json_append_element(JsonNode *array, JsonNode *element) +{ + assert(array->tag == JSON_ARRAY); + assert(element->parent == NULL); + + append_node(array, element); +} + +void json_prepend_element(JsonNode *array, JsonNode *element) +{ + assert(array->tag == JSON_ARRAY); + assert(element->parent == NULL); + + prepend_node(array, element); +} + +void json_append_member(JsonNode *object, const char *key, JsonNode *value) +{ + assert(object->tag == JSON_OBJECT); + assert(value->parent == NULL); + + append_member(object, json_strdup(key), value); +} + +void json_prepend_member(JsonNode *object, const char *key, JsonNode *value) +{ + assert(object->tag == JSON_OBJECT); + assert(value->parent == NULL); + + value->key = json_strdup(key); + prepend_node(object, value); +} + +void json_remove_from_parent(JsonNode *node) +{ + JsonNode *parent = node->parent; + + if (parent != NULL) { + if (node->prev != NULL) + node->prev->next = node->next; + else + parent->children.head = node->next; + if (node->next != NULL) + node->next->prev = node->prev; + else + parent->children.tail = node->prev; + + free(node->key); + + node->parent = NULL; + node->prev = node->next = NULL; + node->key = NULL; + } +} + +static bool parse_value(const char **sp, JsonNode **out) +{ + const char *s = *sp; + + switch (*s) { + case 'n': + if (expect_literal(&s, "null")) { + if (out) + *out = json_mknull(); + *sp = s; + return true; + } + return false; + + case 'f': + if (expect_literal(&s, "false")) { + if (out) + *out = json_mkbool(false); + *sp = s; + return true; + } + return false; + + case 't': + if (expect_literal(&s, "true")) { + if (out) + *out = json_mkbool(true); + *sp = s; + return true; + } + return false; + + case '"': { + char *str; + if (parse_string(&s, out ? &str : NULL)) { + if (out) + *out = mkstring(str); + *sp = s; + return true; + } + return false; + } + + case '[': + if (parse_array(&s, out)) { + *sp = s; + return true; + } + return false; + + case '{': + if (parse_object(&s, out)) { + *sp = s; + return true; + } + return false; + + default: { + double num; + if (parse_number(&s, out ? &num : NULL)) { + if (out) + *out = json_mknumber(num); + *sp = s; + return true; + } + return false; + } + } +} + +static bool parse_array(const char **sp, JsonNode **out) +{ + const char *s = *sp; + JsonNode *ret = out ? json_mkarray() : NULL; + JsonNode *element; + + if (*s++ != '[') + goto failure; + skip_space(&s); + + if (*s == ']') { + s++; + goto success; + } + + for (;;) { + if (!parse_value(&s, out ? &element : NULL)) + goto failure; + skip_space(&s); + + if (out) + json_append_element(ret, element); + + if (*s == ']') { + s++; + goto success; + } + + if (*s++ != ',') + goto failure; + skip_space(&s); + } + +success: + *sp = s; + if (out) + *out = ret; + return true; + +failure: + json_delete(ret); + return false; +} + +static bool parse_object(const char **sp, JsonNode **out) +{ + const char *s = *sp; + JsonNode *ret = out ? json_mkobject() : NULL; + char *key; + JsonNode *value; + + if (*s++ != '{') + goto failure; + skip_space(&s); + + if (*s == '}') { + s++; + goto success; + } + + for (;;) { + if (!parse_string(&s, out ? &key : NULL)) + goto failure; + skip_space(&s); + + if (*s++ != ':') + goto failure_free_key; + skip_space(&s); + + if (!parse_value(&s, out ? &value : NULL)) + goto failure_free_key; + skip_space(&s); + + if (out) + append_member(ret, key, value); + + if (*s == '}') { + s++; + goto success; + } + + if (*s++ != ',') + goto failure; + skip_space(&s); + } + +success: + *sp = s; + if (out) + *out = ret; + return true; + +failure_free_key: + if (out) + free(key); +failure: + json_delete(ret); + return false; +} + +bool parse_string(const char **sp, char **out) +{ + const char *s = *sp; + SB sb; + char throwaway_buffer[4]; + /* enough space for a UTF-8 character */ + char *b; + + if (*s++ != '"') + return false; + + if (out) { + sb_init(&sb); + sb_need(&sb, 4); + b = sb.cur; + } else { + b = throwaway_buffer; + } + + while (*s != '"') { + unsigned char c = *s++; + + /* Parse next character, and write it to b. */ + if (c == '\\') { + c = *s++; + switch (c) { + case '"': + case '\\': + case '/': + *b++ = c; + break; + case 'b': + *b++ = '\b'; + break; + case 'f': + *b++ = '\f'; + break; + case 'n': + *b++ = '\n'; + break; + case 'r': + *b++ = '\r'; + break; + case 't': + *b++ = '\t'; + break; + case 'u': + { + uint16_t uc, lc; + uchar_t unicode; + + if (!parse_hex16(&s, &uc)) + goto failed; + + if (uc >= 0xD800 && uc <= 0xDFFF) { + /* Handle UTF-16 surrogate pair. */ + if (*s++ != '\\' || *s++ != 'u' || !parse_hex16(&s, &lc)) + goto failed; /* Incomplete surrogate pair. */ + if (!from_surrogate_pair(uc, lc, &unicode)) + goto failed; /* Invalid surrogate pair. */ + } else if (uc == 0) { + /* Disallow "\u0000". */ + goto failed; + } else { + unicode = uc; + } + + b += utf8_write_char(unicode, b); + break; + } + default: + /* Invalid escape */ + goto failed; + } + } else if (c <= 0x1F) { + /* Control characters are not allowed in string literals. */ + goto failed; + } else { + /* Validate and echo a UTF-8 character. */ + int len; + + s--; + len = utf8_validate_cz(s); + if (len == 0) + goto failed; /* Invalid UTF-8 character. */ + + while (len--) + *b++ = *s++; + } + + /* + * Update sb to know about the new bytes, + * and set up b to write another character. + */ + if (out) { + sb.cur = b; + sb_need(&sb, 4); + b = sb.cur; + } else { + b = throwaway_buffer; + } + } + s++; + + if (out) + *out = sb_finish(&sb); + *sp = s; + return true; + +failed: + if (out) + sb_free(&sb); + return false; +} + +/* + * The JSON spec says that a number shall follow this precise pattern + * (spaces and quotes added for readability): + * '-'? (0 | [1-9][0-9]*) ('.' [0-9]+)? ([Ee] [+-]? [0-9]+)? + * + * However, some JSON parsers are more liberal. For instance, PHP accepts + * '.5' and '1.'. JSON.parse accepts '+3'. + * + * This function takes the strict approach. + */ +bool parse_number(const char **sp, double *out) +{ + const char *s = *sp; + + /* '-'? */ + if (*s == '-') + s++; + + /* (0 | [1-9][0-9]*) */ + if (*s == '0') { + s++; + } else { + if (!is_digit(*s)) + return false; + do { + s++; + } while (is_digit(*s)); + } + + /* ('.' [0-9]+)? */ + if (*s == '.') { + s++; + if (!is_digit(*s)) + return false; + do { + s++; + } while (is_digit(*s)); + } + + /* ([Ee] [+-]? [0-9]+)? */ + if (*s == 'E' || *s == 'e') { + s++; + if (*s == '+' || *s == '-') + s++; + if (!is_digit(*s)) + return false; + do { + s++; + } while (is_digit(*s)); + } + + if (out) + *out = strtod(*sp, NULL); + + *sp = s; + return true; +} + +static void skip_space(const char **sp) +{ + const char *s = *sp; + while (is_space(*s)) + s++; + *sp = s; +} + +static void emit_value(SB *out, const JsonNode *node) +{ + assert(tag_is_valid(node->tag)); + switch (node->tag) { + case JSON_NULL: + sb_puts(out, "null"); + break; + case JSON_BOOL: + sb_puts(out, node->bool_ ? "true" : "false"); + break; + case JSON_STRING: + emit_string(out, node->string_); + break; + case JSON_NUMBER: + emit_number(out, node->number_); + break; + case JSON_ARRAY: + emit_array(out, node); + break; + case JSON_OBJECT: + emit_object(out, node); + break; + default: + assert(false); + } +} + +void emit_value_indented(SB *out, const JsonNode *node, const char *space, int indent_level) +{ + assert(tag_is_valid(node->tag)); + switch (node->tag) { + case JSON_NULL: + sb_puts(out, "null"); + break; + case JSON_BOOL: + sb_puts(out, node->bool_ ? "true" : "false"); + break; + case JSON_STRING: + emit_string(out, node->string_); + break; + case JSON_NUMBER: + emit_number(out, node->number_); + break; + case JSON_ARRAY: + emit_array_indented(out, node, space, indent_level); + break; + case JSON_OBJECT: + emit_object_indented(out, node, space, indent_level); + break; + default: + assert(false); + } +} + +static void emit_array(SB *out, const JsonNode *array) +{ + const JsonNode *element; + + sb_putc(out, '['); + json_foreach(element, array) { + emit_value(out, element); + if (element->next != NULL) + sb_putc(out, ','); + } + sb_putc(out, ']'); +} + +static void emit_array_indented(SB *out, const JsonNode *array, const char *space, int indent_level) +{ + const JsonNode *element = array->children.head; + int i; + + if (element == NULL) { + sb_puts(out, "[]"); + return; + } + + sb_puts(out, "[\n"); + while (element != NULL) { + for (i = 0; i < indent_level + 1; i++) + sb_puts(out, space); + emit_value_indented(out, element, space, indent_level + 1); + + element = element->next; + sb_puts(out, element != NULL ? ",\n" : "\n"); + } + for (i = 0; i < indent_level; i++) + sb_puts(out, space); + sb_putc(out, ']'); +} + +static void emit_object(SB *out, const JsonNode *object) +{ + const JsonNode *member; + + sb_putc(out, '{'); + json_foreach(member, object) { + emit_string(out, member->key); + sb_putc(out, ':'); + emit_value(out, member); + if (member->next != NULL) + sb_putc(out, ','); + } + sb_putc(out, '}'); +} + +static void emit_object_indented(SB *out, const JsonNode *object, const char *space, int indent_level) +{ + const JsonNode *member = object->children.head; + int i; + + if (member == NULL) { + sb_puts(out, "{}"); + return; + } + + sb_puts(out, "{\n"); + while (member != NULL) { + for (i = 0; i < indent_level + 1; i++) + sb_puts(out, space); + emit_string(out, member->key); + sb_puts(out, ": "); + emit_value_indented(out, member, space, indent_level + 1); + + member = member->next; + sb_puts(out, member != NULL ? ",\n" : "\n"); + } + for (i = 0; i < indent_level; i++) + sb_puts(out, space); + sb_putc(out, '}'); +} + +void emit_string(SB *out, const char *str) +{ + bool escape_unicode = false; + const char *s = str; + char *b; + + assert(utf8_validate(str)); + + /* + * 14 bytes is enough space to write up to two + * \uXXXX escapes and two quotation marks. + */ + sb_need(out, 14); + b = out->cur; + + *b++ = '"'; + while (*s != 0) { + unsigned char c = *s++; + + /* Encode the next character, and write it to b. */ + switch (c) { + case '"': + *b++ = '\\'; + *b++ = '"'; + break; + case '\\': + *b++ = '\\'; + *b++ = '\\'; + break; + case '\b': + *b++ = '\\'; + *b++ = 'b'; + break; + case '\f': + *b++ = '\\'; + *b++ = 'f'; + break; + case '\n': + *b++ = '\\'; + *b++ = 'n'; + break; + case '\r': + *b++ = '\\'; + *b++ = 'r'; + break; + case '\t': + *b++ = '\\'; + *b++ = 't'; + break; + default: { + int len; + + s--; + len = utf8_validate_cz(s); + + if (len == 0) { + /* + * Handle invalid UTF-8 character gracefully in production + * by writing a replacement character (U+FFFD) + * and skipping a single byte. + * + * This should never happen when assertions are enabled + * due to the assertion at the beginning of this function. + */ + assert(false); + if (escape_unicode) { + strcpy(b, "\\uFFFD"); + b += 6; + } else { + *b++ = 0xEF; + *b++ = 0xBF; + *b++ = 0xBD; + } + s++; + } else if (c < 0x1F || (c >= 0x80 && escape_unicode)) { + /* Encode using \u.... */ + uint32_t unicode; + + s += utf8_read_char(s, &unicode); + + if (unicode <= 0xFFFF) { + *b++ = '\\'; + *b++ = 'u'; + b += write_hex16(b, unicode); + } else { + /* Produce a surrogate pair. */ + uint16_t uc, lc; + assert(unicode <= 0x10FFFF); + to_surrogate_pair(unicode, &uc, &lc); + *b++ = '\\'; + *b++ = 'u'; + b += write_hex16(b, uc); + *b++ = '\\'; + *b++ = 'u'; + b += write_hex16(b, lc); + } + } else { + /* Write the character directly. */ + while (len--) + *b++ = *s++; + } + + break; + } + } + + /* + * Update *out to know about the new bytes, + * and set up b to write another encoded character. + */ + out->cur = b; + sb_need(out, 14); + b = out->cur; + } + *b++ = '"'; + + out->cur = b; +} + +static void emit_number(SB *out, double num) +{ + /* + * This isn't exactly how JavaScript renders numbers, + * but it should produce valid JSON for reasonable numbers + * preserve precision well enough, and avoid some oddities + * like 0.3 -> 0.299999999999999988898 . + */ + char buf[64]; + sprintf(buf, "%.16g", num); + + if (number_is_valid(buf)) + sb_puts(out, buf); + else + sb_puts(out, "null"); +} + +static bool tag_is_valid(unsigned int tag) +{ + return (/* tag >= JSON_NULL && */ tag <= JSON_OBJECT); +} + +static bool number_is_valid(const char *num) +{ + return (parse_number(&num, NULL) && *num == '\0'); +} + +static bool expect_literal(const char **sp, const char *str) +{ + const char *s = *sp; + + while (*str != '\0') + if (*s++ != *str++) + return false; + + *sp = s; + return true; +} + +/* + * Parses exactly 4 hex characters (capital or lowercase). + * Fails if any input chars are not [0-9A-Fa-f]. + */ +static bool parse_hex16(const char **sp, uint16_t *out) +{ + const char *s = *sp; + uint16_t ret = 0; + uint16_t i; + uint16_t tmp; + char c; + + for (i = 0; i < 4; i++) { + c = *s++; + if (c >= '0' && c <= '9') + tmp = c - '0'; + else if (c >= 'A' && c <= 'F') + tmp = c - 'A' + 10; + else if (c >= 'a' && c <= 'f') + tmp = c - 'a' + 10; + else + return false; + + ret <<= 4; + ret += tmp; + } + + if (out) + *out = ret; + *sp = s; + return true; +} + +/* + * Encodes a 16-bit number into hexadecimal, + * writing exactly 4 hex chars. + */ +static int write_hex16(char *out, uint16_t val) +{ + const char *hex = "0123456789ABCDEF"; + + *out++ = hex[(val >> 12) & 0xF]; + *out++ = hex[(val >> 8) & 0xF]; + *out++ = hex[(val >> 4) & 0xF]; + *out++ = hex[ val & 0xF]; + + return 4; +} + +bool json_check(const JsonNode *node, char errmsg[256]) +{ + #define problem(...) do { \ + if (errmsg != NULL) \ + snprintf(errmsg, 256, __VA_ARGS__); \ + return false; \ + } while (0) + + if (node->key != NULL && !utf8_validate(node->key)) + problem("key contains invalid UTF-8"); + + if (!tag_is_valid(node->tag)) + problem("tag is invalid (%u)", node->tag); + + if (node->tag == JSON_BOOL) { + if (node->bool_ != false && node->bool_ != true) + problem("bool_ is neither false (%d) nor true (%d)", (int)false, (int)true); + } else if (node->tag == JSON_STRING) { + if (node->string_ == NULL) + problem("string_ is NULL"); + if (!utf8_validate(node->string_)) + problem("string_ contains invalid UTF-8"); + } else if (node->tag == JSON_ARRAY || node->tag == JSON_OBJECT) { + JsonNode *head = node->children.head; + JsonNode *tail = node->children.tail; + + if (head == NULL || tail == NULL) { + if (head != NULL) + problem("tail is NULL, but head is not"); + if (tail != NULL) + problem("head is NULL, but tail is not"); + } else { + JsonNode *child; + JsonNode *last = NULL; + + if (head->prev != NULL) + problem("First child's prev pointer is not NULL"); + + for (child = head; child != NULL; last = child, child = child->next) { + if (child == node) + problem("node is its own child"); + if (child->next == child) + problem("child->next == child (cycle)"); + if (child->next == head) + problem("child->next == head (cycle)"); + + if (child->parent != node) + problem("child does not point back to parent"); + if (child->next != NULL && child->next->prev != child) + problem("child->next does not point back to child"); + + if (node->tag == JSON_ARRAY && child->key != NULL) + problem("Array element's key is not NULL"); + if (node->tag == JSON_OBJECT && child->key == NULL) + problem("Object member's key is NULL"); + + if (!json_check(child, errmsg)) + return false; + } + + if (last != tail) + problem("tail does not match pointer found by starting at head and following next links"); + } + } + + return true; + + #undef problem +} \ No newline at end of file diff --git a/v2/internal/ffenestri/json.h b/v2/internal/ffenestri/json.h new file mode 100644 index 000000000..aaf711f8a --- /dev/null +++ b/v2/internal/ffenestri/json.h @@ -0,0 +1,122 @@ +/* + Copyright (C) 2011 Joseph A. Adams (joeyadams3.14159@gmail.com) + All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + Source: http://git.ozlabs.org/?p=ccan;a=tree;f=ccan/json;hb=HEAD +*/ + +#ifndef CCAN_JSON_H +#define CCAN_JSON_H + +#include +#include + +typedef enum { + JSON_NULL, + JSON_BOOL, + JSON_STRING, + JSON_NUMBER, + JSON_ARRAY, + JSON_OBJECT, +} JsonTag; + +typedef struct JsonNode JsonNode; + +struct JsonNode +{ + /* only if parent is an object or array (NULL otherwise) */ + JsonNode *parent; + JsonNode *prev, *next; + + /* only if parent is an object (NULL otherwise) */ + char *key; /* Must be valid UTF-8. */ + + JsonTag tag; + union { + /* JSON_BOOL */ + bool bool_; + + /* JSON_STRING */ + char *string_; /* Must be valid UTF-8. */ + + /* JSON_NUMBER */ + double number_; + + /* JSON_ARRAY */ + /* JSON_OBJECT */ + struct { + JsonNode *head, *tail; + } children; + }; +}; + +/*** Encoding, decoding, and validation ***/ + +JsonNode *json_decode (const char *json); +char *json_encode (const JsonNode *node); +char *json_encode_string (const char *str); +char *json_stringify (const JsonNode *node, const char *space); +void json_delete (JsonNode *node); + +bool json_validate (const char *json); + +/*** Lookup and traversal ***/ + +JsonNode *json_find_element (JsonNode *array, int index); +JsonNode *json_find_member (JsonNode *object, const char *key); + +JsonNode *json_first_child (const JsonNode *node); + +#define json_foreach(i, object_or_array) \ + for ((i) = json_first_child(object_or_array); \ + (i) != NULL; \ + (i) = (i)->next) + +/*** Construction and manipulation ***/ + +JsonNode *json_mknull(void); +JsonNode *json_mkbool(bool b); +JsonNode *json_mkstring(const char *s); +JsonNode *json_mknumber(double n); +JsonNode *json_mkarray(void); +JsonNode *json_mkobject(void); + +void json_append_element(JsonNode *array, JsonNode *element); +void json_prepend_element(JsonNode *array, JsonNode *element); +void json_append_member(JsonNode *object, const char *key, JsonNode *value); +void json_prepend_member(JsonNode *object, const char *key, JsonNode *value); + +void json_remove_from_parent(JsonNode *node); + +/*** Debugging ***/ + +/* + * Look for structure and encoding problems in a JsonNode or its descendents. + * + * If a problem is detected, return false, writing a description of the problem + * to errmsg (unless errmsg is NULL). + */ +bool json_check(const JsonNode *node, char errmsg[256]); + +// Added by Lea Anthony 28/11/2020 +int json_array_length(JsonNode *array); + +#endif \ No newline at end of file diff --git a/v2/internal/ffenestri/menu_darwin.c b/v2/internal/ffenestri/menu_darwin.c new file mode 100644 index 000000000..282d3331e --- /dev/null +++ b/v2/internal/ffenestri/menu_darwin.c @@ -0,0 +1,1001 @@ +// +// Created by Lea Anthony on 6/1/21. +// + +#include "ffenestri_darwin.h" +#include "menu_darwin.h" +#include "contextmenus_darwin.h" +#include "common.h" + +// NewMenu creates a new Menu struct, saving the given menu structure as JSON +Menu* NewMenu(JsonNode *menuData) { + + Menu *result = malloc(sizeof(Menu)); + + result->processedMenu = menuData; + + // No title by default + result->title = ""; + + // Initialise menuCallbackDataCache + vec_init(&result->callbackDataCache); + + // Allocate MenuItem Map + if( 0 != hashmap_create((const unsigned)16, &result->menuItemMap)) { + ABORT("[NewMenu] Not enough memory to allocate menuItemMap!"); + } + // Allocate the Radio Group Map + if( 0 != hashmap_create((const unsigned)4, &result->radioGroupMap)) { + ABORT("[NewMenu] Not enough memory to allocate radioGroupMap!"); + } + + // Init other members + result->menu = NULL; + result->parentData = NULL; + + return result; +} + +Menu* NewApplicationMenu(const char *menuAsJSON) { + + // Parse the menu json + JsonNode *processedMenu = json_decode(menuAsJSON); + if( processedMenu == NULL ) { + // Parse error! + ABORT("Unable to parse Menu JSON: %s", menuAsJSON); + } + + Menu *result = NewMenu(processedMenu); + result->menuType = ApplicationMenuType; + return result; +} + +MenuItemCallbackData* CreateMenuItemCallbackData(Menu *menu, id menuItem, const char *menuID, enum MenuItemType menuItemType) { + MenuItemCallbackData* result = malloc(sizeof(MenuItemCallbackData)); + + result->menu = menu; + result->menuID = menuID; + result->menuItem = menuItem; + result->menuItemType = menuItemType; + + // Store reference to this so we can destroy later + vec_push(&menu->callbackDataCache, result); + + return result; +} + +void DeleteMenu(Menu *menu) { + + // Free menu item hashmap + hashmap_destroy(&menu->menuItemMap); + + // Free radio group members + if( hashmap_num_entries(&menu->radioGroupMap) > 0 ) { + if (0 != hashmap_iterate_pairs(&menu->radioGroupMap, freeHashmapItem, NULL)) { + ABORT("[DeleteMenu] Failed to release radioGroupMap entries!"); + } + } + + // Free radio groups hashmap + hashmap_destroy(&menu->radioGroupMap); + + // Free up the processed menu memory + if (menu->processedMenu != NULL) { + json_delete(menu->processedMenu); + menu->processedMenu = NULL; + } + + // Release the callback data memory + vector + int i; MenuItemCallbackData* callbackData; + vec_foreach(&menu->callbackDataCache, callbackData, i) { + free(callbackData); + } + vec_deinit(&menu->callbackDataCache); + + free(menu); +} + +// Creates a JSON message for the given menuItemID and data +const char* createMenuClickedMessage(const char *menuItemID, const char *data, enum MenuType menuType, const char *parentID) { + + JsonNode *jsonObject = json_mkobject(); + if (menuItemID == NULL ) { + ABORT("Item ID NULL for menu!!\n"); + } + json_append_member(jsonObject, "menuItemID", json_mkstring(menuItemID)); + json_append_member(jsonObject, "menuType", json_mkstring(MenuTypeAsString[(int)menuType])); + if (data != NULL) { + json_append_member(jsonObject, "data", json_mkstring(data)); + } + if (parentID != NULL) { + json_append_member(jsonObject, "parentID", json_mkstring(parentID)); + } + const char *payload = json_encode(jsonObject); + json_delete(jsonObject); + const char *result = concat("MC", payload); + MEMFREE(payload); + return result; +} + +// Callback for text menu items +void menuItemCallback(id self, SEL cmd, id sender) { + MenuItemCallbackData *callbackData = (MenuItemCallbackData *)msg_reg(msg_reg(sender, s("representedObject")), s("pointerValue")); + const char *message; + + // Update checkbox / radio item + if( callbackData->menuItemType == Checkbox) { + // Toggle state + bool state = msg_reg(callbackData->menuItem, s("state")); + msg_int(callbackData->menuItem, s("setState:"), (state? NSControlStateValueOff : NSControlStateValueOn)); + } else if( callbackData->menuItemType == Radio ) { + // Check the menu items' current state + bool selected = (bool)msg_reg(callbackData->menuItem, s("state")); + + // If it's already selected, exit early + if (selected) return; + + // Get this item's radio group members and turn them off + id *members = (id*)hashmap_get(&(callbackData->menu->radioGroupMap), (char*)callbackData->menuID, strlen(callbackData->menuID)); + + // Uncheck all members of the group + id thisMember = members[0]; + int count = 0; + while(thisMember != NULL) { + msg_int(thisMember, s("setState:"), NSControlStateValueOff); + count = count + 1; + thisMember = members[count]; + } + + // check the selected menu item + msg_int(callbackData->menuItem, s("setState:"), NSControlStateValueOn); + } + + const char *menuID = callbackData->menuID; + const char *data = NULL; + enum MenuType menuType = callbackData->menu->menuType; + const char *parentID = NULL; + + // Generate message to send to backend + if( menuType == ContextMenuType ) { + // Get the context menu data from the menu + ContextMenu* contextMenu = (ContextMenu*) callbackData->menu->parentData; + data = contextMenu->contextMenuData; + parentID = contextMenu->ID; + } else if ( menuType == TrayMenuType ) { + parentID = (const char*) callbackData->menu->parentData; + } + + message = createMenuClickedMessage(menuID, data, menuType, parentID); + + // Notify the backend + messageFromWindowCallback(message); + MEMFREE(message); +} + +id processAcceleratorKey(const char *key) { + + // Guard against no accelerator key + if( key == NULL ) { + return str(""); + } + + if( STREQ(key, "backspace") ) { + return strunicode(0x0008); + } + if( STREQ(key, "tab") ) { + return strunicode(0x0009); + } + if( STREQ(key, "return") ) { + return strunicode(0x000d); + } + if( STREQ(key, "enter") ) { + return strunicode(0x000d); + } + if( STREQ(key, "escape") ) { + return strunicode(0x001b); + } + if( STREQ(key, "left") ) { + return strunicode(0x001c); + } + if( STREQ(key, "right") ) { + return strunicode(0x001d); + } + if( STREQ(key, "up") ) { + return strunicode(0x001e); + } + if( STREQ(key, "down") ) { + return strunicode(0x001f); + } + if( STREQ(key, "space") ) { + return strunicode(0x0020); + } + if( STREQ(key, "delete") ) { + return strunicode(0x007f); + } + if( STREQ(key, "home") ) { + return strunicode(0x2196); + } + if( STREQ(key, "end") ) { + return strunicode(0x2198); + } + if( STREQ(key, "page up") ) { + return strunicode(0x21de); + } + if( STREQ(key, "page down") ) { + return strunicode(0x21df); + } + if( STREQ(key, "f1") ) { + return strunicode(0xf704); + } + if( STREQ(key, "f2") ) { + return strunicode(0xf705); + } + if( STREQ(key, "f3") ) { + return strunicode(0xf706); + } + if( STREQ(key, "f4") ) { + return strunicode(0xf707); + } + if( STREQ(key, "f5") ) { + return strunicode(0xf708); + } + if( STREQ(key, "f6") ) { + return strunicode(0xf709); + } + if( STREQ(key, "f7") ) { + return strunicode(0xf70a); + } + if( STREQ(key, "f8") ) { + return strunicode(0xf70b); + } + if( STREQ(key, "f9") ) { + return strunicode(0xf70c); + } + if( STREQ(key, "f10") ) { + return strunicode(0xf70d); + } + if( STREQ(key, "f11") ) { + return strunicode(0xf70e); + } + if( STREQ(key, "f12") ) { + return strunicode(0xf70f); + } + if( STREQ(key, "f13") ) { + return strunicode(0xf710); + } + if( STREQ(key, "f14") ) { + return strunicode(0xf711); + } + if( STREQ(key, "f15") ) { + return strunicode(0xf712); + } + if( STREQ(key, "f16") ) { + return strunicode(0xf713); + } + if( STREQ(key, "f17") ) { + return strunicode(0xf714); + } + if( STREQ(key, "f18") ) { + return strunicode(0xf715); + } + if( STREQ(key, "f19") ) { + return strunicode(0xf716); + } + if( STREQ(key, "f20") ) { + return strunicode(0xf717); + } + if( STREQ(key, "f21") ) { + return strunicode(0xf718); + } + if( STREQ(key, "f22") ) { + return strunicode(0xf719); + } + if( STREQ(key, "f23") ) { + return strunicode(0xf71a); + } + if( STREQ(key, "f24") ) { + return strunicode(0xf71b); + } + if( STREQ(key, "f25") ) { + return strunicode(0xf71c); + } + if( STREQ(key, "f26") ) { + return strunicode(0xf71d); + } + if( STREQ(key, "f27") ) { + return strunicode(0xf71e); + } + if( STREQ(key, "f28") ) { + return strunicode(0xf71f); + } + if( STREQ(key, "f29") ) { + return strunicode(0xf720); + } + if( STREQ(key, "f30") ) { + return strunicode(0xf721); + } + if( STREQ(key, "f31") ) { + return strunicode(0xf722); + } + if( STREQ(key, "f32") ) { + return strunicode(0xf723); + } + if( STREQ(key, "f33") ) { + return strunicode(0xf724); + } + if( STREQ(key, "f34") ) { + return strunicode(0xf725); + } + if( STREQ(key, "f35") ) { + return strunicode(0xf726); + } +// if( STREQ(key, "Insert") ) { +// return strunicode(0xf727); +// } +// if( STREQ(key, "PrintScreen") ) { +// return strunicode(0xf72e); +// } +// if( STREQ(key, "ScrollLock") ) { +// return strunicode(0xf72f); +// } + if( STREQ(key, "numLock") ) { + return strunicode(0xf739); + } + + return str(key); +} + + +void addSeparator(id menu) { + id item = msg_reg(c("NSMenuItem"), s("separatorItem")); + msg_id(menu, s("addItem:"), item); +} + +id createMenuItemNoAutorelease( id title, const char *action, const char *key) { + id item = ALLOC("NSMenuItem"); + ((id(*)(id, SEL, id, SEL, id))objc_msgSend)(item, s("initWithTitle:action:keyEquivalent:"), title, s(action), str(key)); + return item; +} + +id createMenuItem(id title, const char *action, const char *key) { + id item = ALLOC("NSMenuItem"); + ((id(*)(id, SEL, id, SEL, id))objc_msgSend)(item, s("initWithTitle:action:keyEquivalent:"), title, s(action), str(key)); + msg_reg(item, s("autorelease")); + return item; +} + +id addMenuItem(id menu, const char *title, const char *action, const char *key, bool disabled) { + id item = createMenuItem(str(title), action, key); + msg_bool(item, s("setEnabled:"), !disabled); + msg_id(menu, s("addItem:"), item); + return item; +} + +id createMenu(id title) { + id menu = ALLOC("NSMenu"); + msg_id(menu, s("initWithTitle:"), title); + msg_bool(menu, s("setAutoenablesItems:"), NO); + msg_reg(menu, s("autorelease")); + return menu; +} + +void createDefaultAppMenu(id parentMenu) { +// App Menu + id appName = msg_reg(msg_reg(c("NSProcessInfo"), s("processInfo")), s("processName")); + id appMenuItem = createMenuItemNoAutorelease(appName, NULL, ""); + id appMenu = createMenu(appName); + + msg_id(appMenuItem, s("setSubmenu:"), appMenu); + msg_id(parentMenu, s("addItem:"), appMenuItem); + + id title = msg_id(str("Hide "), s("stringByAppendingString:"), appName); + id item = createMenuItem(title, "hide:", "h"); + msg_id(appMenu, s("addItem:"), item); + + id hideOthers = addMenuItem(appMenu, "Hide Others", "hideOtherApplications:", "h", FALSE); + msg_int(hideOthers, s("setKeyEquivalentModifierMask:"), (NSEventModifierFlagOption | NSEventModifierFlagCommand)); + + addMenuItem(appMenu, "Show All", "unhideAllApplications:", "", FALSE); + + addSeparator(appMenu); + + title = msg_id(str("Quit "), s("stringByAppendingString:"), appName); + item = createMenuItem(title, "terminate:", "q"); + msg_id(appMenu, s("addItem:"), item); +} + +void createDefaultEditMenu(id parentMenu) { + // Edit Menu + id editMenuItem = createMenuItemNoAutorelease(str("Edit"), NULL, ""); + id editMenu = createMenu(str("Edit")); + + msg_id(editMenuItem, s("setSubmenu:"), editMenu); + msg_id(parentMenu, s("addItem:"), editMenuItem); + + addMenuItem(editMenu, "Undo", "undo:", "z", FALSE); + addMenuItem(editMenu, "Redo", "redo:", "y", FALSE); + addSeparator(editMenu); + addMenuItem(editMenu, "Cut", "cut:", "x", FALSE); + addMenuItem(editMenu, "Copy", "copy:", "c", FALSE); + addMenuItem(editMenu, "Paste", "paste:", "v", FALSE); + addMenuItem(editMenu, "Select All", "selectAll:", "a", FALSE); +} + +void processMenuRole(Menu *menu, id parentMenu, JsonNode *item) { + const char *roleName = item->string_; + + if ( STREQ(roleName, "appMenu") ) { + createDefaultAppMenu(parentMenu); + return; + } + if ( STREQ(roleName, "editMenu")) { + createDefaultEditMenu(parentMenu); + return; + } + if ( STREQ(roleName, "hide")) { + addMenuItem(parentMenu, "Hide Window", "hide:", "h", FALSE); + return; + } + if ( STREQ(roleName, "hideothers")) { + id hideOthers = addMenuItem(parentMenu, "Hide Others", "hideOtherApplications:", "h", FALSE); + msg_int(hideOthers, s("setKeyEquivalentModifierMask:"), (NSEventModifierFlagOption | NSEventModifierFlagCommand)); + return; + } + if ( STREQ(roleName, "unhide")) { + addMenuItem(parentMenu, "Show All", "unhideAllApplications:", "", FALSE); + return; + } + if ( STREQ(roleName, "front")) { + addMenuItem(parentMenu, "Bring All to Front", "arrangeInFront:", "", FALSE); + return; + } + if ( STREQ(roleName, "undo")) { + addMenuItem(parentMenu, "Undo", "undo:", "z", FALSE); + return; + } + if ( STREQ(roleName, "redo")) { + addMenuItem(parentMenu, "Redo", "redo:", "y", FALSE); + return; + } + if ( STREQ(roleName, "cut")) { + addMenuItem(parentMenu, "Cut", "cut:", "x", FALSE); + return; + } + if ( STREQ(roleName, "copy")) { + addMenuItem(parentMenu, "Copy", "copy:", "c", FALSE); + return; + } + if ( STREQ(roleName, "paste")) { + addMenuItem(parentMenu, "Paste", "paste:", "v", FALSE); + return; + } + if ( STREQ(roleName, "delete")) { + addMenuItem(parentMenu, "Delete", "delete:", "", FALSE); + return; + } + if( STREQ(roleName, "pasteandmatchstyle")) { + id pasteandmatchstyle = addMenuItem(parentMenu, "Paste and Match Style", "pasteandmatchstyle:", "v", FALSE); + msg_int(pasteandmatchstyle, s("setKeyEquivalentModifierMask:"), (NSEventModifierFlagOption | NSEventModifierFlagShift | NSEventModifierFlagCommand)); + } + if ( STREQ(roleName, "selectall")) { + addMenuItem(parentMenu, "Select All", "selectAll:", "a", FALSE); + return; + } + if ( STREQ(roleName, "minimize")) { + addMenuItem(parentMenu, "Minimize", "miniaturize:", "m", FALSE); + return; + } + if ( STREQ(roleName, "zoom")) { + addMenuItem(parentMenu, "Zoom", "performZoom:", "", FALSE); + return; + } + if ( STREQ(roleName, "quit")) { + addMenuItem(parentMenu, "Quit (More work TBD)", "terminate:", "q", FALSE); + return; + } + if ( STREQ(roleName, "togglefullscreen")) { + addMenuItem(parentMenu, "Toggle Full Screen", "toggleFullScreen:", "f", FALSE); + return; + } + +} + +// This converts a string array of modifiers into the +// equivalent MacOS Modifier Flags +unsigned long parseModifiers(const char **modifiers) { + + // Our result is a modifier flag list + unsigned long result = 0; + + const char *thisModifier = modifiers[0]; + int count = 0; + while( thisModifier != NULL ) { + + // Determine flags + if( STREQ(thisModifier, "cmdorctrl") ) { + result |= NSEventModifierFlagCommand; + } + if( STREQ(thisModifier, "optionoralt") ) { + result |= NSEventModifierFlagOption; + } + if( STREQ(thisModifier, "shift") ) { + result |= NSEventModifierFlagShift; + } + if( STREQ(thisModifier, "super") ) { + result |= NSEventModifierFlagCommand; + } + if( STREQ(thisModifier, "ctrl") ) { + result |= NSEventModifierFlagControl; + } + count++; + thisModifier = modifiers[count]; + } + return result; +} + +id processRadioMenuItem(Menu *menu, id parentmenu, const char *title, const char *menuid, bool disabled, bool checked, const char *acceleratorkey) { + id item = ALLOC("NSMenuItem"); + + // Store the item in the menu item map + hashmap_put(&menu->menuItemMap, (char*)menuid, strlen(menuid), item); + + // Create a MenuItemCallbackData + MenuItemCallbackData *callback = CreateMenuItemCallbackData(menu, item, menuid, Radio); + + id wrappedId = msg_id(c("NSValue"), s("valueWithPointer:"), (id)callback); + msg_id(item, s("setRepresentedObject:"), wrappedId); + + id key = processAcceleratorKey(acceleratorkey); + + ((id(*)(id, SEL, id, SEL, id))objc_msgSend)(item, s("initWithTitle:action:keyEquivalent:"), str(title), s("menuItemCallback:"), key); + + msg_bool(item, s("setEnabled:"), !disabled); + msg_reg(item, s("autorelease")); + msg_int(item, s("setState:"), (checked ? NSControlStateValueOn : NSControlStateValueOff)); + + msg_id(parentmenu, s("addItem:"), item); + return item; + +} + +id processCheckboxMenuItem(Menu *menu, id parentmenu, const char *title, const char *menuid, bool disabled, bool checked, const char *key) { + + id item = ALLOC("NSMenuItem"); + msg_reg(item, s("autorelease")); + + // Store the item in the menu item map + hashmap_put(&menu->menuItemMap, (char*)menuid, strlen(menuid), item); + + // Create a MenuItemCallbackData + MenuItemCallbackData *callback = CreateMenuItemCallbackData(menu, item, menuid, Checkbox); + + id wrappedId = msg_id(c("NSValue"), s("valueWithPointer:"), (id)callback); + msg_id(item, s("setRepresentedObject:"), wrappedId); + ((id(*)(id, SEL, id, SEL, id))objc_msgSend)(item, s("initWithTitle:action:keyEquivalent:"), str(title), s("menuItemCallback:"), str(key)); + msg_bool(item, s("setEnabled:"), !disabled); + msg_int(item, s("setState:"), (checked ? NSControlStateValueOn : NSControlStateValueOff)); + msg_id(parentmenu, s("addItem:"), item); + return item; +} + +// getColour returns the colour from a styledLabel based on the key +const char* getColour(JsonNode *styledLabelEntry, const char* key) { + JsonNode* colEntry = getJSONObject(styledLabelEntry, key); + if( colEntry == NULL ) { + return NULL; + } + return getJSONString(colEntry, "hex"); +} + +id createAttributedStringFromStyledLabel(JsonNode *styledLabel, const char* fontName, int fontSize) { + + // Create result + id attributedString = ALLOC_INIT("NSMutableAttributedString"); + msg_reg(attributedString, s("autorelease")); + + // Create new Dictionary + id dictionary = ALLOC_INIT("NSMutableDictionary"); + msg_reg(dictionary, s("autorelease")); + + // Use default font + CGFloat fontSizeFloat = (CGFloat)fontSize; + id font = ((id(*)(id, SEL, CGFloat))objc_msgSend)(c("NSFont"), s("menuBarFontOfSize:"), fontSizeFloat); + + // Check user supplied font + if( STR_HAS_CHARS(fontName) ) { + id fontNameAsNSString = str(fontName); + id userFont = ((id(*)(id, SEL, id, CGFloat))objc_msgSend)(c("NSFont"), s("fontWithName:size:"), fontNameAsNSString, fontSizeFloat); + if( userFont != NULL ) { + font = userFont; + } + } + + id fan = lookupStringConstant(str("NSFontAttributeName")); + id NSForegroundColorAttributeName = lookupStringConstant(str("NSForegroundColorAttributeName")); + id NSBackgroundColorAttributeName = lookupStringConstant(str("NSBackgroundColorAttributeName")); + + // Loop over styled text creating NSAttributedText and appending to result + JsonNode *styledLabelEntry; + json_foreach(styledLabelEntry, styledLabel) { + + // Clear dictionary + msg_reg(dictionary, s("removeAllObjects")); + + // Add font to dictionary + msg_id_id(dictionary, s("setObject:forKey:"), font, fan); + + // Get Text + const char* thisLabel = mustJSONString(styledLabelEntry, "Label"); + + // Get foreground colour + const char *hexColour = getColour(styledLabelEntry, "FgCol"); + if( hexColour != NULL) { + unsigned short r, g, b, a; + + // white by default + r = g = b = a = 255; + int count = sscanf(hexColour, "#%02hx%02hx%02hx%02hx", &r, &g, &b, &a); + if (count > 0) { + id colour = ((id(*)(id, SEL, CGFloat, CGFloat, CGFloat, CGFloat))objc_msgSend)(c("NSColor"), s("colorWithCalibratedRed:green:blue:alpha:"), + (CGFloat)r / (CGFloat)255.0, + (CGFloat)g / (CGFloat)255.0, + (CGFloat)b / (CGFloat)255.0, + (CGFloat)a / (CGFloat)255.0); + msg_id_id(dictionary, s("setObject:forKey:"), colour, NSForegroundColorAttributeName); + } + } + + // Get background colour + hexColour = getColour(styledLabelEntry, "BgCol"); + if( hexColour != NULL) { + unsigned short r, g, b, a; + + // white by default + r = g = b = a = 255; + int count = sscanf(hexColour, "#%02hx%02hx%02hx%02hx", &r, &g, &b, &a); + if (count > 0) { + id colour = ((id(*)(id, SEL, CGFloat, CGFloat, CGFloat, CGFloat))objc_msgSend)(c("NSColor"), s("colorWithCalibratedRed:green:blue:alpha:"), + (CGFloat)r / (CGFloat)255.0, + (CGFloat)g / (CGFloat)255.0, + (CGFloat)b / (CGFloat)255.0, + (CGFloat)a / (CGFloat)255.0); + msg_id_id(dictionary, s("setObject:forKey:"), colour, NSForegroundColorAttributeName); + } + } + + // Create AttributedText + id thisString = ALLOC("NSMutableAttributedString"); + msg_reg(thisString, s("autorelease")); + msg_id_id(thisString, s("initWithString:attributes:"), str(thisLabel), dictionary); + + // Append text to result + msg_id(attributedString, s("appendAttributedString:"), thisString); + } + + return attributedString; + +} + + +id createAttributedString(const char* title, const char* fontName, int fontSize, const char* RGBA) { + + // Create new Dictionary + id dictionary = ALLOC_INIT("NSMutableDictionary"); + CGFloat fontSizeFloat = (CGFloat)fontSize; + + // Use default font + id font = ((id(*)(id, SEL, CGFloat))objc_msgSend)(c("NSFont"), s("menuBarFontOfSize:"), fontSizeFloat); + + // Check user supplied font + if( STR_HAS_CHARS(fontName) ) { + id fontNameAsNSString = str(fontName); + id userFont = ((id(*)(id, SEL, id, CGFloat))objc_msgSend)(c("NSFont"), s("fontWithName:size:"), fontNameAsNSString, fontSizeFloat); + if( userFont != NULL ) { + font = userFont; + } + } + + // Add font to dictionary + id fan = lookupStringConstant(str("NSFontAttributeName")); + msg_id_id(dictionary, s("setObject:forKey:"), font, fan); + + // RGBA + if( RGBA != NULL && strlen(RGBA) > 0) { + unsigned short r, g, b, a; + + // white by default + r = g = b = a = 255; + int count = sscanf(RGBA, "#%02hx%02hx%02hx%02hx", &r, &g, &b, &a); + if (count > 0) { + id colour = ((id(*)(id, SEL, CGFloat, CGFloat, CGFloat, CGFloat))objc_msgSend)(c("NSColor"), s("colorWithCalibratedRed:green:blue:alpha:"), + (CGFloat)r / (CGFloat)255.0, + (CGFloat)g / (CGFloat)255.0, + (CGFloat)b / (CGFloat)255.0, + (CGFloat)a / (CGFloat)255.0); + id NSForegroundColorAttributeName = lookupStringConstant(str("NSForegroundColorAttributeName")); + msg_id_id(dictionary, s("setObject:forKey:"), colour, NSForegroundColorAttributeName); + } + } + + id attributedString = ALLOC("NSMutableAttributedString"); + msg_id_id(attributedString, s("initWithString:attributes:"), str(title), dictionary); + msg_reg(attributedString, s("autorelease")); + msg_reg(dictionary, s("autorelease")); + return attributedString; +} + +id processTextMenuItem(Menu *menu, id parentMenu, const char *title, const char *menuid, bool disabled, const char *acceleratorkey, const char **modifiers, const char* tooltip, const char* image, const char* fontName, int fontSize, const char* RGBA, bool templateImage, bool alternate, JsonNode* styledLabel) { + id item = ALLOC("NSMenuItem"); + msg_reg(item, s("autorelease")); + + // Create a MenuItemCallbackData + MenuItemCallbackData *callback = CreateMenuItemCallbackData(menu, item, menuid, Text); + + id wrappedId = msg_id(c("NSValue"), s("valueWithPointer:"), (id)callback); + msg_id(item, s("setRepresentedObject:"), wrappedId); + + if( !alternate ) { + id key = processAcceleratorKey(acceleratorkey); + ((id(*)(id, SEL, id, SEL, id))objc_msgSend)(item, s("initWithTitle:action:keyEquivalent:"), str(title), + s("menuItemCallback:"), key); + } else { + ((id(*)(id, SEL, id, SEL, id))objc_msgSend)(item, s("initWithTitle:action:keyEquivalent:"), str(title), s("menuItemCallback:"), str("")); + } + + if( tooltip != NULL ) { + msg_id(item, s("setToolTip:"), str(tooltip)); + } + + // Process image + if( image != NULL && strlen(image) > 0) { + id nsimage = createImageFromBase64Data(image, templateImage); + msg_id(item, s("setImage:"), nsimage); + } + + id attributedString = NULL; + if( styledLabel != NULL) { + attributedString = createAttributedStringFromStyledLabel(styledLabel, fontName, fontSize); + } else { + attributedString = createAttributedString(title, fontName, fontSize, RGBA); + } + msg_id(item, s("setAttributedTitle:"), attributedString); + +//msg_id(item, s("setTitle:"), str(title)); + + msg_bool(item, s("setEnabled:"), !disabled); + + // Process modifiers + if( modifiers != NULL && !alternate) { + unsigned long modifierFlags = parseModifiers(modifiers); + ((id(*)(id, SEL, unsigned long))objc_msgSend)(item, s("setKeyEquivalentModifierMask:"), modifierFlags); + } + + // alternate + if( alternate ) { + msg_bool(item, s("setAlternate:"), true); + msg_int(item, s("setKeyEquivalentModifierMask:"), NSEventModifierFlagOption); + } + msg_id(parentMenu, s("addItem:"), item); + + return item; +} + +void processMenuItem(Menu *menu, id parentMenu, JsonNode *item) { + + // Check if this item is hidden and if so, exit early! + bool hidden = false; + getJSONBool(item, "Hidden", &hidden); + if( hidden ) { + return; + } + + // Get the role + JsonNode *role = json_find_member(item, "Role"); + if( role != NULL ) { + processMenuRole(menu, parentMenu, role); + return; + } + + // This is a user menu. Get the common data + // Get the label + const char *label = getJSONString(item, "Label"); + if ( label == NULL) { + label = "(empty)"; + } + + // Check for a styled label + JsonNode *styledLabel = getJSONObject(item, "StyledLabel"); + + // Is this an alternate menu item? + bool alternate = false; + getJSONBool(item, "MacAlternate", &alternate); + + const char *menuid = getJSONString(item, "ID"); + if ( menuid == NULL) { + menuid = ""; + } + + bool disabled = false; + getJSONBool(item, "Disabled", &disabled); + + // Get the Accelerator + JsonNode *accelerator = json_find_member(item, "Accelerator"); + const char *acceleratorkey = NULL; + const char **modifiers = NULL; + + const char *tooltip = getJSONString(item, "Tooltip"); + const char *image = getJSONString(item, "Image"); + const char *fontName = getJSONString(item, "FontName"); + const char *RGBA = getJSONString(item, "RGBA"); + bool templateImage = false; + getJSONBool(item, "MacTemplateImage", &templateImage); + + int fontSize = 0; + getJSONInt(item, "FontSize", &fontSize); + + // If we have an accelerator + if( accelerator != NULL ) { + // Get the key + acceleratorkey = getJSONString(accelerator, "Key"); + // Check if there are modifiers + JsonNode *modifiersList = json_find_member(accelerator, "Modifiers"); + if ( modifiersList != NULL ) { + // Allocate an array of strings + int noOfModifiers = json_array_length(modifiersList); + + // Do we have any? + if (noOfModifiers > 0) { + modifiers = malloc(sizeof(const char *) * (noOfModifiers + 1)); + JsonNode *modifier; + int count = 0; + // Iterate the modifiers and save a reference to them in our new array + json_foreach(modifier, modifiersList) { + // Get modifier name + modifiers[count] = modifier->string_; + count++; + } + // Null terminate the modifier list + modifiers[count] = NULL; + } + } + } + + // Get the Type + JsonNode *type = json_find_member(item, "Type"); + if( type != NULL ) { + if( STREQ(type->string_, "Text") || STREQ(type->string_, "Submenu")) { + id thisMenuItem = processTextMenuItem(menu, parentMenu, label, menuid, disabled, acceleratorkey, modifiers, tooltip, image, fontName, fontSize, RGBA, templateImage, alternate, styledLabel); + + // Check if this node has a submenu + JsonNode *submenu = json_find_member(item, "SubMenu"); + if( submenu != NULL ) { + // Get the label + JsonNode *menuNameNode = json_find_member(item, "Label"); + const char *name = ""; + if ( menuNameNode != NULL) { + name = menuNameNode->string_; + } + + id thisMenu = createMenu(str(name)); + + msg_id(thisMenuItem, s("setSubmenu:"), thisMenu); + + JsonNode *submenuItems = json_find_member(submenu, "Items"); + // If we have no items, just return + if ( submenuItems == NULL ) { + return; + } + + // Loop over submenu items + JsonNode *item; + json_foreach(item, submenuItems) { + // Get item label + processMenuItem(menu, thisMenu, item); + } + } + } + else if ( STREQ(type->string_, "Separator")) { + addSeparator(parentMenu); + } + else if ( STREQ(type->string_, "Checkbox")) { + // Get checked state + bool checked = false; + getJSONBool(item, "Checked", &checked); + + processCheckboxMenuItem(menu, parentMenu, label, menuid, disabled, checked, ""); + } + else if ( STREQ(type->string_, "Radio")) { + // Get checked state + bool checked = false; + getJSONBool(item, "Checked", &checked); + + processRadioMenuItem(menu, parentMenu, label, menuid, disabled, checked, ""); + } + } + + if ( modifiers != NULL ) { + free(modifiers); + } + + return; +} + +void processMenuData(Menu *menu, JsonNode *menuData) { + JsonNode *items = json_find_member(menuData, "Items"); + if( items == NULL ) { + // Parse error! + ABORT("Unable to find 'Items' in menu JSON!"); + } + + // Iterate items + JsonNode *item; + json_foreach(item, items) { + // Process each menu item + processMenuItem(menu, menu->menu, item); + } +} + +void processRadioGroupJSON(Menu *menu, JsonNode *radioGroup) { + + int groupLength; + getJSONInt(radioGroup, "Length", &groupLength); + JsonNode *members = json_find_member(radioGroup, "Members"); + JsonNode *member; + + // Allocate array + size_t arrayLength = sizeof(id)*(groupLength+1); + id memberList[arrayLength]; + + // Build the radio group items + int count=0; + json_foreach(member, members) { + // Get menu by id + id menuItem = (id)hashmap_get(&menu->menuItemMap, (char*)member->string_, strlen(member->string_)); + // Save Member + memberList[count] = menuItem; + count = count + 1; + } + // Null terminate array + memberList[groupLength] = 0; + + // Store the members + json_foreach(member, members) { + // Copy the memberList + char *newMemberList = (char *)malloc(arrayLength); + memcpy(newMemberList, memberList, arrayLength); + // add group to each member of group + hashmap_put(&menu->radioGroupMap, member->string_, strlen(member->string_), newMemberList); + } + +} + +id GetMenu(Menu *menu) { + + // Pull out the menu data + JsonNode *menuData = json_find_member(menu->processedMenu, "Menu"); + if( menuData == NULL ) { + ABORT("Unable to find Menu data: %s", menu->processedMenu); + } + + menu->menu = createMenu(str("")); + + // Process the menu data + processMenuData(menu, menuData); + + // Create the radiogroup cache + JsonNode *radioGroups = json_find_member(menu->processedMenu, "RadioGroups"); + if( radioGroups == NULL ) { + // Parse error! + ABORT("Unable to find RadioGroups data: %s", menu->processedMenu); + } + + // Iterate radio groups + JsonNode *radioGroup; + json_foreach(radioGroup, radioGroups) { + // Get item label + processRadioGroupJSON(menu, radioGroup); + } + + return menu->menu; +} + diff --git a/v2/internal/ffenestri/menu_darwin.h b/v2/internal/ffenestri/menu_darwin.h new file mode 100644 index 000000000..a68c483bd --- /dev/null +++ b/v2/internal/ffenestri/menu_darwin.h @@ -0,0 +1,117 @@ +// +// Created by Lea Anthony on 6/1/21. +// + +#ifndef MENU_DARWIN_H +#define MENU_DARWIN_H + +#include "common.h" +#include "ffenestri_darwin.h" + +enum MenuItemType {Text = 0, Checkbox = 1, Radio = 2}; +enum MenuType {ApplicationMenuType = 0, ContextMenuType = 1, TrayMenuType = 2}; +static const char *MenuTypeAsString[] = { + "ApplicationMenu", "ContextMenu", "TrayMenu", +}; + +typedef struct _NSRange { + unsigned long location; + unsigned long length; +} NSRange; + +#define NSFontWeightUltraLight -0.8 +#define NSFontWeightThin -0.6 +#define NSFontWeightLight -0.4 +#define NSFontWeightRegular 0.0 +#define NSFontWeightMedium 0.23 +#define NSFontWeightSemibold 0.3 +#define NSFontWeightBold 0.4 +#define NSFontWeightHeavy 0.56 +#define NSFontWeightBlack 0.62 + +extern void messageFromWindowCallback(const char *); + +typedef struct { + + const char *title; + + /*** Internal ***/ + + // The decoded version of the Menu JSON + JsonNode *processedMenu; + + struct hashmap_s menuItemMap; + struct hashmap_s radioGroupMap; + + // Vector to keep track of callback data memory + vec_void_t callbackDataCache; + + // The NSMenu for this menu + id menu; + + // The parent data, eg ContextMenuStore or Tray + void *parentData; + + // The commands for the menu callbacks + const char *callbackCommand; + + // This indicates if we are an Application Menu, tray menu or context menu + enum MenuType menuType; + + +} Menu; + + +typedef struct { + id menuItem; + Menu *menu; + const char *menuID; + enum MenuItemType menuItemType; +} MenuItemCallbackData; + + + +// NewMenu creates a new Menu struct, saving the given menu structure as JSON +Menu* NewMenu(JsonNode *menuData); + +Menu* NewApplicationMenu(const char *menuAsJSON); +MenuItemCallbackData* CreateMenuItemCallbackData(Menu *menu, id menuItem, const char *menuID, enum MenuItemType menuItemType); + +void DeleteMenu(Menu *menu); + +// Creates a JSON message for the given menuItemID and data +const char* createMenuClickedMessage(const char *menuItemID, const char *data, enum MenuType menuType, const char *parentID); +// Callback for text menu items +void menuItemCallback(id self, SEL cmd, id sender); +id processAcceleratorKey(const char *key); + + +void addSeparator(id menu); +id createMenuItemNoAutorelease( id title, const char *action, const char *key); + +id createMenuItem(id title, const char *action, const char *key); + +id addMenuItem(id menu, const char *title, const char *action, const char *key, bool disabled); + +id createMenu(id title); +void createDefaultAppMenu(id parentMenu); +void createDefaultEditMenu(id parentMenu); + +void processMenuRole(Menu *menu, id parentMenu, JsonNode *item); +// This converts a string array of modifiers into the +// equivalent MacOS Modifier Flags +unsigned long parseModifiers(const char **modifiers); +id processRadioMenuItem(Menu *menu, id parentmenu, const char *title, const char *menuid, bool disabled, bool checked, const char *acceleratorkey); + +id processCheckboxMenuItem(Menu *menu, id parentmenu, const char *title, const char *menuid, bool disabled, bool checked, const char *key); + +id processTextMenuItem(Menu *menu, id parentMenu, const char *title, const char *menuid, bool disabled, const char *acceleratorkey, const char **modifiers, const char* tooltip, const char* image, const char* fontName, int fontSize, const char* RGBA, bool templateImage, bool alternate, JsonNode* styledLabel); +void processMenuItem(Menu *menu, id parentMenu, JsonNode *item); +void processMenuData(Menu *menu, JsonNode *menuData); + +void processRadioGroupJSON(Menu *menu, JsonNode *radioGroup); +id GetMenu(Menu *menu); +id createAttributedString(const char* title, const char* fontName, int fontSize, const char* RGBA); +id createAttributedStringFromStyledLabel(JsonNode *styledLabel, const char* fontName, int fontSize); + +#endif //ASSETS_C_MENU_DARWIN_H diff --git a/v2/internal/ffenestri/runtime_darwin.c b/v2/internal/ffenestri/runtime_darwin.c new file mode 100644 index 000000000..0d733f87a --- /dev/null +++ b/v2/internal/ffenestri/runtime_darwin.c @@ -0,0 +1,5 @@ + +// runtime.c (c) 2019-Present Lea Anthony. +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file was auto-generated. DO NOT MODIFY. +const unsigned char runtime[]={0x76, 0x61, 0x72, 0x20, 0x57, 0x61, 0x69, 0x6c, 0x73, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x7b, 0x7d, 0x3b, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x65, 0x28, 0x72, 0x29, 0x7b, 0x69, 0x66, 0x28, 0x74, 0x5b, 0x72, 0x5d, 0x29, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x5b, 0x72, 0x5d, 0x2e, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x69, 0x3d, 0x74, 0x5b, 0x72, 0x5d, 0x3d, 0x7b, 0x69, 0x3a, 0x72, 0x2c, 0x6c, 0x3a, 0x21, 0x31, 0x2c, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x3a, 0x7b, 0x7d, 0x7d, 0x3b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x5b, 0x72, 0x5d, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x69, 0x2e, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x2c, 0x69, 0x2c, 0x69, 0x2e, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x2c, 0x65, 0x29, 0x2c, 0x69, 0x2e, 0x6c, 0x3d, 0x21, 0x30, 0x2c, 0x69, 0x2e, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x7d, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x65, 0x2e, 0x6d, 0x3d, 0x6e, 0x2c, 0x65, 0x2e, 0x63, 0x3d, 0x74, 0x2c, 0x65, 0x2e, 0x64, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x2c, 0x74, 0x2c, 0x72, 0x29, 0x7b, 0x65, 0x2e, 0x6f, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7c, 0x7c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x28, 0x6e, 0x2c, 0x74, 0x2c, 0x7b, 0x65, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x3a, 0x21, 0x30, 0x2c, 0x67, 0x65, 0x74, 0x3a, 0x72, 0x7d, 0x29, 0x7d, 0x2c, 0x65, 0x2e, 0x72, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x22, 0x75, 0x6e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x22, 0x21, 0x3d, 0x74, 0x79, 0x70, 0x65, 0x6f, 0x66, 0x20, 0x53, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x26, 0x26, 0x53, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x2e, 0x74, 0x6f, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x26, 0x26, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x28, 0x6e, 0x2c, 0x53, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x2e, 0x74, 0x6f, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x2c, 0x7b, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x22, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x22, 0x7d, 0x29, 0x2c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x28, 0x6e, 0x2c, 0x22, 0x5f, 0x5f, 0x65, 0x73, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x22, 0x2c, 0x7b, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x21, 0x30, 0x7d, 0x29, 0x7d, 0x2c, 0x65, 0x2e, 0x74, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7b, 0x69, 0x66, 0x28, 0x31, 0x26, 0x74, 0x26, 0x26, 0x28, 0x6e, 0x3d, 0x65, 0x28, 0x6e, 0x29, 0x29, 0x2c, 0x38, 0x26, 0x74, 0x29, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x3b, 0x69, 0x66, 0x28, 0x34, 0x26, 0x74, 0x26, 0x26, 0x22, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x3d, 0x3d, 0x74, 0x79, 0x70, 0x65, 0x6f, 0x66, 0x20, 0x6e, 0x26, 0x26, 0x6e, 0x26, 0x26, 0x6e, 0x2e, 0x5f, 0x5f, 0x65, 0x73, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x29, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x72, 0x3d, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x28, 0x6e, 0x75, 0x6c, 0x6c, 0x29, 0x3b, 0x69, 0x66, 0x28, 0x65, 0x2e, 0x72, 0x28, 0x72, 0x29, 0x2c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x28, 0x72, 0x2c, 0x22, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x22, 0x2c, 0x7b, 0x65, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x3a, 0x21, 0x30, 0x2c, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x6e, 0x7d, 0x29, 0x2c, 0x32, 0x26, 0x74, 0x26, 0x26, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x21, 0x3d, 0x74, 0x79, 0x70, 0x65, 0x6f, 0x66, 0x20, 0x6e, 0x29, 0x66, 0x6f, 0x72, 0x28, 0x76, 0x61, 0x72, 0x20, 0x69, 0x20, 0x69, 0x6e, 0x20, 0x6e, 0x29, 0x65, 0x2e, 0x64, 0x28, 0x72, 0x2c, 0x69, 0x2c, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x74, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x5b, 0x74, 0x5d, 0x7d, 0x2e, 0x62, 0x69, 0x6e, 0x64, 0x28, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x69, 0x29, 0x29, 0x3b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x7d, 0x2c, 0x65, 0x2e, 0x6e, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x6e, 0x26, 0x26, 0x6e, 0x2e, 0x5f, 0x5f, 0x65, 0x73, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x3f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x7d, 0x3a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x7d, 0x3b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x65, 0x2e, 0x64, 0x28, 0x74, 0x2c, 0x22, 0x61, 0x22, 0x2c, 0x74, 0x29, 0x2c, 0x74, 0x7d, 0x2c, 0x65, 0x2e, 0x6f, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x68, 0x61, 0x73, 0x4f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7d, 0x2c, 0x65, 0x2e, 0x70, 0x3d, 0x22, 0x22, 0x2c, 0x65, 0x28, 0x65, 0x2e, 0x73, 0x3d, 0x30, 0x29, 0x7d, 0x28, 0x5b, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x2c, 0x74, 0x2c, 0x65, 0x29, 0x7b, 0x22, 0x75, 0x73, 0x65, 0x20, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x22, 0x3b, 0x65, 0x2e, 0x72, 0x28, 0x74, 0x29, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x72, 0x3d, 0x7b, 0x7d, 0x3b, 0x65, 0x2e, 0x72, 0x28, 0x72, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x72, 0x2c, 0x22, 0x54, 0x72, 0x61, 0x63, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x76, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x72, 0x2c, 0x22, 0x50, 0x72, 0x69, 0x6e, 0x74, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x70, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x72, 0x2c, 0x22, 0x44, 0x65, 0x62, 0x75, 0x67, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x79, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x72, 0x2c, 0x22, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6d, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x72, 0x2c, 0x22, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x62, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x72, 0x2c, 0x22, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x67, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x72, 0x2c, 0x22, 0x46, 0x61, 0x74, 0x61, 0x6c, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x68, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x72, 0x2c, 0x22, 0x53, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x53, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x72, 0x2c, 0x22, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x45, 0x7d, 0x29, 0x29, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x69, 0x3d, 0x7b, 0x7d, 0x3b, 0x65, 0x2e, 0x72, 0x28, 0x69, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x69, 0x2c, 0x22, 0x4f, 0x70, 0x65, 0x6e, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x78, 0x7d, 0x29, 0x29, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x6f, 0x3d, 0x7b, 0x7d, 0x3b, 0x65, 0x2e, 0x72, 0x28, 0x6f, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x4e, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x53, 0x65, 0x74, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x54, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x46, 0x75, 0x6c, 0x6c, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6a, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x55, 0x6e, 0x46, 0x75, 0x6c, 0x6c, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x44, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x53, 0x65, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x49, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x53, 0x65, 0x74, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x50, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x48, 0x69, 0x64, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x41, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x53, 0x68, 0x6f, 0x77, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x4a, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x4d, 0x61, 0x78, 0x69, 0x6d, 0x69, 0x73, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x4c, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x55, 0x6e, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x69, 0x73, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x52, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x69, 0x73, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x55, 0x6e, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x69, 0x73, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x46, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x55, 0x7d, 0x29, 0x29, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x61, 0x3d, 0x7b, 0x7d, 0x3b, 0x65, 0x2e, 0x72, 0x28, 0x61, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x61, 0x2c, 0x22, 0x4f, 0x70, 0x65, 0x6e, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x42, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x61, 0x2c, 0x22, 0x53, 0x61, 0x76, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x48, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x61, 0x2c, 0x22, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x47, 0x7d, 0x29, 0x29, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x75, 0x3d, 0x7b, 0x7d, 0x3b, 0x65, 0x2e, 0x72, 0x28, 0x75, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x75, 0x2c, 0x22, 0x4e, 0x65, 0x77, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x65, 0x6e, 0x7d, 0x29, 0x29, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x63, 0x3d, 0x7b, 0x7d, 0x3b, 0x65, 0x2e, 0x72, 0x28, 0x63, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x63, 0x2c, 0x22, 0x53, 0x65, 0x74, 0x49, 0x63, 0x6f, 0x6e, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x6e, 0x7d, 0x29, 0x29, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x6c, 0x3d, 0x7b, 0x41, 0x70, 0x70, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x22, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x22, 0x2c, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x3a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x22, 0x64, 0x61, 0x72, 0x77, 0x69, 0x6e, 0x22, 0x7d, 0x7d, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x73, 0x3d, 0x5b, 0x5d, 0x3b, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x66, 0x28, 0x6e, 0x29, 0x7b, 0x73, 0x2e, 0x70, 0x75, 0x73, 0x68, 0x28, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x64, 0x28, 0x6e, 0x29, 0x7b, 0x69, 0x66, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x28, 0x6e, 0x29, 0x7d, 0x28, 0x6e, 0x29, 0x2c, 0x73, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3e, 0x30, 0x29, 0x66, 0x6f, 0x72, 0x28, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x30, 0x3b, 0x74, 0x3c, 0x73, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3b, 0x74, 0x2b, 0x2b, 0x29, 0x73, 0x5b, 0x74, 0x5d, 0x28, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x77, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x4c, 0x22, 0x2b, 0x6e, 0x2b, 0x74, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x76, 0x28, 0x6e, 0x29, 0x7b, 0x77, 0x28, 0x22, 0x54, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x70, 0x28, 0x6e, 0x29, 0x7b, 0x77, 0x28, 0x22, 0x50, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x79, 0x28, 0x6e, 0x29, 0x7b, 0x77, 0x28, 0x22, 0x44, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x28, 0x6e, 0x29, 0x7b, 0x77, 0x28, 0x22, 0x49, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x62, 0x28, 0x6e, 0x29, 0x7b, 0x77, 0x28, 0x22, 0x57, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x67, 0x28, 0x6e, 0x29, 0x7b, 0x77, 0x28, 0x22, 0x45, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x68, 0x28, 0x6e, 0x29, 0x7b, 0x77, 0x28, 0x22, 0x46, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x53, 0x28, 0x6e, 0x29, 0x7b, 0x77, 0x28, 0x22, 0x53, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x76, 0x61, 0x72, 0x20, 0x4f, 0x2c, 0x45, 0x3d, 0x7b, 0x54, 0x52, 0x41, 0x43, 0x45, 0x3a, 0x31, 0x2c, 0x44, 0x45, 0x42, 0x55, 0x47, 0x3a, 0x32, 0x2c, 0x49, 0x4e, 0x46, 0x4f, 0x3a, 0x33, 0x2c, 0x57, 0x41, 0x52, 0x4e, 0x49, 0x4e, 0x47, 0x3a, 0x34, 0x2c, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x3a, 0x35, 0x7d, 0x2c, 0x6b, 0x3d, 0x7b, 0x7d, 0x3b, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x43, 0x28, 0x6e, 0x2c, 0x74, 0x2c, 0x65, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x21, 0x3d, 0x65, 0x26, 0x26, 0x6e, 0x75, 0x6c, 0x6c, 0x21, 0x3d, 0x65, 0x7c, 0x7c, 0x28, 0x65, 0x3d, 0x30, 0x29, 0x2c, 0x6e, 0x65, 0x77, 0x20, 0x50, 0x72, 0x6f, 0x6d, 0x69, 0x73, 0x65, 0x28, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x72, 0x2c, 0x69, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x6f, 0x3b, 0x64, 0x6f, 0x7b, 0x6f, 0x3d, 0x6e, 0x2b, 0x22, 0x2d, 0x22, 0x2b, 0x4f, 0x28, 0x29, 0x7d, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x28, 0x6b, 0x5b, 0x6f, 0x5d, 0x29, 0x3b, 0x69, 0x66, 0x28, 0x65, 0x3e, 0x30, 0x29, 0x76, 0x61, 0x72, 0x20, 0x61, 0x3d, 0x73, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x28, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x69, 0x28, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x22, 0x43, 0x61, 0x6c, 0x6c, 0x20, 0x74, 0x6f, 0x20, 0x22, 0x2b, 0x6e, 0x2b, 0x22, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x64, 0x20, 0x6f, 0x75, 0x74, 0x2e, 0x20, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x20, 0x49, 0x44, 0x3a, 0x20, 0x22, 0x2b, 0x6f, 0x29, 0x29, 0x7d, 0x29, 0x2c, 0x65, 0x29, 0x3b, 0x6b, 0x5b, 0x6f, 0x5d, 0x3d, 0x7b, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x3a, 0x61, 0x2c, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x69, 0x2c, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x3a, 0x72, 0x7d, 0x3b, 0x74, 0x72, 0x79, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x75, 0x3d, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x6e, 0x2c, 0x61, 0x72, 0x67, 0x73, 0x3a, 0x74, 0x2c, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x49, 0x44, 0x3a, 0x6f, 0x7d, 0x3b, 0x64, 0x28, 0x22, 0x43, 0x22, 0x2b, 0x4a, 0x53, 0x4f, 0x4e, 0x2e, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x69, 0x66, 0x79, 0x28, 0x75, 0x29, 0x29, 0x7d, 0x63, 0x61, 0x74, 0x63, 0x68, 0x28, 0x6e, 0x29, 0x7b, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x6e, 0x29, 0x7d, 0x7d, 0x29, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x57, 0x28, 0x6e, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3b, 0x74, 0x72, 0x79, 0x7b, 0x74, 0x3d, 0x4a, 0x53, 0x4f, 0x4e, 0x2e, 0x70, 0x61, 0x72, 0x73, 0x65, 0x28, 0x6e, 0x29, 0x7d, 0x63, 0x61, 0x74, 0x63, 0x68, 0x28, 0x74, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x65, 0x3d, 0x22, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x4a, 0x53, 0x4f, 0x4e, 0x20, 0x70, 0x61, 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x3a, 0x20, 0x22, 0x2e, 0x63, 0x6f, 0x6e, 0x63, 0x61, 0x74, 0x28, 0x74, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, 0x22, 0x2e, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x3a, 0x20, 0x22, 0x29, 0x2e, 0x63, 0x6f, 0x6e, 0x63, 0x61, 0x74, 0x28, 0x6e, 0x29, 0x3b, 0x74, 0x68, 0x72, 0x6f, 0x77, 0x20, 0x79, 0x28, 0x65, 0x29, 0x2c, 0x6e, 0x65, 0x77, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x65, 0x29, 0x7d, 0x76, 0x61, 0x72, 0x20, 0x72, 0x3d, 0x74, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x69, 0x64, 0x2c, 0x69, 0x3d, 0x6b, 0x5b, 0x72, 0x5d, 0x3b, 0x69, 0x66, 0x28, 0x21, 0x69, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x6f, 0x3d, 0x22, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x20, 0x27, 0x22, 0x2e, 0x63, 0x6f, 0x6e, 0x63, 0x61, 0x74, 0x28, 0x72, 0x2c, 0x22, 0x27, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x21, 0x21, 0x21, 0x22, 0x29, 0x3b, 0x74, 0x68, 0x72, 0x6f, 0x77, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x6f, 0x29, 0x2c, 0x6e, 0x65, 0x77, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x6f, 0x29, 0x7d, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x28, 0x69, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x2c, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x20, 0x6b, 0x5b, 0x72, 0x5d, 0x2c, 0x74, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x3f, 0x69, 0x2e, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x28, 0x74, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x29, 0x3a, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x28, 0x74, 0x2e, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x4d, 0x28, 0x6e, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x5b, 0x5d, 0x2e, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x28, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x29, 0x2e, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x28, 0x31, 0x29, 0x3b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x43, 0x28, 0x22, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x22, 0x2b, 0x6e, 0x2c, 0x74, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x78, 0x28, 0x6e, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x64, 0x28, 0x22, 0x52, 0x42, 0x4f, 0x22, 0x2b, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x4e, 0x28, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x63, 0x22, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x54, 0x28, 0x6e, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x54, 0x22, 0x2b, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6a, 0x28, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x46, 0x22, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x44, 0x28, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x66, 0x22, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x49, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x73, 0x3a, 0x22, 0x2b, 0x6e, 0x2b, 0x22, 0x3a, 0x22, 0x2b, 0x74, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x50, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x70, 0x3a, 0x22, 0x2b, 0x6e, 0x2b, 0x22, 0x3a, 0x22, 0x2b, 0x74, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x28, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x48, 0x22, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x4a, 0x28, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x53, 0x22, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x4c, 0x28, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x4d, 0x22, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x52, 0x28, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x55, 0x22, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x5f, 0x28, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x6d, 0x22, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x46, 0x28, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x75, 0x22, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x55, 0x28, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x43, 0x22, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x42, 0x28, 0x6e, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x4d, 0x28, 0x22, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x48, 0x28, 0x6e, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x4d, 0x28, 0x22, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x2e, 0x53, 0x61, 0x76, 0x65, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x47, 0x28, 0x6e, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x4d, 0x28, 0x22, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x4f, 0x3d, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x3f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x6e, 0x3d, 0x6e, 0x65, 0x77, 0x20, 0x55, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x41, 0x72, 0x72, 0x61, 0x79, 0x28, 0x31, 0x29, 0x3b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x67, 0x65, 0x74, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x28, 0x6e, 0x29, 0x5b, 0x30, 0x5d, 0x7d, 0x3a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x39, 0x30, 0x30, 0x37, 0x31, 0x39, 0x39, 0x32, 0x35, 0x34, 0x37, 0x34, 0x30, 0x39, 0x39, 0x31, 0x2a, 0x4d, 0x61, 0x74, 0x68, 0x2e, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x28, 0x29, 0x7d, 0x2c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x3d, 0x7b, 0x7d, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x71, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6e, 0x28, 0x74, 0x2c, 0x65, 0x29, 0x7b, 0x21, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7b, 0x69, 0x66, 0x28, 0x21, 0x28, 0x6e, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x6f, 0x66, 0x20, 0x74, 0x29, 0x29, 0x74, 0x68, 0x72, 0x6f, 0x77, 0x20, 0x6e, 0x65, 0x77, 0x20, 0x54, 0x79, 0x70, 0x65, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x22, 0x43, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x63, 0x61, 0x6c, 0x6c, 0x20, 0x61, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x61, 0x73, 0x20, 0x61, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x29, 0x7d, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2c, 0x6e, 0x29, 0x2c, 0x65, 0x3d, 0x65, 0x7c, 0x7c, 0x2d, 0x31, 0x2c, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x28, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x6e, 0x29, 0x2c, 0x2d, 0x31, 0x21, 0x3d, 0x3d, 0x65, 0x26, 0x26, 0x30, 0x3d, 0x3d, 0x3d, 0x28, 0x65, 0x2d, 0x3d, 0x31, 0x29, 0x7d, 0x7d, 0x2c, 0x7a, 0x3d, 0x7b, 0x7d, 0x3b, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x56, 0x28, 0x6e, 0x2c, 0x74, 0x2c, 0x65, 0x29, 0x7b, 0x7a, 0x5b, 0x6e, 0x5d, 0x3d, 0x7a, 0x5b, 0x6e, 0x5d, 0x7c, 0x7c, 0x5b, 0x5d, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x72, 0x3d, 0x6e, 0x65, 0x77, 0x20, 0x71, 0x28, 0x74, 0x2c, 0x65, 0x29, 0x3b, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x2e, 0x6c, 0x6f, 0x67, 0x28, 0x22, 0x50, 0x75, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x3a, 0x20, 0x22, 0x2b, 0x6e, 0x29, 0x2c, 0x7a, 0x5b, 0x6e, 0x5d, 0x2e, 0x70, 0x75, 0x73, 0x68, 0x28, 0x72, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x4b, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7b, 0x56, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x51, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7b, 0x56, 0x28, 0x6e, 0x2c, 0x74, 0x2c, 0x31, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x58, 0x28, 0x6e, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x6e, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x3b, 0x69, 0x66, 0x28, 0x7a, 0x5b, 0x74, 0x5d, 0x29, 0x7b, 0x66, 0x6f, 0x72, 0x28, 0x76, 0x61, 0x72, 0x20, 0x65, 0x3d, 0x7a, 0x5b, 0x74, 0x5d, 0x2e, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x28, 0x29, 0x2c, 0x72, 0x3d, 0x30, 0x3b, 0x72, 0x3c, 0x7a, 0x5b, 0x74, 0x5d, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3b, 0x72, 0x2b, 0x3d, 0x31, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x69, 0x3d, 0x7a, 0x5b, 0x74, 0x5d, 0x5b, 0x72, 0x5d, 0x2c, 0x6f, 0x3d, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x3b, 0x69, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x28, 0x6f, 0x29, 0x26, 0x26, 0x65, 0x2e, 0x73, 0x70, 0x6c, 0x69, 0x63, 0x65, 0x28, 0x72, 0x2c, 0x31, 0x29, 0x7d, 0x7a, 0x5b, 0x74, 0x5d, 0x3d, 0x65, 0x7d, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x59, 0x28, 0x6e, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3b, 0x74, 0x72, 0x79, 0x7b, 0x74, 0x3d, 0x4a, 0x53, 0x4f, 0x4e, 0x2e, 0x70, 0x61, 0x72, 0x73, 0x65, 0x28, 0x6e, 0x29, 0x7d, 0x63, 0x61, 0x74, 0x63, 0x68, 0x28, 0x74, 0x29, 0x7b, 0x74, 0x68, 0x72, 0x6f, 0x77, 0x20, 0x6e, 0x65, 0x77, 0x20, 0x67, 0x28, 0x22, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x4a, 0x53, 0x4f, 0x4e, 0x20, 0x70, 0x61, 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x3a, 0x20, 0x22, 0x2b, 0x6e, 0x29, 0x7d, 0x58, 0x28, 0x74, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x5a, 0x28, 0x6e, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x6e, 0x2c, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x5b, 0x5d, 0x2e, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x28, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x29, 0x2e, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x28, 0x31, 0x29, 0x7d, 0x3b, 0x58, 0x28, 0x74, 0x29, 0x2c, 0x64, 0x28, 0x22, 0x45, 0x6a, 0x22, 0x2b, 0x4a, 0x53, 0x4f, 0x4e, 0x2e, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x69, 0x66, 0x79, 0x28, 0x74, 0x29, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x24, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x65, 0x3d, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x28, 0x22, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x22, 0x29, 0x3b, 0x65, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x3d, 0x6e, 0x2c, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x62, 0x6f, 0x64, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x28, 0x65, 0x29, 0x2c, 0x74, 0x26, 0x26, 0x5a, 0x28, 0x74, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6e, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x74, 0x72, 0x79, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x28, 0x22, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x22, 0x29, 0x3b, 0x74, 0x2e, 0x73, 0x65, 0x74, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x28, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x2c, 0x22, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x63, 0x73, 0x73, 0x22, 0x29, 0x2c, 0x74, 0x2e, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x53, 0x68, 0x65, 0x65, 0x74, 0x3f, 0x74, 0x2e, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x53, 0x68, 0x65, 0x65, 0x74, 0x2e, 0x63, 0x73, 0x73, 0x54, 0x65, 0x78, 0x74, 0x3d, 0x6e, 0x3a, 0x74, 0x2e, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x28, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x65, 0x78, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x28, 0x6e, 0x29, 0x29, 0x2c, 0x28, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x7c, 0x7c, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x79, 0x54, 0x61, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x28, 0x22, 0x68, 0x65, 0x61, 0x64, 0x22, 0x29, 0x5b, 0x30, 0x5d, 0x29, 0x2e, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x28, 0x74, 0x29, 0x7d, 0x63, 0x61, 0x74, 0x63, 0x68, 0x28, 0x6e, 0x29, 0x7b, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x2e, 0x6c, 0x6f, 0x67, 0x28, 0x6e, 0x29, 0x7d, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x6e, 0x28, 0x29, 0x7b, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x57, 0x61, 0x69, 0x6c, 0x73, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x4d, 0x65, 0x6e, 0x75, 0x3d, 0x21, 0x30, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x65, 0x6e, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x65, 0x3b, 0x69, 0x66, 0x28, 0x21, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x29, 0x74, 0x68, 0x72, 0x6f, 0x77, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x22, 0x57, 0x61, 0x69, 0x6c, 0x73, 0x20, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x73, 0x65, 0x64, 0x22, 0x29, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x72, 0x3d, 0x5b, 0x5d, 0x3b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4f, 0x6e, 0x28, 0x22, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x3a, 0x73, 0x79, 0x6e, 0x63, 0x3a, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x3a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x62, 0x79, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x3a, 0x22, 0x2b, 0x6e, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x4a, 0x53, 0x4f, 0x4e, 0x2e, 0x70, 0x61, 0x72, 0x73, 0x65, 0x28, 0x6e, 0x29, 0x3b, 0x65, 0x3d, 0x74, 0x2c, 0x72, 0x2e, 0x66, 0x6f, 0x72, 0x45, 0x61, 0x63, 0x68, 0x28, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x6e, 0x28, 0x65, 0x29, 0x7d, 0x29, 0x29, 0x7d, 0x29, 0x29, 0x2c, 0x74, 0x26, 0x26, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x73, 0x65, 0x74, 0x28, 0x74, 0x29, 0x2c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x6d, 0x69, 0x74, 0x28, 0x22, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x3a, 0x73, 0x79, 0x6e, 0x63, 0x3a, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x3a, 0x72, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x3a, 0x22, 0x2b, 0x6e, 0x29, 0x2c, 0x7b, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x3a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x72, 0x2e, 0x70, 0x75, 0x73, 0x68, 0x28, 0x6e, 0x29, 0x7d, 0x2c, 0x67, 0x65, 0x74, 0x3a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x65, 0x7d, 0x2c, 0x73, 0x65, 0x74, 0x3a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x74, 0x29, 0x7b, 0x65, 0x3d, 0x74, 0x2c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x6d, 0x69, 0x74, 0x28, 0x22, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x3a, 0x73, 0x79, 0x6e, 0x63, 0x3a, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x3a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x62, 0x79, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x3a, 0x22, 0x2b, 0x6e, 0x2c, 0x4a, 0x53, 0x4f, 0x4e, 0x2e, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x69, 0x66, 0x79, 0x28, 0x65, 0x29, 0x29, 0x2c, 0x72, 0x2e, 0x66, 0x6f, 0x72, 0x45, 0x61, 0x63, 0x68, 0x28, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x6e, 0x28, 0x65, 0x29, 0x7d, 0x29, 0x29, 0x7d, 0x2c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x6e, 0x28, 0x65, 0x29, 0x3b, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x73, 0x65, 0x74, 0x28, 0x74, 0x29, 0x7d, 0x7d, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x54, 0x49, 0x22, 0x2b, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x28, 0x6f, 0x6e, 0x3d, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x61, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x7c, 0x7c, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x66, 0x6f, 0x72, 0x28, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x31, 0x3b, 0x74, 0x3c, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3b, 0x74, 0x2b, 0x2b, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x65, 0x3d, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x5b, 0x74, 0x5d, 0x3b, 0x66, 0x6f, 0x72, 0x28, 0x76, 0x61, 0x72, 0x20, 0x72, 0x20, 0x69, 0x6e, 0x20, 0x65, 0x29, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x68, 0x61, 0x73, 0x4f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x65, 0x2c, 0x72, 0x29, 0x26, 0x26, 0x28, 0x6e, 0x5b, 0x72, 0x5d, 0x3d, 0x65, 0x5b, 0x72, 0x5d, 0x29, 0x7d, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x7d, 0x29, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2c, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x29, 0x7d, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x3d, 0x7b, 0x7d, 0x2c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x3d, 0x7b, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x3a, 0x6c, 0x2c, 0x4c, 0x6f, 0x67, 0x3a, 0x72, 0x2c, 0x42, 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, 0x3a, 0x69, 0x2c, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x3a, 0x6f, 0x2c, 0x54, 0x72, 0x61, 0x79, 0x3a, 0x63, 0x2c, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x3a, 0x61, 0x2c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x3a, 0x7b, 0x4f, 0x6e, 0x3a, 0x4b, 0x2c, 0x4f, 0x6e, 0x63, 0x65, 0x3a, 0x51, 0x2c, 0x4f, 0x6e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x3a, 0x56, 0x2c, 0x45, 0x6d, 0x69, 0x74, 0x3a, 0x5a, 0x7d, 0x2c, 0x5f, 0x3a, 0x7b, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x3a, 0x57, 0x2c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x3a, 0x59, 0x2c, 0x41, 0x64, 0x64, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x3a, 0x24, 0x2c, 0x49, 0x6e, 0x6a, 0x65, 0x63, 0x74, 0x43, 0x53, 0x53, 0x3a, 0x6e, 0x6e, 0x2c, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x4d, 0x65, 0x6e, 0x75, 0x3a, 0x74, 0x6e, 0x2c, 0x41, 0x64, 0x64, 0x49, 0x50, 0x43, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x3a, 0x66, 0x2c, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x61, 0x6c, 0x6c, 0x3a, 0x4d, 0x2c, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x3a, 0x64, 0x7d, 0x2c, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x3a, 0x75, 0x7d, 0x2c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x3d, 0x7b, 0x49, 0x73, 0x44, 0x61, 0x72, 0x6b, 0x4d, 0x6f, 0x64, 0x65, 0x3a, 0x65, 0x6e, 0x28, 0x22, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x3a, 0x69, 0x73, 0x64, 0x61, 0x72, 0x6b, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0x29, 0x2c, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x3a, 0x65, 0x6e, 0x28, 0x22, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x3a, 0x6c, 0x6f, 0x67, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x29, 0x2c, 0x41, 0x70, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x3a, 0x65, 0x6e, 0x28, 0x22, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x3a, 0x61, 0x70, 0x70, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x29, 0x7d, 0x2c, 0x6f, 0x6e, 0x28, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2c, 0x6c, 0x29, 0x2c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x61, 0x64, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x28, 0x22, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x64, 0x6f, 0x77, 0x6e, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x66, 0x6f, 0x72, 0x28, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x6e, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x3b, 0x6e, 0x75, 0x6c, 0x6c, 0x21, 0x3d, 0x74, 0x26, 0x26, 0x21, 0x74, 0x2e, 0x68, 0x61, 0x73, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x28, 0x22, 0x64, 0x61, 0x74, 0x61, 0x2d, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2d, 0x6e, 0x6f, 0x2d, 0x64, 0x72, 0x61, 0x67, 0x22, 0x29, 0x3b, 0x29, 0x7b, 0x69, 0x66, 0x28, 0x74, 0x2e, 0x68, 0x61, 0x73, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x28, 0x22, 0x64, 0x61, 0x74, 0x61, 0x2d, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2d, 0x64, 0x72, 0x61, 0x67, 0x22, 0x29, 0x29, 0x7b, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x44, 0x72, 0x61, 0x67, 0x28, 0x6e, 0x75, 0x6c, 0x6c, 0x29, 0x3b, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x7d, 0x74, 0x3d, 0x74, 0x2e, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x7d, 0x7d, 0x29, 0x29, 0x2c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x61, 0x64, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x28, 0x22, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x6d, 0x65, 0x6e, 0x75, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x66, 0x6f, 0x72, 0x28, 0x76, 0x61, 0x72, 0x20, 0x74, 0x2c, 0x65, 0x3d, 0x6e, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x3b, 0x6e, 0x75, 0x6c, 0x6c, 0x21, 0x3d, 0x65, 0x26, 0x26, 0x6e, 0x75, 0x6c, 0x6c, 0x3d, 0x3d, 0x28, 0x74, 0x3d, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x5b, 0x22, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x6d, 0x65, 0x6e, 0x75, 0x2d, 0x69, 0x64, 0x22, 0x5d, 0x29, 0x3b, 0x29, 0x65, 0x3d, 0x65, 0x2e, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x3b, 0x69, 0x66, 0x28, 0x28, 0x6e, 0x75, 0x6c, 0x6c, 0x21, 0x3d, 0x74, 0x7c, 0x7c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x57, 0x61, 0x69, 0x6c, 0x73, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x4d, 0x65, 0x6e, 0x75, 0x29, 0x26, 0x26, 0x6e, 0x2e, 0x70, 0x72, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x28, 0x29, 0x2c, 0x6e, 0x75, 0x6c, 0x6c, 0x21, 0x3d, 0x74, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x72, 0x3d, 0x7b, 0x69, 0x64, 0x3a, 0x74, 0x2c, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x5b, 0x22, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x6d, 0x65, 0x6e, 0x75, 0x2d, 0x64, 0x61, 0x74, 0x61, 0x22, 0x5d, 0x7c, 0x7c, 0x22, 0x22, 0x7d, 0x3b, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x4d, 0x65, 0x6e, 0x75, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x28, 0x4a, 0x53, 0x4f, 0x4e, 0x2e, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x69, 0x66, 0x79, 0x28, 0x72, 0x29, 0x29, 0x7d, 0x7d, 0x29, 0x29, 0x2c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x26, 0x26, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x74, 0x72, 0x79, 0x7b, 0x6e, 0x3d, 0x4a, 0x53, 0x4f, 0x4e, 0x2e, 0x70, 0x61, 0x72, 0x73, 0x65, 0x28, 0x6e, 0x29, 0x7d, 0x63, 0x61, 0x74, 0x63, 0x68, 0x28, 0x6e, 0x29, 0x7b, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x6e, 0x29, 0x7d, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x3d, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x7c, 0x7c, 0x7b, 0x7d, 0x2c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x6e, 0x29, 0x2e, 0x66, 0x6f, 0x72, 0x45, 0x61, 0x63, 0x68, 0x28, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x74, 0x29, 0x7b, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5b, 0x74, 0x5d, 0x3d, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5b, 0x74, 0x5d, 0x7c, 0x7c, 0x7b, 0x7d, 0x2c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x6e, 0x5b, 0x74, 0x5d, 0x29, 0x2e, 0x66, 0x6f, 0x72, 0x45, 0x61, 0x63, 0x68, 0x28, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x65, 0x29, 0x7b, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5b, 0x74, 0x5d, 0x5b, 0x65, 0x5d, 0x3d, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5b, 0x74, 0x5d, 0x5b, 0x65, 0x5d, 0x7c, 0x7c, 0x7b, 0x7d, 0x2c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x6e, 0x5b, 0x74, 0x5d, 0x5b, 0x65, 0x5d, 0x29, 0x2e, 0x66, 0x6f, 0x72, 0x45, 0x61, 0x63, 0x68, 0x28, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5b, 0x74, 0x5d, 0x5b, 0x65, 0x5d, 0x5b, 0x6e, 0x5d, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x72, 0x3d, 0x30, 0x3b, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x28, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x69, 0x3d, 0x5b, 0x5d, 0x2e, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x29, 0x3b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x43, 0x28, 0x5b, 0x74, 0x2c, 0x65, 0x2c, 0x6e, 0x5d, 0x2e, 0x6a, 0x6f, 0x69, 0x6e, 0x28, 0x22, 0x2e, 0x22, 0x29, 0x2c, 0x69, 0x2c, 0x72, 0x29, 0x7d, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x69, 0x2e, 0x73, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x72, 0x3d, 0x6e, 0x7d, 0x2c, 0x69, 0x2e, 0x67, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x7d, 0x2c, 0x69, 0x7d, 0x28, 0x29, 0x7d, 0x29, 0x29, 0x7d, 0x29, 0x29, 0x7d, 0x29, 0x29, 0x7d, 0x28, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x2c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x6d, 0x69, 0x74, 0x28, 0x22, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x3a, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x22, 0x29, 0x7d, 0x5d, 0x29, 0x3b, 0x00}; \ No newline at end of file diff --git a/v2/internal/ffenestri/runtime_linux.c b/v2/internal/ffenestri/runtime_linux.c new file mode 100644 index 000000000..a8eb668be --- /dev/null +++ b/v2/internal/ffenestri/runtime_linux.c @@ -0,0 +1,5 @@ + +// runtime.c (c) 2019-Present Lea Anthony. +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file was auto-generated. DO NOT MODIFY. +const unsigned char runtime[]={0x76, 0x61, 0x72, 0x20, 0x57, 0x61, 0x69, 0x6c, 0x73, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x7b, 0x7d, 0x3b, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x65, 0x28, 0x72, 0x29, 0x7b, 0x69, 0x66, 0x28, 0x74, 0x5b, 0x72, 0x5d, 0x29, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x5b, 0x72, 0x5d, 0x2e, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x69, 0x3d, 0x74, 0x5b, 0x72, 0x5d, 0x3d, 0x7b, 0x69, 0x3a, 0x72, 0x2c, 0x6c, 0x3a, 0x21, 0x31, 0x2c, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x3a, 0x7b, 0x7d, 0x7d, 0x3b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x5b, 0x72, 0x5d, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x69, 0x2e, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x2c, 0x69, 0x2c, 0x69, 0x2e, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x2c, 0x65, 0x29, 0x2c, 0x69, 0x2e, 0x6c, 0x3d, 0x21, 0x30, 0x2c, 0x69, 0x2e, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x7d, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x65, 0x2e, 0x6d, 0x3d, 0x6e, 0x2c, 0x65, 0x2e, 0x63, 0x3d, 0x74, 0x2c, 0x65, 0x2e, 0x64, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x2c, 0x74, 0x2c, 0x72, 0x29, 0x7b, 0x65, 0x2e, 0x6f, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7c, 0x7c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x28, 0x6e, 0x2c, 0x74, 0x2c, 0x7b, 0x65, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x3a, 0x21, 0x30, 0x2c, 0x67, 0x65, 0x74, 0x3a, 0x72, 0x7d, 0x29, 0x7d, 0x2c, 0x65, 0x2e, 0x72, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x22, 0x75, 0x6e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x22, 0x21, 0x3d, 0x74, 0x79, 0x70, 0x65, 0x6f, 0x66, 0x20, 0x53, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x26, 0x26, 0x53, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x2e, 0x74, 0x6f, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x26, 0x26, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x28, 0x6e, 0x2c, 0x53, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x2e, 0x74, 0x6f, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x2c, 0x7b, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x22, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x22, 0x7d, 0x29, 0x2c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x28, 0x6e, 0x2c, 0x22, 0x5f, 0x5f, 0x65, 0x73, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x22, 0x2c, 0x7b, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x21, 0x30, 0x7d, 0x29, 0x7d, 0x2c, 0x65, 0x2e, 0x74, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7b, 0x69, 0x66, 0x28, 0x31, 0x26, 0x74, 0x26, 0x26, 0x28, 0x6e, 0x3d, 0x65, 0x28, 0x6e, 0x29, 0x29, 0x2c, 0x38, 0x26, 0x74, 0x29, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x3b, 0x69, 0x66, 0x28, 0x34, 0x26, 0x74, 0x26, 0x26, 0x22, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x3d, 0x3d, 0x74, 0x79, 0x70, 0x65, 0x6f, 0x66, 0x20, 0x6e, 0x26, 0x26, 0x6e, 0x26, 0x26, 0x6e, 0x2e, 0x5f, 0x5f, 0x65, 0x73, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x29, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x72, 0x3d, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x28, 0x6e, 0x75, 0x6c, 0x6c, 0x29, 0x3b, 0x69, 0x66, 0x28, 0x65, 0x2e, 0x72, 0x28, 0x72, 0x29, 0x2c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x28, 0x72, 0x2c, 0x22, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x22, 0x2c, 0x7b, 0x65, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x3a, 0x21, 0x30, 0x2c, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x6e, 0x7d, 0x29, 0x2c, 0x32, 0x26, 0x74, 0x26, 0x26, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x21, 0x3d, 0x74, 0x79, 0x70, 0x65, 0x6f, 0x66, 0x20, 0x6e, 0x29, 0x66, 0x6f, 0x72, 0x28, 0x76, 0x61, 0x72, 0x20, 0x69, 0x20, 0x69, 0x6e, 0x20, 0x6e, 0x29, 0x65, 0x2e, 0x64, 0x28, 0x72, 0x2c, 0x69, 0x2c, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x74, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x5b, 0x74, 0x5d, 0x7d, 0x2e, 0x62, 0x69, 0x6e, 0x64, 0x28, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x69, 0x29, 0x29, 0x3b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x7d, 0x2c, 0x65, 0x2e, 0x6e, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x6e, 0x26, 0x26, 0x6e, 0x2e, 0x5f, 0x5f, 0x65, 0x73, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x3f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x7d, 0x3a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x7d, 0x3b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x65, 0x2e, 0x64, 0x28, 0x74, 0x2c, 0x22, 0x61, 0x22, 0x2c, 0x74, 0x29, 0x2c, 0x74, 0x7d, 0x2c, 0x65, 0x2e, 0x6f, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x68, 0x61, 0x73, 0x4f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7d, 0x2c, 0x65, 0x2e, 0x70, 0x3d, 0x22, 0x22, 0x2c, 0x65, 0x28, 0x65, 0x2e, 0x73, 0x3d, 0x30, 0x29, 0x7d, 0x28, 0x5b, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x2c, 0x74, 0x2c, 0x65, 0x29, 0x7b, 0x22, 0x75, 0x73, 0x65, 0x20, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x22, 0x3b, 0x65, 0x2e, 0x72, 0x28, 0x74, 0x29, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x72, 0x3d, 0x7b, 0x7d, 0x3b, 0x65, 0x2e, 0x72, 0x28, 0x72, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x72, 0x2c, 0x22, 0x54, 0x72, 0x61, 0x63, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x76, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x72, 0x2c, 0x22, 0x50, 0x72, 0x69, 0x6e, 0x74, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x70, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x72, 0x2c, 0x22, 0x44, 0x65, 0x62, 0x75, 0x67, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x79, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x72, 0x2c, 0x22, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6d, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x72, 0x2c, 0x22, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x62, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x72, 0x2c, 0x22, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x67, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x72, 0x2c, 0x22, 0x46, 0x61, 0x74, 0x61, 0x6c, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x68, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x72, 0x2c, 0x22, 0x53, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x53, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x72, 0x2c, 0x22, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x45, 0x7d, 0x29, 0x29, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x69, 0x3d, 0x7b, 0x7d, 0x3b, 0x65, 0x2e, 0x72, 0x28, 0x69, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x69, 0x2c, 0x22, 0x4f, 0x70, 0x65, 0x6e, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x4d, 0x7d, 0x29, 0x29, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x6f, 0x3d, 0x7b, 0x7d, 0x3b, 0x65, 0x2e, 0x72, 0x28, 0x6f, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x4e, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x53, 0x65, 0x74, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x54, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x46, 0x75, 0x6c, 0x6c, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6a, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x55, 0x6e, 0x46, 0x75, 0x6c, 0x6c, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x44, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x53, 0x65, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x49, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x53, 0x65, 0x74, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x50, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x48, 0x69, 0x64, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x41, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x53, 0x68, 0x6f, 0x77, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x4a, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x4d, 0x61, 0x78, 0x69, 0x6d, 0x69, 0x73, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x4c, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x55, 0x6e, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x69, 0x73, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x52, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x69, 0x73, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x55, 0x6e, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x69, 0x73, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x46, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x55, 0x7d, 0x29, 0x29, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x61, 0x3d, 0x7b, 0x7d, 0x3b, 0x65, 0x2e, 0x72, 0x28, 0x61, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x61, 0x2c, 0x22, 0x4f, 0x70, 0x65, 0x6e, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x42, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x61, 0x2c, 0x22, 0x53, 0x61, 0x76, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x48, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x61, 0x2c, 0x22, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x47, 0x7d, 0x29, 0x29, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x75, 0x3d, 0x7b, 0x7d, 0x3b, 0x65, 0x2e, 0x72, 0x28, 0x75, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x75, 0x2c, 0x22, 0x4e, 0x65, 0x77, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x65, 0x6e, 0x7d, 0x29, 0x29, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x63, 0x3d, 0x7b, 0x7d, 0x3b, 0x65, 0x2e, 0x72, 0x28, 0x63, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x63, 0x2c, 0x22, 0x53, 0x65, 0x74, 0x49, 0x63, 0x6f, 0x6e, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x6e, 0x7d, 0x29, 0x29, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x6c, 0x3d, 0x7b, 0x41, 0x70, 0x70, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x22, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x22, 0x2c, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x3a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x22, 0x6c, 0x69, 0x6e, 0x75, 0x78, 0x22, 0x7d, 0x7d, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x73, 0x3d, 0x5b, 0x5d, 0x3b, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x66, 0x28, 0x6e, 0x29, 0x7b, 0x73, 0x2e, 0x70, 0x75, 0x73, 0x68, 0x28, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x64, 0x28, 0x6e, 0x29, 0x7b, 0x69, 0x66, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x28, 0x6e, 0x29, 0x7d, 0x28, 0x6e, 0x29, 0x2c, 0x73, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3e, 0x30, 0x29, 0x66, 0x6f, 0x72, 0x28, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x30, 0x3b, 0x74, 0x3c, 0x73, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3b, 0x74, 0x2b, 0x2b, 0x29, 0x73, 0x5b, 0x74, 0x5d, 0x28, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x77, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x4c, 0x22, 0x2b, 0x6e, 0x2b, 0x74, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x76, 0x28, 0x6e, 0x29, 0x7b, 0x77, 0x28, 0x22, 0x54, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x70, 0x28, 0x6e, 0x29, 0x7b, 0x77, 0x28, 0x22, 0x50, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x79, 0x28, 0x6e, 0x29, 0x7b, 0x77, 0x28, 0x22, 0x44, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x28, 0x6e, 0x29, 0x7b, 0x77, 0x28, 0x22, 0x49, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x62, 0x28, 0x6e, 0x29, 0x7b, 0x77, 0x28, 0x22, 0x57, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x67, 0x28, 0x6e, 0x29, 0x7b, 0x77, 0x28, 0x22, 0x45, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x68, 0x28, 0x6e, 0x29, 0x7b, 0x77, 0x28, 0x22, 0x46, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x53, 0x28, 0x6e, 0x29, 0x7b, 0x77, 0x28, 0x22, 0x53, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x76, 0x61, 0x72, 0x20, 0x4f, 0x2c, 0x45, 0x3d, 0x7b, 0x54, 0x52, 0x41, 0x43, 0x45, 0x3a, 0x31, 0x2c, 0x44, 0x45, 0x42, 0x55, 0x47, 0x3a, 0x32, 0x2c, 0x49, 0x4e, 0x46, 0x4f, 0x3a, 0x33, 0x2c, 0x57, 0x41, 0x52, 0x4e, 0x49, 0x4e, 0x47, 0x3a, 0x34, 0x2c, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x3a, 0x35, 0x7d, 0x2c, 0x6b, 0x3d, 0x7b, 0x7d, 0x3b, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x43, 0x28, 0x6e, 0x2c, 0x74, 0x2c, 0x65, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x21, 0x3d, 0x65, 0x26, 0x26, 0x6e, 0x75, 0x6c, 0x6c, 0x21, 0x3d, 0x65, 0x7c, 0x7c, 0x28, 0x65, 0x3d, 0x30, 0x29, 0x2c, 0x6e, 0x65, 0x77, 0x20, 0x50, 0x72, 0x6f, 0x6d, 0x69, 0x73, 0x65, 0x28, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x72, 0x2c, 0x69, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x6f, 0x3b, 0x64, 0x6f, 0x7b, 0x6f, 0x3d, 0x6e, 0x2b, 0x22, 0x2d, 0x22, 0x2b, 0x4f, 0x28, 0x29, 0x7d, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x28, 0x6b, 0x5b, 0x6f, 0x5d, 0x29, 0x3b, 0x69, 0x66, 0x28, 0x65, 0x3e, 0x30, 0x29, 0x76, 0x61, 0x72, 0x20, 0x61, 0x3d, 0x73, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x28, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x69, 0x28, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x22, 0x43, 0x61, 0x6c, 0x6c, 0x20, 0x74, 0x6f, 0x20, 0x22, 0x2b, 0x6e, 0x2b, 0x22, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x64, 0x20, 0x6f, 0x75, 0x74, 0x2e, 0x20, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x20, 0x49, 0x44, 0x3a, 0x20, 0x22, 0x2b, 0x6f, 0x29, 0x29, 0x7d, 0x29, 0x2c, 0x65, 0x29, 0x3b, 0x6b, 0x5b, 0x6f, 0x5d, 0x3d, 0x7b, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x3a, 0x61, 0x2c, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x69, 0x2c, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x3a, 0x72, 0x7d, 0x3b, 0x74, 0x72, 0x79, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x75, 0x3d, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x6e, 0x2c, 0x61, 0x72, 0x67, 0x73, 0x3a, 0x74, 0x2c, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x49, 0x44, 0x3a, 0x6f, 0x7d, 0x3b, 0x64, 0x28, 0x22, 0x43, 0x22, 0x2b, 0x4a, 0x53, 0x4f, 0x4e, 0x2e, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x69, 0x66, 0x79, 0x28, 0x75, 0x29, 0x29, 0x7d, 0x63, 0x61, 0x74, 0x63, 0x68, 0x28, 0x6e, 0x29, 0x7b, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x6e, 0x29, 0x7d, 0x7d, 0x29, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x57, 0x28, 0x6e, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3b, 0x74, 0x72, 0x79, 0x7b, 0x74, 0x3d, 0x4a, 0x53, 0x4f, 0x4e, 0x2e, 0x70, 0x61, 0x72, 0x73, 0x65, 0x28, 0x6e, 0x29, 0x7d, 0x63, 0x61, 0x74, 0x63, 0x68, 0x28, 0x74, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x65, 0x3d, 0x22, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x4a, 0x53, 0x4f, 0x4e, 0x20, 0x70, 0x61, 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x3a, 0x20, 0x22, 0x2e, 0x63, 0x6f, 0x6e, 0x63, 0x61, 0x74, 0x28, 0x74, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, 0x22, 0x2e, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x3a, 0x20, 0x22, 0x29, 0x2e, 0x63, 0x6f, 0x6e, 0x63, 0x61, 0x74, 0x28, 0x6e, 0x29, 0x3b, 0x74, 0x68, 0x72, 0x6f, 0x77, 0x20, 0x79, 0x28, 0x65, 0x29, 0x2c, 0x6e, 0x65, 0x77, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x65, 0x29, 0x7d, 0x76, 0x61, 0x72, 0x20, 0x72, 0x3d, 0x74, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x69, 0x64, 0x2c, 0x69, 0x3d, 0x6b, 0x5b, 0x72, 0x5d, 0x3b, 0x69, 0x66, 0x28, 0x21, 0x69, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x6f, 0x3d, 0x22, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x20, 0x27, 0x22, 0x2e, 0x63, 0x6f, 0x6e, 0x63, 0x61, 0x74, 0x28, 0x72, 0x2c, 0x22, 0x27, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x21, 0x21, 0x21, 0x22, 0x29, 0x3b, 0x74, 0x68, 0x72, 0x6f, 0x77, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x6f, 0x29, 0x2c, 0x6e, 0x65, 0x77, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x6f, 0x29, 0x7d, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x28, 0x69, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x2c, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x20, 0x6b, 0x5b, 0x72, 0x5d, 0x2c, 0x74, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x3f, 0x69, 0x2e, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x28, 0x74, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x29, 0x3a, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x28, 0x74, 0x2e, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x78, 0x28, 0x6e, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x5b, 0x5d, 0x2e, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x28, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x29, 0x2e, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x28, 0x31, 0x29, 0x3b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x43, 0x28, 0x22, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x22, 0x2b, 0x6e, 0x2c, 0x74, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x4d, 0x28, 0x6e, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x64, 0x28, 0x22, 0x52, 0x42, 0x4f, 0x22, 0x2b, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x4e, 0x28, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x63, 0x22, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x54, 0x28, 0x6e, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x54, 0x22, 0x2b, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6a, 0x28, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x46, 0x22, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x44, 0x28, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x66, 0x22, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x49, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x73, 0x3a, 0x22, 0x2b, 0x6e, 0x2b, 0x22, 0x3a, 0x22, 0x2b, 0x74, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x50, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x70, 0x3a, 0x22, 0x2b, 0x6e, 0x2b, 0x22, 0x3a, 0x22, 0x2b, 0x74, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x28, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x48, 0x22, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x4a, 0x28, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x53, 0x22, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x4c, 0x28, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x4d, 0x22, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x52, 0x28, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x55, 0x22, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x5f, 0x28, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x6d, 0x22, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x46, 0x28, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x75, 0x22, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x55, 0x28, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x43, 0x22, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x42, 0x28, 0x6e, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x78, 0x28, 0x22, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x48, 0x28, 0x6e, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x78, 0x28, 0x22, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x2e, 0x53, 0x61, 0x76, 0x65, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x47, 0x28, 0x6e, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x78, 0x28, 0x22, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x4f, 0x3d, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x3f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x6e, 0x3d, 0x6e, 0x65, 0x77, 0x20, 0x55, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x41, 0x72, 0x72, 0x61, 0x79, 0x28, 0x31, 0x29, 0x3b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x67, 0x65, 0x74, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x28, 0x6e, 0x29, 0x5b, 0x30, 0x5d, 0x7d, 0x3a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x39, 0x30, 0x30, 0x37, 0x31, 0x39, 0x39, 0x32, 0x35, 0x34, 0x37, 0x34, 0x30, 0x39, 0x39, 0x31, 0x2a, 0x4d, 0x61, 0x74, 0x68, 0x2e, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x28, 0x29, 0x7d, 0x2c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x3d, 0x7b, 0x7d, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x71, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6e, 0x28, 0x74, 0x2c, 0x65, 0x29, 0x7b, 0x21, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7b, 0x69, 0x66, 0x28, 0x21, 0x28, 0x6e, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x6f, 0x66, 0x20, 0x74, 0x29, 0x29, 0x74, 0x68, 0x72, 0x6f, 0x77, 0x20, 0x6e, 0x65, 0x77, 0x20, 0x54, 0x79, 0x70, 0x65, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x22, 0x43, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x63, 0x61, 0x6c, 0x6c, 0x20, 0x61, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x61, 0x73, 0x20, 0x61, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x29, 0x7d, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2c, 0x6e, 0x29, 0x2c, 0x65, 0x3d, 0x65, 0x7c, 0x7c, 0x2d, 0x31, 0x2c, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x28, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x6e, 0x29, 0x2c, 0x2d, 0x31, 0x21, 0x3d, 0x3d, 0x65, 0x26, 0x26, 0x30, 0x3d, 0x3d, 0x3d, 0x28, 0x65, 0x2d, 0x3d, 0x31, 0x29, 0x7d, 0x7d, 0x2c, 0x7a, 0x3d, 0x7b, 0x7d, 0x3b, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x56, 0x28, 0x6e, 0x2c, 0x74, 0x2c, 0x65, 0x29, 0x7b, 0x7a, 0x5b, 0x6e, 0x5d, 0x3d, 0x7a, 0x5b, 0x6e, 0x5d, 0x7c, 0x7c, 0x5b, 0x5d, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x72, 0x3d, 0x6e, 0x65, 0x77, 0x20, 0x71, 0x28, 0x74, 0x2c, 0x65, 0x29, 0x3b, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x2e, 0x6c, 0x6f, 0x67, 0x28, 0x22, 0x50, 0x75, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x3a, 0x20, 0x22, 0x2b, 0x6e, 0x29, 0x2c, 0x7a, 0x5b, 0x6e, 0x5d, 0x2e, 0x70, 0x75, 0x73, 0x68, 0x28, 0x72, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x4b, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7b, 0x56, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x51, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7b, 0x56, 0x28, 0x6e, 0x2c, 0x74, 0x2c, 0x31, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x58, 0x28, 0x6e, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x6e, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x3b, 0x69, 0x66, 0x28, 0x7a, 0x5b, 0x74, 0x5d, 0x29, 0x7b, 0x66, 0x6f, 0x72, 0x28, 0x76, 0x61, 0x72, 0x20, 0x65, 0x3d, 0x7a, 0x5b, 0x74, 0x5d, 0x2e, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x28, 0x29, 0x2c, 0x72, 0x3d, 0x30, 0x3b, 0x72, 0x3c, 0x7a, 0x5b, 0x74, 0x5d, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3b, 0x72, 0x2b, 0x3d, 0x31, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x69, 0x3d, 0x7a, 0x5b, 0x74, 0x5d, 0x5b, 0x72, 0x5d, 0x2c, 0x6f, 0x3d, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x3b, 0x69, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x28, 0x6f, 0x29, 0x26, 0x26, 0x65, 0x2e, 0x73, 0x70, 0x6c, 0x69, 0x63, 0x65, 0x28, 0x72, 0x2c, 0x31, 0x29, 0x7d, 0x7a, 0x5b, 0x74, 0x5d, 0x3d, 0x65, 0x7d, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x59, 0x28, 0x6e, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3b, 0x74, 0x72, 0x79, 0x7b, 0x74, 0x3d, 0x4a, 0x53, 0x4f, 0x4e, 0x2e, 0x70, 0x61, 0x72, 0x73, 0x65, 0x28, 0x6e, 0x29, 0x7d, 0x63, 0x61, 0x74, 0x63, 0x68, 0x28, 0x74, 0x29, 0x7b, 0x74, 0x68, 0x72, 0x6f, 0x77, 0x20, 0x6e, 0x65, 0x77, 0x20, 0x67, 0x28, 0x22, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x4a, 0x53, 0x4f, 0x4e, 0x20, 0x70, 0x61, 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x3a, 0x20, 0x22, 0x2b, 0x6e, 0x29, 0x7d, 0x58, 0x28, 0x74, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x5a, 0x28, 0x6e, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x6e, 0x2c, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x5b, 0x5d, 0x2e, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x28, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x29, 0x2e, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x28, 0x31, 0x29, 0x7d, 0x3b, 0x58, 0x28, 0x74, 0x29, 0x2c, 0x64, 0x28, 0x22, 0x45, 0x6a, 0x22, 0x2b, 0x4a, 0x53, 0x4f, 0x4e, 0x2e, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x69, 0x66, 0x79, 0x28, 0x74, 0x29, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x24, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x65, 0x3d, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x28, 0x22, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x22, 0x29, 0x3b, 0x65, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x3d, 0x6e, 0x2c, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x62, 0x6f, 0x64, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x28, 0x65, 0x29, 0x2c, 0x74, 0x26, 0x26, 0x5a, 0x28, 0x74, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6e, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x74, 0x72, 0x79, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x28, 0x22, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x22, 0x29, 0x3b, 0x74, 0x2e, 0x73, 0x65, 0x74, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x28, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x2c, 0x22, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x63, 0x73, 0x73, 0x22, 0x29, 0x2c, 0x74, 0x2e, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x53, 0x68, 0x65, 0x65, 0x74, 0x3f, 0x74, 0x2e, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x53, 0x68, 0x65, 0x65, 0x74, 0x2e, 0x63, 0x73, 0x73, 0x54, 0x65, 0x78, 0x74, 0x3d, 0x6e, 0x3a, 0x74, 0x2e, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x28, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x65, 0x78, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x28, 0x6e, 0x29, 0x29, 0x2c, 0x28, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x7c, 0x7c, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x79, 0x54, 0x61, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x28, 0x22, 0x68, 0x65, 0x61, 0x64, 0x22, 0x29, 0x5b, 0x30, 0x5d, 0x29, 0x2e, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x28, 0x74, 0x29, 0x7d, 0x63, 0x61, 0x74, 0x63, 0x68, 0x28, 0x6e, 0x29, 0x7b, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x2e, 0x6c, 0x6f, 0x67, 0x28, 0x6e, 0x29, 0x7d, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x6e, 0x28, 0x29, 0x7b, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x57, 0x61, 0x69, 0x6c, 0x73, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x4d, 0x65, 0x6e, 0x75, 0x3d, 0x21, 0x30, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x65, 0x6e, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x65, 0x3b, 0x69, 0x66, 0x28, 0x21, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x29, 0x74, 0x68, 0x72, 0x6f, 0x77, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x22, 0x57, 0x61, 0x69, 0x6c, 0x73, 0x20, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x73, 0x65, 0x64, 0x22, 0x29, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x72, 0x3d, 0x5b, 0x5d, 0x3b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4f, 0x6e, 0x28, 0x22, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x3a, 0x73, 0x79, 0x6e, 0x63, 0x3a, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x3a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x62, 0x79, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x3a, 0x22, 0x2b, 0x6e, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x4a, 0x53, 0x4f, 0x4e, 0x2e, 0x70, 0x61, 0x72, 0x73, 0x65, 0x28, 0x6e, 0x29, 0x3b, 0x65, 0x3d, 0x74, 0x2c, 0x72, 0x2e, 0x66, 0x6f, 0x72, 0x45, 0x61, 0x63, 0x68, 0x28, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x6e, 0x28, 0x65, 0x29, 0x7d, 0x29, 0x29, 0x7d, 0x29, 0x29, 0x2c, 0x74, 0x26, 0x26, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x73, 0x65, 0x74, 0x28, 0x74, 0x29, 0x2c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x6d, 0x69, 0x74, 0x28, 0x22, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x3a, 0x73, 0x79, 0x6e, 0x63, 0x3a, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x3a, 0x72, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x3a, 0x22, 0x2b, 0x6e, 0x29, 0x2c, 0x7b, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x3a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x72, 0x2e, 0x70, 0x75, 0x73, 0x68, 0x28, 0x6e, 0x29, 0x7d, 0x2c, 0x67, 0x65, 0x74, 0x3a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x65, 0x7d, 0x2c, 0x73, 0x65, 0x74, 0x3a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x74, 0x29, 0x7b, 0x65, 0x3d, 0x74, 0x2c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x6d, 0x69, 0x74, 0x28, 0x22, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x3a, 0x73, 0x79, 0x6e, 0x63, 0x3a, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x3a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x62, 0x79, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x3a, 0x22, 0x2b, 0x6e, 0x2c, 0x4a, 0x53, 0x4f, 0x4e, 0x2e, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x69, 0x66, 0x79, 0x28, 0x65, 0x29, 0x29, 0x2c, 0x72, 0x2e, 0x66, 0x6f, 0x72, 0x45, 0x61, 0x63, 0x68, 0x28, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x6e, 0x28, 0x65, 0x29, 0x7d, 0x29, 0x29, 0x7d, 0x2c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x6e, 0x28, 0x65, 0x29, 0x3b, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x73, 0x65, 0x74, 0x28, 0x74, 0x29, 0x7d, 0x7d, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x54, 0x49, 0x22, 0x2b, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x28, 0x6f, 0x6e, 0x3d, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x61, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x7c, 0x7c, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x66, 0x6f, 0x72, 0x28, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x31, 0x3b, 0x74, 0x3c, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3b, 0x74, 0x2b, 0x2b, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x65, 0x3d, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x5b, 0x74, 0x5d, 0x3b, 0x66, 0x6f, 0x72, 0x28, 0x76, 0x61, 0x72, 0x20, 0x72, 0x20, 0x69, 0x6e, 0x20, 0x65, 0x29, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x68, 0x61, 0x73, 0x4f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x65, 0x2c, 0x72, 0x29, 0x26, 0x26, 0x28, 0x6e, 0x5b, 0x72, 0x5d, 0x3d, 0x65, 0x5b, 0x72, 0x5d, 0x29, 0x7d, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x7d, 0x29, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2c, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x29, 0x7d, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x3d, 0x7b, 0x7d, 0x2c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x3d, 0x7b, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x3a, 0x6c, 0x2c, 0x4c, 0x6f, 0x67, 0x3a, 0x72, 0x2c, 0x42, 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, 0x3a, 0x69, 0x2c, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x3a, 0x6f, 0x2c, 0x54, 0x72, 0x61, 0x79, 0x3a, 0x63, 0x2c, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x3a, 0x61, 0x2c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x3a, 0x7b, 0x4f, 0x6e, 0x3a, 0x4b, 0x2c, 0x4f, 0x6e, 0x63, 0x65, 0x3a, 0x51, 0x2c, 0x4f, 0x6e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x3a, 0x56, 0x2c, 0x45, 0x6d, 0x69, 0x74, 0x3a, 0x5a, 0x7d, 0x2c, 0x5f, 0x3a, 0x7b, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x3a, 0x57, 0x2c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x3a, 0x59, 0x2c, 0x41, 0x64, 0x64, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x3a, 0x24, 0x2c, 0x49, 0x6e, 0x6a, 0x65, 0x63, 0x74, 0x43, 0x53, 0x53, 0x3a, 0x6e, 0x6e, 0x2c, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x4d, 0x65, 0x6e, 0x75, 0x3a, 0x74, 0x6e, 0x2c, 0x41, 0x64, 0x64, 0x49, 0x50, 0x43, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x3a, 0x66, 0x2c, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x61, 0x6c, 0x6c, 0x3a, 0x78, 0x2c, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x3a, 0x64, 0x7d, 0x2c, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x3a, 0x75, 0x7d, 0x2c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x3d, 0x7b, 0x49, 0x73, 0x44, 0x61, 0x72, 0x6b, 0x4d, 0x6f, 0x64, 0x65, 0x3a, 0x65, 0x6e, 0x28, 0x22, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x3a, 0x69, 0x73, 0x64, 0x61, 0x72, 0x6b, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0x29, 0x2c, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x3a, 0x65, 0x6e, 0x28, 0x22, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x3a, 0x6c, 0x6f, 0x67, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x29, 0x2c, 0x41, 0x70, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x3a, 0x65, 0x6e, 0x28, 0x22, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x3a, 0x61, 0x70, 0x70, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x29, 0x7d, 0x2c, 0x6f, 0x6e, 0x28, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2c, 0x6c, 0x29, 0x2c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x61, 0x64, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x28, 0x22, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x64, 0x6f, 0x77, 0x6e, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x66, 0x6f, 0x72, 0x28, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x6e, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x3b, 0x6e, 0x75, 0x6c, 0x6c, 0x21, 0x3d, 0x74, 0x26, 0x26, 0x21, 0x74, 0x2e, 0x68, 0x61, 0x73, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x28, 0x22, 0x64, 0x61, 0x74, 0x61, 0x2d, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2d, 0x6e, 0x6f, 0x2d, 0x64, 0x72, 0x61, 0x67, 0x22, 0x29, 0x3b, 0x29, 0x7b, 0x69, 0x66, 0x28, 0x74, 0x2e, 0x68, 0x61, 0x73, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x28, 0x22, 0x64, 0x61, 0x74, 0x61, 0x2d, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2d, 0x64, 0x72, 0x61, 0x67, 0x22, 0x29, 0x29, 0x7b, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x44, 0x72, 0x61, 0x67, 0x28, 0x6e, 0x75, 0x6c, 0x6c, 0x29, 0x3b, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x7d, 0x74, 0x3d, 0x74, 0x2e, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x7d, 0x7d, 0x29, 0x29, 0x2c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x61, 0x64, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x28, 0x22, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x6d, 0x65, 0x6e, 0x75, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x66, 0x6f, 0x72, 0x28, 0x76, 0x61, 0x72, 0x20, 0x74, 0x2c, 0x65, 0x3d, 0x6e, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x3b, 0x6e, 0x75, 0x6c, 0x6c, 0x21, 0x3d, 0x65, 0x26, 0x26, 0x6e, 0x75, 0x6c, 0x6c, 0x3d, 0x3d, 0x28, 0x74, 0x3d, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x5b, 0x22, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x6d, 0x65, 0x6e, 0x75, 0x2d, 0x69, 0x64, 0x22, 0x5d, 0x29, 0x3b, 0x29, 0x65, 0x3d, 0x65, 0x2e, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x3b, 0x69, 0x66, 0x28, 0x28, 0x6e, 0x75, 0x6c, 0x6c, 0x21, 0x3d, 0x74, 0x7c, 0x7c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x57, 0x61, 0x69, 0x6c, 0x73, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x4d, 0x65, 0x6e, 0x75, 0x29, 0x26, 0x26, 0x6e, 0x2e, 0x70, 0x72, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x28, 0x29, 0x2c, 0x6e, 0x75, 0x6c, 0x6c, 0x21, 0x3d, 0x74, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x72, 0x3d, 0x7b, 0x69, 0x64, 0x3a, 0x74, 0x2c, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x5b, 0x22, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x6d, 0x65, 0x6e, 0x75, 0x2d, 0x64, 0x61, 0x74, 0x61, 0x22, 0x5d, 0x7c, 0x7c, 0x22, 0x22, 0x7d, 0x3b, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x4d, 0x65, 0x6e, 0x75, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x28, 0x4a, 0x53, 0x4f, 0x4e, 0x2e, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x69, 0x66, 0x79, 0x28, 0x72, 0x29, 0x29, 0x7d, 0x7d, 0x29, 0x29, 0x2c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x26, 0x26, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x74, 0x72, 0x79, 0x7b, 0x6e, 0x3d, 0x4a, 0x53, 0x4f, 0x4e, 0x2e, 0x70, 0x61, 0x72, 0x73, 0x65, 0x28, 0x6e, 0x29, 0x7d, 0x63, 0x61, 0x74, 0x63, 0x68, 0x28, 0x6e, 0x29, 0x7b, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x6e, 0x29, 0x7d, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x3d, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x7c, 0x7c, 0x7b, 0x7d, 0x2c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x6e, 0x29, 0x2e, 0x66, 0x6f, 0x72, 0x45, 0x61, 0x63, 0x68, 0x28, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x74, 0x29, 0x7b, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5b, 0x74, 0x5d, 0x3d, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5b, 0x74, 0x5d, 0x7c, 0x7c, 0x7b, 0x7d, 0x2c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x6e, 0x5b, 0x74, 0x5d, 0x29, 0x2e, 0x66, 0x6f, 0x72, 0x45, 0x61, 0x63, 0x68, 0x28, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x65, 0x29, 0x7b, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5b, 0x74, 0x5d, 0x5b, 0x65, 0x5d, 0x3d, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5b, 0x74, 0x5d, 0x5b, 0x65, 0x5d, 0x7c, 0x7c, 0x7b, 0x7d, 0x2c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x6e, 0x5b, 0x74, 0x5d, 0x5b, 0x65, 0x5d, 0x29, 0x2e, 0x66, 0x6f, 0x72, 0x45, 0x61, 0x63, 0x68, 0x28, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5b, 0x74, 0x5d, 0x5b, 0x65, 0x5d, 0x5b, 0x6e, 0x5d, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x72, 0x3d, 0x30, 0x3b, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x28, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x69, 0x3d, 0x5b, 0x5d, 0x2e, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x29, 0x3b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x43, 0x28, 0x5b, 0x74, 0x2c, 0x65, 0x2c, 0x6e, 0x5d, 0x2e, 0x6a, 0x6f, 0x69, 0x6e, 0x28, 0x22, 0x2e, 0x22, 0x29, 0x2c, 0x69, 0x2c, 0x72, 0x29, 0x7d, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x69, 0x2e, 0x73, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x72, 0x3d, 0x6e, 0x7d, 0x2c, 0x69, 0x2e, 0x67, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x7d, 0x2c, 0x69, 0x7d, 0x28, 0x29, 0x7d, 0x29, 0x29, 0x7d, 0x29, 0x29, 0x7d, 0x29, 0x29, 0x7d, 0x28, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x2c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x6d, 0x69, 0x74, 0x28, 0x22, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x3a, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x22, 0x29, 0x7d, 0x5d, 0x29, 0x3b, 0x00}; \ No newline at end of file diff --git a/v2/internal/ffenestri/runtime_windows.c b/v2/internal/ffenestri/runtime_windows.c new file mode 100644 index 000000000..e9a3ff705 --- /dev/null +++ b/v2/internal/ffenestri/runtime_windows.c @@ -0,0 +1,5 @@ + +// runtime.c (c) 2019-Present Lea Anthony. +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file was auto-generated. DO NOT MODIFY. +const unsigned char runtime[]={0x76, 0x61, 0x72, 0x20, 0x57, 0x61, 0x69, 0x6c, 0x73, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x7b, 0x7d, 0x3b, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x65, 0x28, 0x72, 0x29, 0x7b, 0x69, 0x66, 0x28, 0x74, 0x5b, 0x72, 0x5d, 0x29, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x5b, 0x72, 0x5d, 0x2e, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x69, 0x3d, 0x74, 0x5b, 0x72, 0x5d, 0x3d, 0x7b, 0x69, 0x3a, 0x72, 0x2c, 0x6c, 0x3a, 0x21, 0x31, 0x2c, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x3a, 0x7b, 0x7d, 0x7d, 0x3b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x5b, 0x72, 0x5d, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x69, 0x2e, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x2c, 0x69, 0x2c, 0x69, 0x2e, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x2c, 0x65, 0x29, 0x2c, 0x69, 0x2e, 0x6c, 0x3d, 0x21, 0x30, 0x2c, 0x69, 0x2e, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x7d, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x65, 0x2e, 0x6d, 0x3d, 0x6e, 0x2c, 0x65, 0x2e, 0x63, 0x3d, 0x74, 0x2c, 0x65, 0x2e, 0x64, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x2c, 0x74, 0x2c, 0x72, 0x29, 0x7b, 0x65, 0x2e, 0x6f, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7c, 0x7c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x28, 0x6e, 0x2c, 0x74, 0x2c, 0x7b, 0x65, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x3a, 0x21, 0x30, 0x2c, 0x67, 0x65, 0x74, 0x3a, 0x72, 0x7d, 0x29, 0x7d, 0x2c, 0x65, 0x2e, 0x72, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x22, 0x75, 0x6e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x22, 0x21, 0x3d, 0x74, 0x79, 0x70, 0x65, 0x6f, 0x66, 0x20, 0x53, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x26, 0x26, 0x53, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x2e, 0x74, 0x6f, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x26, 0x26, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x28, 0x6e, 0x2c, 0x53, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x2e, 0x74, 0x6f, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x2c, 0x7b, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x22, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x22, 0x7d, 0x29, 0x2c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x28, 0x6e, 0x2c, 0x22, 0x5f, 0x5f, 0x65, 0x73, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x22, 0x2c, 0x7b, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x21, 0x30, 0x7d, 0x29, 0x7d, 0x2c, 0x65, 0x2e, 0x74, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7b, 0x69, 0x66, 0x28, 0x31, 0x26, 0x74, 0x26, 0x26, 0x28, 0x6e, 0x3d, 0x65, 0x28, 0x6e, 0x29, 0x29, 0x2c, 0x38, 0x26, 0x74, 0x29, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x3b, 0x69, 0x66, 0x28, 0x34, 0x26, 0x74, 0x26, 0x26, 0x22, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x3d, 0x3d, 0x74, 0x79, 0x70, 0x65, 0x6f, 0x66, 0x20, 0x6e, 0x26, 0x26, 0x6e, 0x26, 0x26, 0x6e, 0x2e, 0x5f, 0x5f, 0x65, 0x73, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x29, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x72, 0x3d, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x28, 0x6e, 0x75, 0x6c, 0x6c, 0x29, 0x3b, 0x69, 0x66, 0x28, 0x65, 0x2e, 0x72, 0x28, 0x72, 0x29, 0x2c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x28, 0x72, 0x2c, 0x22, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x22, 0x2c, 0x7b, 0x65, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x3a, 0x21, 0x30, 0x2c, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x6e, 0x7d, 0x29, 0x2c, 0x32, 0x26, 0x74, 0x26, 0x26, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x21, 0x3d, 0x74, 0x79, 0x70, 0x65, 0x6f, 0x66, 0x20, 0x6e, 0x29, 0x66, 0x6f, 0x72, 0x28, 0x76, 0x61, 0x72, 0x20, 0x69, 0x20, 0x69, 0x6e, 0x20, 0x6e, 0x29, 0x65, 0x2e, 0x64, 0x28, 0x72, 0x2c, 0x69, 0x2c, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x74, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x5b, 0x74, 0x5d, 0x7d, 0x2e, 0x62, 0x69, 0x6e, 0x64, 0x28, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x69, 0x29, 0x29, 0x3b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x7d, 0x2c, 0x65, 0x2e, 0x6e, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x6e, 0x26, 0x26, 0x6e, 0x2e, 0x5f, 0x5f, 0x65, 0x73, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x3f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x7d, 0x3a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x7d, 0x3b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x65, 0x2e, 0x64, 0x28, 0x74, 0x2c, 0x22, 0x61, 0x22, 0x2c, 0x74, 0x29, 0x2c, 0x74, 0x7d, 0x2c, 0x65, 0x2e, 0x6f, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x68, 0x61, 0x73, 0x4f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7d, 0x2c, 0x65, 0x2e, 0x70, 0x3d, 0x22, 0x22, 0x2c, 0x65, 0x28, 0x65, 0x2e, 0x73, 0x3d, 0x30, 0x29, 0x7d, 0x28, 0x5b, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x2c, 0x74, 0x2c, 0x65, 0x29, 0x7b, 0x22, 0x75, 0x73, 0x65, 0x20, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x22, 0x3b, 0x65, 0x2e, 0x72, 0x28, 0x74, 0x29, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x72, 0x3d, 0x7b, 0x7d, 0x3b, 0x65, 0x2e, 0x72, 0x28, 0x72, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x72, 0x2c, 0x22, 0x54, 0x72, 0x61, 0x63, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x76, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x72, 0x2c, 0x22, 0x50, 0x72, 0x69, 0x6e, 0x74, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x70, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x72, 0x2c, 0x22, 0x44, 0x65, 0x62, 0x75, 0x67, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x79, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x72, 0x2c, 0x22, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6d, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x72, 0x2c, 0x22, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x62, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x72, 0x2c, 0x22, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x67, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x72, 0x2c, 0x22, 0x46, 0x61, 0x74, 0x61, 0x6c, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x68, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x72, 0x2c, 0x22, 0x53, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x53, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x72, 0x2c, 0x22, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x45, 0x7d, 0x29, 0x29, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x69, 0x3d, 0x7b, 0x7d, 0x3b, 0x65, 0x2e, 0x72, 0x28, 0x69, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x69, 0x2c, 0x22, 0x4f, 0x70, 0x65, 0x6e, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x54, 0x7d, 0x29, 0x29, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x6f, 0x3d, 0x7b, 0x7d, 0x3b, 0x65, 0x2e, 0x72, 0x28, 0x6f, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6a, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x53, 0x65, 0x74, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x78, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x46, 0x75, 0x6c, 0x6c, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x4d, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x55, 0x6e, 0x46, 0x75, 0x6c, 0x6c, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x49, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x53, 0x65, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x44, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x53, 0x65, 0x74, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x50, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x48, 0x69, 0x64, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x41, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x53, 0x68, 0x6f, 0x77, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x4a, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x4d, 0x61, 0x78, 0x69, 0x6d, 0x69, 0x73, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x4c, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x55, 0x6e, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x69, 0x73, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x52, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x69, 0x73, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x55, 0x6e, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x69, 0x73, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x46, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x6f, 0x2c, 0x22, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x55, 0x7d, 0x29, 0x29, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x61, 0x3d, 0x7b, 0x7d, 0x3b, 0x65, 0x2e, 0x72, 0x28, 0x61, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x61, 0x2c, 0x22, 0x4f, 0x70, 0x65, 0x6e, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x42, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x61, 0x2c, 0x22, 0x53, 0x61, 0x76, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x48, 0x7d, 0x29, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x61, 0x2c, 0x22, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x47, 0x7d, 0x29, 0x29, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x75, 0x3d, 0x7b, 0x7d, 0x3b, 0x65, 0x2e, 0x72, 0x28, 0x75, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x75, 0x2c, 0x22, 0x4e, 0x65, 0x77, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x65, 0x6e, 0x7d, 0x29, 0x29, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x63, 0x3d, 0x7b, 0x7d, 0x3b, 0x65, 0x2e, 0x72, 0x28, 0x63, 0x29, 0x2c, 0x65, 0x2e, 0x64, 0x28, 0x63, 0x2c, 0x22, 0x53, 0x65, 0x74, 0x49, 0x63, 0x6f, 0x6e, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x6e, 0x7d, 0x29, 0x29, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x6c, 0x3d, 0x7b, 0x41, 0x70, 0x70, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x22, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x22, 0x2c, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x3a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x22, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x22, 0x7d, 0x7d, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x73, 0x3d, 0x5b, 0x5d, 0x3b, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x66, 0x28, 0x6e, 0x29, 0x7b, 0x73, 0x2e, 0x70, 0x75, 0x73, 0x68, 0x28, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x64, 0x28, 0x6e, 0x29, 0x7b, 0x69, 0x66, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x28, 0x6e, 0x29, 0x7d, 0x28, 0x6e, 0x29, 0x2c, 0x73, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3e, 0x30, 0x29, 0x66, 0x6f, 0x72, 0x28, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x30, 0x3b, 0x74, 0x3c, 0x73, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3b, 0x74, 0x2b, 0x2b, 0x29, 0x73, 0x5b, 0x74, 0x5d, 0x28, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x77, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x4c, 0x22, 0x2b, 0x6e, 0x2b, 0x74, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x76, 0x28, 0x6e, 0x29, 0x7b, 0x77, 0x28, 0x22, 0x54, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x70, 0x28, 0x6e, 0x29, 0x7b, 0x77, 0x28, 0x22, 0x50, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x79, 0x28, 0x6e, 0x29, 0x7b, 0x77, 0x28, 0x22, 0x44, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x28, 0x6e, 0x29, 0x7b, 0x77, 0x28, 0x22, 0x49, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x62, 0x28, 0x6e, 0x29, 0x7b, 0x77, 0x28, 0x22, 0x57, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x67, 0x28, 0x6e, 0x29, 0x7b, 0x77, 0x28, 0x22, 0x45, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x68, 0x28, 0x6e, 0x29, 0x7b, 0x77, 0x28, 0x22, 0x46, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x53, 0x28, 0x6e, 0x29, 0x7b, 0x77, 0x28, 0x22, 0x53, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x76, 0x61, 0x72, 0x20, 0x4f, 0x2c, 0x45, 0x3d, 0x7b, 0x54, 0x52, 0x41, 0x43, 0x45, 0x3a, 0x31, 0x2c, 0x44, 0x45, 0x42, 0x55, 0x47, 0x3a, 0x32, 0x2c, 0x49, 0x4e, 0x46, 0x4f, 0x3a, 0x33, 0x2c, 0x57, 0x41, 0x52, 0x4e, 0x49, 0x4e, 0x47, 0x3a, 0x34, 0x2c, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x3a, 0x35, 0x7d, 0x2c, 0x6b, 0x3d, 0x7b, 0x7d, 0x3b, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x43, 0x28, 0x6e, 0x2c, 0x74, 0x2c, 0x65, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x21, 0x3d, 0x65, 0x26, 0x26, 0x6e, 0x75, 0x6c, 0x6c, 0x21, 0x3d, 0x65, 0x7c, 0x7c, 0x28, 0x65, 0x3d, 0x30, 0x29, 0x2c, 0x6e, 0x65, 0x77, 0x20, 0x50, 0x72, 0x6f, 0x6d, 0x69, 0x73, 0x65, 0x28, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x72, 0x2c, 0x69, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x6f, 0x3b, 0x64, 0x6f, 0x7b, 0x6f, 0x3d, 0x6e, 0x2b, 0x22, 0x2d, 0x22, 0x2b, 0x4f, 0x28, 0x29, 0x7d, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x28, 0x6b, 0x5b, 0x6f, 0x5d, 0x29, 0x3b, 0x69, 0x66, 0x28, 0x65, 0x3e, 0x30, 0x29, 0x76, 0x61, 0x72, 0x20, 0x61, 0x3d, 0x73, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x28, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x69, 0x28, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x22, 0x43, 0x61, 0x6c, 0x6c, 0x20, 0x74, 0x6f, 0x20, 0x22, 0x2b, 0x6e, 0x2b, 0x22, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x64, 0x20, 0x6f, 0x75, 0x74, 0x2e, 0x20, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x20, 0x49, 0x44, 0x3a, 0x20, 0x22, 0x2b, 0x6f, 0x29, 0x29, 0x7d, 0x29, 0x2c, 0x65, 0x29, 0x3b, 0x6b, 0x5b, 0x6f, 0x5d, 0x3d, 0x7b, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x3a, 0x61, 0x2c, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x69, 0x2c, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x3a, 0x72, 0x7d, 0x3b, 0x74, 0x72, 0x79, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x75, 0x3d, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x6e, 0x2c, 0x61, 0x72, 0x67, 0x73, 0x3a, 0x74, 0x2c, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x49, 0x44, 0x3a, 0x6f, 0x7d, 0x3b, 0x64, 0x28, 0x22, 0x43, 0x22, 0x2b, 0x4a, 0x53, 0x4f, 0x4e, 0x2e, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x69, 0x66, 0x79, 0x28, 0x75, 0x29, 0x29, 0x7d, 0x63, 0x61, 0x74, 0x63, 0x68, 0x28, 0x6e, 0x29, 0x7b, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x6e, 0x29, 0x7d, 0x7d, 0x29, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x57, 0x28, 0x6e, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3b, 0x74, 0x72, 0x79, 0x7b, 0x74, 0x3d, 0x4a, 0x53, 0x4f, 0x4e, 0x2e, 0x70, 0x61, 0x72, 0x73, 0x65, 0x28, 0x6e, 0x29, 0x7d, 0x63, 0x61, 0x74, 0x63, 0x68, 0x28, 0x74, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x65, 0x3d, 0x22, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x4a, 0x53, 0x4f, 0x4e, 0x20, 0x70, 0x61, 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x3a, 0x20, 0x22, 0x2e, 0x63, 0x6f, 0x6e, 0x63, 0x61, 0x74, 0x28, 0x74, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, 0x22, 0x2e, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x3a, 0x20, 0x22, 0x29, 0x2e, 0x63, 0x6f, 0x6e, 0x63, 0x61, 0x74, 0x28, 0x6e, 0x29, 0x3b, 0x74, 0x68, 0x72, 0x6f, 0x77, 0x20, 0x79, 0x28, 0x65, 0x29, 0x2c, 0x6e, 0x65, 0x77, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x65, 0x29, 0x7d, 0x76, 0x61, 0x72, 0x20, 0x72, 0x3d, 0x74, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x69, 0x64, 0x2c, 0x69, 0x3d, 0x6b, 0x5b, 0x72, 0x5d, 0x3b, 0x69, 0x66, 0x28, 0x21, 0x69, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x6f, 0x3d, 0x22, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x20, 0x27, 0x22, 0x2e, 0x63, 0x6f, 0x6e, 0x63, 0x61, 0x74, 0x28, 0x72, 0x2c, 0x22, 0x27, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x21, 0x21, 0x21, 0x22, 0x29, 0x3b, 0x74, 0x68, 0x72, 0x6f, 0x77, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x6f, 0x29, 0x2c, 0x6e, 0x65, 0x77, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x6f, 0x29, 0x7d, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x28, 0x69, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x2c, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x20, 0x6b, 0x5b, 0x72, 0x5d, 0x2c, 0x74, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x3f, 0x69, 0x2e, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x28, 0x74, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x29, 0x3a, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x28, 0x74, 0x2e, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x4e, 0x28, 0x6e, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x5b, 0x5d, 0x2e, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x28, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x29, 0x2e, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x28, 0x31, 0x29, 0x3b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x43, 0x28, 0x22, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x22, 0x2b, 0x6e, 0x2c, 0x74, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x54, 0x28, 0x6e, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x64, 0x28, 0x22, 0x52, 0x42, 0x4f, 0x22, 0x2b, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6a, 0x28, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x63, 0x22, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x78, 0x28, 0x6e, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x54, 0x22, 0x2b, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x4d, 0x28, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x46, 0x22, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x49, 0x28, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x66, 0x22, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x44, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x73, 0x3a, 0x22, 0x2b, 0x6e, 0x2b, 0x22, 0x3a, 0x22, 0x2b, 0x74, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x50, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x70, 0x3a, 0x22, 0x2b, 0x6e, 0x2b, 0x22, 0x3a, 0x22, 0x2b, 0x74, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x28, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x48, 0x22, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x4a, 0x28, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x53, 0x22, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x4c, 0x28, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x4d, 0x22, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x52, 0x28, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x55, 0x22, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x5f, 0x28, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x6d, 0x22, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x46, 0x28, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x75, 0x22, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x55, 0x28, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x57, 0x43, 0x22, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x42, 0x28, 0x6e, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x4e, 0x28, 0x22, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x48, 0x28, 0x6e, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x4e, 0x28, 0x22, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x2e, 0x53, 0x61, 0x76, 0x65, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x47, 0x28, 0x6e, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x4e, 0x28, 0x22, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x2c, 0x6e, 0x29, 0x7d, 0x4f, 0x3d, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x3f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x6e, 0x3d, 0x6e, 0x65, 0x77, 0x20, 0x55, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x41, 0x72, 0x72, 0x61, 0x79, 0x28, 0x31, 0x29, 0x3b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x67, 0x65, 0x74, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x28, 0x6e, 0x29, 0x5b, 0x30, 0x5d, 0x7d, 0x3a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x39, 0x30, 0x30, 0x37, 0x31, 0x39, 0x39, 0x32, 0x35, 0x34, 0x37, 0x34, 0x30, 0x39, 0x39, 0x31, 0x2a, 0x4d, 0x61, 0x74, 0x68, 0x2e, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x28, 0x29, 0x7d, 0x2c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x3d, 0x7b, 0x7d, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x71, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6e, 0x28, 0x74, 0x2c, 0x65, 0x29, 0x7b, 0x21, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7b, 0x69, 0x66, 0x28, 0x21, 0x28, 0x6e, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x6f, 0x66, 0x20, 0x74, 0x29, 0x29, 0x74, 0x68, 0x72, 0x6f, 0x77, 0x20, 0x6e, 0x65, 0x77, 0x20, 0x54, 0x79, 0x70, 0x65, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x22, 0x43, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x63, 0x61, 0x6c, 0x6c, 0x20, 0x61, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x61, 0x73, 0x20, 0x61, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x29, 0x7d, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2c, 0x6e, 0x29, 0x2c, 0x65, 0x3d, 0x65, 0x7c, 0x7c, 0x2d, 0x31, 0x2c, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x28, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x6e, 0x29, 0x2c, 0x2d, 0x31, 0x21, 0x3d, 0x3d, 0x65, 0x26, 0x26, 0x30, 0x3d, 0x3d, 0x3d, 0x28, 0x65, 0x2d, 0x3d, 0x31, 0x29, 0x7d, 0x7d, 0x2c, 0x7a, 0x3d, 0x7b, 0x7d, 0x3b, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x56, 0x28, 0x6e, 0x2c, 0x74, 0x2c, 0x65, 0x29, 0x7b, 0x7a, 0x5b, 0x6e, 0x5d, 0x3d, 0x7a, 0x5b, 0x6e, 0x5d, 0x7c, 0x7c, 0x5b, 0x5d, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x72, 0x3d, 0x6e, 0x65, 0x77, 0x20, 0x71, 0x28, 0x74, 0x2c, 0x65, 0x29, 0x3b, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x2e, 0x6c, 0x6f, 0x67, 0x28, 0x22, 0x50, 0x75, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x3a, 0x20, 0x22, 0x2b, 0x6e, 0x29, 0x2c, 0x7a, 0x5b, 0x6e, 0x5d, 0x2e, 0x70, 0x75, 0x73, 0x68, 0x28, 0x72, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x4b, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7b, 0x56, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x51, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7b, 0x56, 0x28, 0x6e, 0x2c, 0x74, 0x2c, 0x31, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x58, 0x28, 0x6e, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x6e, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x3b, 0x69, 0x66, 0x28, 0x7a, 0x5b, 0x74, 0x5d, 0x29, 0x7b, 0x66, 0x6f, 0x72, 0x28, 0x76, 0x61, 0x72, 0x20, 0x65, 0x3d, 0x7a, 0x5b, 0x74, 0x5d, 0x2e, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x28, 0x29, 0x2c, 0x72, 0x3d, 0x30, 0x3b, 0x72, 0x3c, 0x7a, 0x5b, 0x74, 0x5d, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3b, 0x72, 0x2b, 0x3d, 0x31, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x69, 0x3d, 0x7a, 0x5b, 0x74, 0x5d, 0x5b, 0x72, 0x5d, 0x2c, 0x6f, 0x3d, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x3b, 0x69, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x28, 0x6f, 0x29, 0x26, 0x26, 0x65, 0x2e, 0x73, 0x70, 0x6c, 0x69, 0x63, 0x65, 0x28, 0x72, 0x2c, 0x31, 0x29, 0x7d, 0x7a, 0x5b, 0x74, 0x5d, 0x3d, 0x65, 0x7d, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x59, 0x28, 0x6e, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3b, 0x74, 0x72, 0x79, 0x7b, 0x74, 0x3d, 0x4a, 0x53, 0x4f, 0x4e, 0x2e, 0x70, 0x61, 0x72, 0x73, 0x65, 0x28, 0x6e, 0x29, 0x7d, 0x63, 0x61, 0x74, 0x63, 0x68, 0x28, 0x74, 0x29, 0x7b, 0x74, 0x68, 0x72, 0x6f, 0x77, 0x20, 0x6e, 0x65, 0x77, 0x20, 0x67, 0x28, 0x22, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x4a, 0x53, 0x4f, 0x4e, 0x20, 0x70, 0x61, 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x3a, 0x20, 0x22, 0x2b, 0x6e, 0x29, 0x7d, 0x58, 0x28, 0x74, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x5a, 0x28, 0x6e, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x6e, 0x2c, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x5b, 0x5d, 0x2e, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x28, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x29, 0x2e, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x28, 0x31, 0x29, 0x7d, 0x3b, 0x58, 0x28, 0x74, 0x29, 0x2c, 0x64, 0x28, 0x22, 0x45, 0x6a, 0x22, 0x2b, 0x4a, 0x53, 0x4f, 0x4e, 0x2e, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x69, 0x66, 0x79, 0x28, 0x74, 0x29, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x24, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x65, 0x3d, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x28, 0x22, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x22, 0x29, 0x3b, 0x65, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x3d, 0x6e, 0x2c, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x62, 0x6f, 0x64, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x28, 0x65, 0x29, 0x2c, 0x74, 0x26, 0x26, 0x5a, 0x28, 0x74, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6e, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x74, 0x72, 0x79, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x28, 0x22, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x22, 0x29, 0x3b, 0x74, 0x2e, 0x73, 0x65, 0x74, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x28, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x2c, 0x22, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x63, 0x73, 0x73, 0x22, 0x29, 0x2c, 0x74, 0x2e, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x53, 0x68, 0x65, 0x65, 0x74, 0x3f, 0x74, 0x2e, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x53, 0x68, 0x65, 0x65, 0x74, 0x2e, 0x63, 0x73, 0x73, 0x54, 0x65, 0x78, 0x74, 0x3d, 0x6e, 0x3a, 0x74, 0x2e, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x28, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x65, 0x78, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x28, 0x6e, 0x29, 0x29, 0x2c, 0x28, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x7c, 0x7c, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x79, 0x54, 0x61, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x28, 0x22, 0x68, 0x65, 0x61, 0x64, 0x22, 0x29, 0x5b, 0x30, 0x5d, 0x29, 0x2e, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x28, 0x74, 0x29, 0x7d, 0x63, 0x61, 0x74, 0x63, 0x68, 0x28, 0x6e, 0x29, 0x7b, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x2e, 0x6c, 0x6f, 0x67, 0x28, 0x6e, 0x29, 0x7d, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x6e, 0x28, 0x29, 0x7b, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x57, 0x61, 0x69, 0x6c, 0x73, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x4d, 0x65, 0x6e, 0x75, 0x3d, 0x21, 0x30, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x65, 0x6e, 0x28, 0x6e, 0x2c, 0x74, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x65, 0x3b, 0x69, 0x66, 0x28, 0x21, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x29, 0x74, 0x68, 0x72, 0x6f, 0x77, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x22, 0x57, 0x61, 0x69, 0x6c, 0x73, 0x20, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x73, 0x65, 0x64, 0x22, 0x29, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x72, 0x3d, 0x5b, 0x5d, 0x3b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4f, 0x6e, 0x28, 0x22, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x3a, 0x73, 0x79, 0x6e, 0x63, 0x3a, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x3a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x62, 0x79, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x3a, 0x22, 0x2b, 0x6e, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x4a, 0x53, 0x4f, 0x4e, 0x2e, 0x70, 0x61, 0x72, 0x73, 0x65, 0x28, 0x6e, 0x29, 0x3b, 0x65, 0x3d, 0x74, 0x2c, 0x72, 0x2e, 0x66, 0x6f, 0x72, 0x45, 0x61, 0x63, 0x68, 0x28, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x6e, 0x28, 0x65, 0x29, 0x7d, 0x29, 0x29, 0x7d, 0x29, 0x29, 0x2c, 0x74, 0x26, 0x26, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x73, 0x65, 0x74, 0x28, 0x74, 0x29, 0x2c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x6d, 0x69, 0x74, 0x28, 0x22, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x3a, 0x73, 0x79, 0x6e, 0x63, 0x3a, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x3a, 0x72, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x3a, 0x22, 0x2b, 0x6e, 0x29, 0x2c, 0x7b, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x3a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x72, 0x2e, 0x70, 0x75, 0x73, 0x68, 0x28, 0x6e, 0x29, 0x7d, 0x2c, 0x67, 0x65, 0x74, 0x3a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x65, 0x7d, 0x2c, 0x73, 0x65, 0x74, 0x3a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x74, 0x29, 0x7b, 0x65, 0x3d, 0x74, 0x2c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x6d, 0x69, 0x74, 0x28, 0x22, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x3a, 0x73, 0x79, 0x6e, 0x63, 0x3a, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x3a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x62, 0x79, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x3a, 0x22, 0x2b, 0x6e, 0x2c, 0x4a, 0x53, 0x4f, 0x4e, 0x2e, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x69, 0x66, 0x79, 0x28, 0x65, 0x29, 0x29, 0x2c, 0x72, 0x2e, 0x66, 0x6f, 0x72, 0x45, 0x61, 0x63, 0x68, 0x28, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x6e, 0x28, 0x65, 0x29, 0x7d, 0x29, 0x29, 0x7d, 0x2c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x6e, 0x28, 0x65, 0x29, 0x3b, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x73, 0x65, 0x74, 0x28, 0x74, 0x29, 0x7d, 0x7d, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x64, 0x28, 0x22, 0x54, 0x49, 0x22, 0x2b, 0x6e, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x28, 0x6f, 0x6e, 0x3d, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x61, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x7c, 0x7c, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x66, 0x6f, 0x72, 0x28, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x31, 0x3b, 0x74, 0x3c, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3b, 0x74, 0x2b, 0x2b, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x65, 0x3d, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x5b, 0x74, 0x5d, 0x3b, 0x66, 0x6f, 0x72, 0x28, 0x76, 0x61, 0x72, 0x20, 0x72, 0x20, 0x69, 0x6e, 0x20, 0x65, 0x29, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x68, 0x61, 0x73, 0x4f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x65, 0x2c, 0x72, 0x29, 0x26, 0x26, 0x28, 0x6e, 0x5b, 0x72, 0x5d, 0x3d, 0x65, 0x5b, 0x72, 0x5d, 0x29, 0x7d, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x7d, 0x29, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2c, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x29, 0x7d, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x3d, 0x7b, 0x7d, 0x2c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x3d, 0x7b, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x3a, 0x6c, 0x2c, 0x4c, 0x6f, 0x67, 0x3a, 0x72, 0x2c, 0x42, 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, 0x3a, 0x69, 0x2c, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x3a, 0x6f, 0x2c, 0x54, 0x72, 0x61, 0x79, 0x3a, 0x63, 0x2c, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x3a, 0x61, 0x2c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x3a, 0x7b, 0x4f, 0x6e, 0x3a, 0x4b, 0x2c, 0x4f, 0x6e, 0x63, 0x65, 0x3a, 0x51, 0x2c, 0x4f, 0x6e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x3a, 0x56, 0x2c, 0x45, 0x6d, 0x69, 0x74, 0x3a, 0x5a, 0x7d, 0x2c, 0x5f, 0x3a, 0x7b, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x3a, 0x57, 0x2c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x3a, 0x59, 0x2c, 0x41, 0x64, 0x64, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x3a, 0x24, 0x2c, 0x49, 0x6e, 0x6a, 0x65, 0x63, 0x74, 0x43, 0x53, 0x53, 0x3a, 0x6e, 0x6e, 0x2c, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x4d, 0x65, 0x6e, 0x75, 0x3a, 0x74, 0x6e, 0x2c, 0x41, 0x64, 0x64, 0x49, 0x50, 0x43, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x3a, 0x66, 0x2c, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x61, 0x6c, 0x6c, 0x3a, 0x4e, 0x2c, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x3a, 0x64, 0x7d, 0x2c, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x3a, 0x75, 0x7d, 0x2c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x3d, 0x7b, 0x49, 0x73, 0x44, 0x61, 0x72, 0x6b, 0x4d, 0x6f, 0x64, 0x65, 0x3a, 0x65, 0x6e, 0x28, 0x22, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x3a, 0x69, 0x73, 0x64, 0x61, 0x72, 0x6b, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0x29, 0x2c, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x3a, 0x65, 0x6e, 0x28, 0x22, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x3a, 0x6c, 0x6f, 0x67, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x29, 0x2c, 0x41, 0x70, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x3a, 0x65, 0x6e, 0x28, 0x22, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x3a, 0x61, 0x70, 0x70, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x29, 0x7d, 0x2c, 0x6f, 0x6e, 0x28, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2c, 0x6c, 0x29, 0x2c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x61, 0x64, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x28, 0x22, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x64, 0x6f, 0x77, 0x6e, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x66, 0x6f, 0x72, 0x28, 0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x6e, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x3b, 0x6e, 0x75, 0x6c, 0x6c, 0x21, 0x3d, 0x74, 0x26, 0x26, 0x21, 0x74, 0x2e, 0x68, 0x61, 0x73, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x28, 0x22, 0x64, 0x61, 0x74, 0x61, 0x2d, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2d, 0x6e, 0x6f, 0x2d, 0x64, 0x72, 0x61, 0x67, 0x22, 0x29, 0x3b, 0x29, 0x7b, 0x69, 0x66, 0x28, 0x74, 0x2e, 0x68, 0x61, 0x73, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x28, 0x22, 0x64, 0x61, 0x74, 0x61, 0x2d, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2d, 0x64, 0x72, 0x61, 0x67, 0x22, 0x29, 0x29, 0x7b, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x28, 0x22, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2d, 0x64, 0x72, 0x61, 0x67, 0x22, 0x29, 0x3b, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x7d, 0x74, 0x3d, 0x74, 0x2e, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x7d, 0x7d, 0x29, 0x29, 0x2c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x61, 0x64, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x28, 0x22, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x6d, 0x65, 0x6e, 0x75, 0x22, 0x2c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x66, 0x6f, 0x72, 0x28, 0x76, 0x61, 0x72, 0x20, 0x74, 0x2c, 0x65, 0x3d, 0x6e, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x3b, 0x6e, 0x75, 0x6c, 0x6c, 0x21, 0x3d, 0x65, 0x26, 0x26, 0x6e, 0x75, 0x6c, 0x6c, 0x3d, 0x3d, 0x28, 0x74, 0x3d, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x5b, 0x22, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x6d, 0x65, 0x6e, 0x75, 0x2d, 0x69, 0x64, 0x22, 0x5d, 0x29, 0x3b, 0x29, 0x65, 0x3d, 0x65, 0x2e, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x3b, 0x69, 0x66, 0x28, 0x28, 0x6e, 0x75, 0x6c, 0x6c, 0x21, 0x3d, 0x74, 0x7c, 0x7c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x57, 0x61, 0x69, 0x6c, 0x73, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x4d, 0x65, 0x6e, 0x75, 0x29, 0x26, 0x26, 0x6e, 0x2e, 0x70, 0x72, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x28, 0x29, 0x2c, 0x6e, 0x75, 0x6c, 0x6c, 0x21, 0x3d, 0x74, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x72, 0x3d, 0x7b, 0x69, 0x64, 0x3a, 0x74, 0x2c, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x5b, 0x22, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x6d, 0x65, 0x6e, 0x75, 0x2d, 0x64, 0x61, 0x74, 0x61, 0x22, 0x5d, 0x7c, 0x7c, 0x22, 0x22, 0x7d, 0x3b, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x28, 0x22, 0x43, 0x22, 0x2b, 0x4a, 0x53, 0x4f, 0x4e, 0x2e, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x69, 0x66, 0x79, 0x28, 0x72, 0x29, 0x29, 0x7d, 0x7d, 0x29, 0x29, 0x2c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x26, 0x26, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x74, 0x72, 0x79, 0x7b, 0x6e, 0x3d, 0x4a, 0x53, 0x4f, 0x4e, 0x2e, 0x70, 0x61, 0x72, 0x73, 0x65, 0x28, 0x6e, 0x29, 0x7d, 0x63, 0x61, 0x74, 0x63, 0x68, 0x28, 0x6e, 0x29, 0x7b, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x6e, 0x29, 0x7d, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x3d, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x7c, 0x7c, 0x7b, 0x7d, 0x2c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x6e, 0x29, 0x2e, 0x66, 0x6f, 0x72, 0x45, 0x61, 0x63, 0x68, 0x28, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x74, 0x29, 0x7b, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5b, 0x74, 0x5d, 0x3d, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5b, 0x74, 0x5d, 0x7c, 0x7c, 0x7b, 0x7d, 0x2c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x6e, 0x5b, 0x74, 0x5d, 0x29, 0x2e, 0x66, 0x6f, 0x72, 0x45, 0x61, 0x63, 0x68, 0x28, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x65, 0x29, 0x7b, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5b, 0x74, 0x5d, 0x5b, 0x65, 0x5d, 0x3d, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5b, 0x74, 0x5d, 0x5b, 0x65, 0x5d, 0x7c, 0x7c, 0x7b, 0x7d, 0x2c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x6e, 0x5b, 0x74, 0x5d, 0x5b, 0x65, 0x5d, 0x29, 0x2e, 0x66, 0x6f, 0x72, 0x45, 0x61, 0x63, 0x68, 0x28, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5b, 0x74, 0x5d, 0x5b, 0x65, 0x5d, 0x5b, 0x6e, 0x5d, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x72, 0x3d, 0x30, 0x3b, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x28, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x69, 0x3d, 0x5b, 0x5d, 0x2e, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x29, 0x3b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x43, 0x28, 0x5b, 0x74, 0x2c, 0x65, 0x2c, 0x6e, 0x5d, 0x2e, 0x6a, 0x6f, 0x69, 0x6e, 0x28, 0x22, 0x2e, 0x22, 0x29, 0x2c, 0x69, 0x2c, 0x72, 0x29, 0x7d, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x69, 0x2e, 0x73, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x7b, 0x72, 0x3d, 0x6e, 0x7d, 0x2c, 0x69, 0x2e, 0x67, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x7d, 0x2c, 0x69, 0x7d, 0x28, 0x29, 0x7d, 0x29, 0x29, 0x7d, 0x29, 0x29, 0x7d, 0x29, 0x29, 0x7d, 0x28, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x2c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x6d, 0x69, 0x74, 0x28, 0x22, 0x77, 0x61, 0x69, 0x6c, 0x73, 0x3a, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x22, 0x29, 0x7d, 0x5d, 0x29, 0x3b, 0x00}; \ No newline at end of file diff --git a/v2/internal/ffenestri/traymenu_darwin.c b/v2/internal/ffenestri/traymenu_darwin.c new file mode 100644 index 000000000..1854d838d --- /dev/null +++ b/v2/internal/ffenestri/traymenu_darwin.c @@ -0,0 +1,266 @@ +// +// Created by Lea Anthony on 12/1/21. +// + +#include "common.h" +#include "traymenu_darwin.h" +#include "trayicons.h" + +extern Class trayMenuDelegateClass; + +// A cache for all our tray menu icons +// Global because it's a singleton +struct hashmap_s trayIconCache; + +TrayMenu* NewTrayMenu(const char* menuJSON) { + TrayMenu* result = malloc(sizeof(TrayMenu)); + +/* + {"ID":"0","Label":"Test Tray Label","Icon":"","ProcessedMenu":{"Menu":{"Items":[{"ID":"0","Label":"Show Window","Type":"Text","Disabled":false,"Hidden":false,"Checked":false,"Foreground":0,"Background":0},{"ID":"1","Label":"Hide Window","Type":"Text","Disabled":false,"Hidden":false,"Checked":false,"Foreground":0,"Background":0},{"ID":"2","Label":"Minimise Window","Type":"Text","Disabled":false,"Hidden":false,"Checked":false,"Foreground":0,"Background":0},{"ID":"3","Label":"Unminimise Window","Type":"Text","Disabled":false,"Hidden":false,"Checked":false,"Foreground":0,"Background":0}]},"RadioGroups":null}} +*/ + JsonNode* processedJSON = json_decode(menuJSON); + if( processedJSON == NULL ) { + ABORT("[NewTrayMenu] Unable to parse TrayMenu JSON: %s", menuJSON); + } + + // Save reference to this json + result->processedJSON = processedJSON; + + // TODO: Make this configurable + result->trayIconPosition = NSImageLeft; + + result->ID = mustJSONString(processedJSON, "ID"); + result->label = mustJSONString(processedJSON, "Label"); + result->icon = mustJSONString(processedJSON, "Image"); + result->fontName = getJSONString(processedJSON, "FontName"); + result->RGBA = getJSONString(processedJSON, "RGBA"); + getJSONBool(processedJSON, "MacTemplateImage", &result->templateImage); + result->fontSize = 0; + getJSONInt(processedJSON, "FontSize", &result->fontSize); + result->tooltip = NULL; + result->tooltip = getJSONString(processedJSON, "Tooltip"); + result->disabled = false; + getJSONBool(processedJSON, "Disabled", &result->disabled); + + result->styledLabel = getJSONObject(processedJSON, "StyledLabel"); + + // Create the menu + JsonNode* processedMenu = mustJSONObject(processedJSON, "ProcessedMenu"); + result->menu = NewMenu(processedMenu); + + result->delegate = NULL; + + // Init tray status bar item + result->statusbaritem = NULL; + + // Set the menu type and store the tray ID in the parent data + result->menu->menuType = TrayMenuType; + result->menu->parentData = (void*) result->ID; + + return result; +} + +void DumpTrayMenu(TrayMenu* trayMenu) { + printf(" ['%s':%p] = { label: '%s', icon: '%s', menu: %p, statusbar: %p }\n", trayMenu->ID, trayMenu, trayMenu->label, trayMenu->icon, trayMenu->menu, trayMenu->statusbaritem ); +} + + +void UpdateTrayLabel(TrayMenu *trayMenu, const char *label, const char *fontName, int fontSize, const char *RGBA, const char *tooltip, bool disabled, JsonNode *styledLabel) { + + // Exit early if NULL + if( trayMenu->label == NULL ) { + return; + } + // Update button label + id statusBarButton = msg_reg(trayMenu->statusbaritem, s("button")); + id attributedString = NULL; + if( styledLabel != NULL) { + attributedString = createAttributedStringFromStyledLabel(styledLabel, fontName, fontSize); + } else { + attributedString = createAttributedString(label, fontName, fontSize, RGBA); + } + + if( tooltip != NULL ) { + msg_id(statusBarButton, s("setToolTip:"), str(tooltip)); + } + + msg_bool(statusBarButton, s("setEnabled:"), !disabled); + + msg_id(statusBarButton, s("setAttributedTitle:"), attributedString); +} + +void UpdateTrayIcon(TrayMenu *trayMenu) { + + // Exit early if NULL + if( trayMenu->icon == NULL ) { + return; + } + + id statusBarButton = msg_reg(trayMenu->statusbaritem, s("button")); + + // Empty icon means remove it + if( STREMPTY(trayMenu->icon) ) { + // Remove image + msg_id(statusBarButton, s("setImage:"), NULL); + return; + } + + id trayImage = hashmap_get(&trayIconCache, trayMenu->icon, strlen(trayMenu->icon)); + + // If we don't have the image in the icon cache then assume it's base64 encoded image data + if (trayImage == NULL) { + trayImage = createImageFromBase64Data(trayMenu->icon, trayMenu->templateImage); + } + + msg_int(statusBarButton, s("setImagePosition:"), trayMenu->trayIconPosition); + msg_id(statusBarButton, s("setImage:"), trayImage); + +} + +void ShowTrayMenu(TrayMenu* trayMenu) { + + // Create a status bar item if we don't have one + if( trayMenu->statusbaritem == NULL ) { + id statusBar = msg_reg( c("NSStatusBar"), s("systemStatusBar") ); + trayMenu->statusbaritem = ((id(*)(id, SEL, CGFloat))objc_msgSend)(statusBar, s("statusItemWithLength:"), NSVariableStatusItemLength); + msg_reg(trayMenu->statusbaritem, s("retain")); + } + + id statusBarButton = msg_reg(trayMenu->statusbaritem, s("button")); + msg_uint(statusBarButton, s("setImagePosition:"), trayMenu->trayIconPosition); + // Update the icon if needed + UpdateTrayIcon(trayMenu); + + // Update the label if needed + UpdateTrayLabel(trayMenu, trayMenu->label, trayMenu->fontName, trayMenu->fontSize, trayMenu->RGBA, trayMenu->tooltip, trayMenu->disabled, trayMenu->styledLabel); + + // Update the menu + id menu = GetMenu(trayMenu->menu); + objc_setAssociatedObject(menu, "trayMenuID", str(trayMenu->ID), OBJC_ASSOCIATION_ASSIGN); + + // Create delegate + id trayMenuDelegate = msg_reg((id)trayMenuDelegateClass, s("new")); + msg_id(menu, s("setDelegate:"), trayMenuDelegate); + objc_setAssociatedObject(trayMenuDelegate, "menu", menu, OBJC_ASSOCIATION_ASSIGN); + + // Create menu delegate + trayMenu->delegate = trayMenuDelegate; + + msg_id(trayMenu->statusbaritem, s("setMenu:"), menu); +} + +// UpdateTrayMenuInPlace receives 2 menus. The current menu gets +// updated with the data from the new menu. +void UpdateTrayMenuInPlace(TrayMenu* currentMenu, TrayMenu* newMenu) { + + // Delete the old menu + DeleteMenu(currentMenu->menu); + if( currentMenu->delegate != NULL ) { + msg_reg(currentMenu->delegate, s("release")); + currentMenu->delegate = NULL; + } + + // Set the new one + currentMenu->menu = newMenu->menu; + + // Delete the old JSON + json_delete(currentMenu->processedJSON); + + // Set the new JSON + currentMenu->processedJSON = newMenu->processedJSON; + + // Copy the other data + currentMenu->ID = newMenu->ID; + currentMenu->label = newMenu->label; + currentMenu->styledLabel = newMenu->styledLabel; + currentMenu->trayIconPosition = newMenu->trayIconPosition; + currentMenu->icon = newMenu->icon; + +} + +void DeleteTrayMenu(TrayMenu* trayMenu) { + + // Delete the menu + DeleteMenu(trayMenu->menu); + if( trayMenu->delegate != NULL ) { + msg_reg(trayMenu->delegate, s("release")); + trayMenu->delegate = NULL; + } + + // Free JSON + if (trayMenu->processedJSON != NULL ) { + json_delete(trayMenu->processedJSON); + } + + // Free the status item + if ( trayMenu->statusbaritem != NULL ) { + id statusBar = msg_reg( c("NSStatusBar"), s("systemStatusBar") ); + msg_id(statusBar, s("removeStatusItem:"), trayMenu->statusbaritem); + msg_reg(trayMenu->statusbaritem, s("release")); + trayMenu->statusbaritem = NULL; + } + + // Free the tray menu memory + MEMFREE(trayMenu); +} +void DeleteTrayMenuKeepStatusBarItem(TrayMenu* trayMenu) { + + // Delete the menu + DeleteMenu(trayMenu->menu); + if( trayMenu->delegate != NULL ) { + msg_reg(trayMenu->delegate, s("release")); + trayMenu->delegate = NULL; + } + + // Free JSON + if (trayMenu->processedJSON != NULL ) { + json_delete(trayMenu->processedJSON); + } + + // Free the tray menu memory + MEMFREE(trayMenu); +} + +void LoadTrayIcons() { + + // Allocate the Tray Icons + if( 0 != hashmap_create((const unsigned)4, &trayIconCache)) { + // Couldn't allocate map + ABORT("Not enough memory to allocate trayIconCache!"); + } + + unsigned int count = 0; + while( 1 ) { + const unsigned char *name = trayIcons[count++]; + if( name == 0x00 ) { + break; + } + const unsigned char *lengthAsString = trayIcons[count++]; + if( name == 0x00 ) { + break; + } + const unsigned char *data = trayIcons[count++]; + if( data == 0x00 ) { + break; + } + int length = atoi((const char *)lengthAsString); + + // Create the icon and add to the hashmap + id imageData = ((id(*)(id, SEL, id, int))objc_msgSend)(c("NSData"), s("dataWithBytes:length:"), (id)data, length); + id trayImage = ALLOC("NSImage"); + msg_id(trayImage, s("initWithData:"), imageData); + hashmap_put(&trayIconCache, (const char *)name, strlen((const char *)name), trayImage); + } +} + +void UnloadTrayIcons() { + // Release the tray cache images + if( hashmap_num_entries(&trayIconCache) > 0 ) { + if (0!=hashmap_iterate_pairs(&trayIconCache, releaseNSObject, NULL)) { + ABORT("failed to release hashmap entries!"); + } + } + + //Free radio groups hashmap + hashmap_destroy(&trayIconCache); +} \ No newline at end of file diff --git a/v2/internal/ffenestri/traymenu_darwin.h b/v2/internal/ffenestri/traymenu_darwin.h new file mode 100644 index 000000000..763b4d63d --- /dev/null +++ b/v2/internal/ffenestri/traymenu_darwin.h @@ -0,0 +1,51 @@ +// +// Created by Lea Anthony on 12/1/21. +// + +#ifndef TRAYMENU_DARWIN_H +#define TRAYMENU_DARWIN_H + +#include "common.h" +#include "menu_darwin.h" + +typedef struct { + + const char *label; + const char *icon; + const char *ID; + const char *tooltip; + + bool templateImage; + const char *fontName; + int fontSize; + const char *RGBA; + + bool disabled; + + Menu* menu; + + id statusbaritem; + unsigned int trayIconPosition; + + JsonNode* processedJSON; + + JsonNode* styledLabel; + + id delegate; + +} TrayMenu; + +TrayMenu* NewTrayMenu(const char *trayJSON); +void DumpTrayMenu(TrayMenu* trayMenu); +void ShowTrayMenu(TrayMenu* trayMenu); +void UpdateTrayMenuInPlace(TrayMenu* currentMenu, TrayMenu* newMenu); +void UpdateTrayIcon(TrayMenu *trayMenu); +void UpdateTrayLabel(TrayMenu *trayMenu, const char *label, const char *fontName, int fontSize, const char *RGBA, const char *tooltip, bool disabled, JsonNode *styledLabel); + +void LoadTrayIcons(); +void UnloadTrayIcons(); + +void DeleteTrayMenu(TrayMenu* trayMenu); +void DeleteTrayMenuKeepStatusBarItem(TrayMenu* trayMenu); + +#endif //TRAYMENU_DARWIN_H diff --git a/v2/internal/ffenestri/traymenustore_darwin.c b/v2/internal/ffenestri/traymenustore_darwin.c new file mode 100644 index 000000000..362c07bf7 --- /dev/null +++ b/v2/internal/ffenestri/traymenustore_darwin.c @@ -0,0 +1,173 @@ +// +// Created by Lea Anthony on 12/1/21. +// + +#include "common.h" +#include "traymenustore_darwin.h" +#include "traymenu_darwin.h" +#include + +TrayMenuStore* NewTrayMenuStore() { + + TrayMenuStore* result = malloc(sizeof(TrayMenuStore)); + + // Allocate Tray Menu Store + if( 0 != hashmap_create((const unsigned)4, &result->trayMenuMap)) { + ABORT("[NewTrayMenuStore] Not enough memory to allocate trayMenuMap!"); + } + + if (pthread_mutex_init(&result->lock, NULL) != 0) { + printf("\n mutex init has failed\n"); + exit(1); + } + + return result; +} + +int dumpTrayMenu(void *const context, struct hashmap_element_s *const e) { + DumpTrayMenu(e->data); + return 0; +} + +void DumpTrayMenuStore(TrayMenuStore* store) { + pthread_mutex_lock(&store->lock); + hashmap_iterate_pairs(&store->trayMenuMap, dumpTrayMenu, NULL); + pthread_mutex_unlock(&store->lock); +} + +void AddTrayMenuToStore(TrayMenuStore* store, const char* menuJSON) { + + TrayMenu* newMenu = NewTrayMenu(menuJSON); + + pthread_mutex_lock(&store->lock); + //TODO: check if there is already an entry for this menu + hashmap_put(&store->trayMenuMap, newMenu->ID, strlen(newMenu->ID), newMenu); + pthread_mutex_unlock(&store->lock); +} + +int showTrayMenu(void *const context, struct hashmap_element_s *const e) { + ShowTrayMenu(e->data); + // 0 to retain element, -1 to delete. + return 0; +} + +void ShowTrayMenusInStore(TrayMenuStore* store) { + pthread_mutex_lock(&store->lock); + if( hashmap_num_entries(&store->trayMenuMap) > 0 ) { + hashmap_iterate_pairs(&store->trayMenuMap, showTrayMenu, NULL); + } + pthread_mutex_unlock(&store->lock); +} + +int freeTrayMenu(void *const context, struct hashmap_element_s *const e) { + DeleteTrayMenu(e->data); + return -1; +} + +void DeleteTrayMenuStore(TrayMenuStore *store) { + + // Delete context menus + if (hashmap_num_entries(&store->trayMenuMap) > 0) { + if (0 != hashmap_iterate_pairs(&store->trayMenuMap, freeTrayMenu, NULL)) { + ABORT("[DeleteContextMenuStore] Failed to release contextMenuStore entries!"); + } + } + + // Destroy tray menu map + hashmap_destroy(&store->trayMenuMap); + + pthread_mutex_destroy(&store->lock); +} + +TrayMenu* GetTrayMenuFromStore(TrayMenuStore* store, const char* menuID) { + // Get the current menu + pthread_mutex_lock(&store->lock); + TrayMenu* result = hashmap_get(&store->trayMenuMap, menuID, strlen(menuID)); + pthread_mutex_unlock(&store->lock); + return result; +} + +TrayMenu* MustGetTrayMenuFromStore(TrayMenuStore* store, const char* menuID) { + // Get the current menu + pthread_mutex_lock(&store->lock); + TrayMenu* result = hashmap_get(&store->trayMenuMap, menuID, strlen(menuID)); + pthread_mutex_unlock(&store->lock); + + if (result == NULL ) { + ABORT("Unable to find TrayMenu with ID '%s' in the TrayMenuStore!", menuID); + } + return result; +} + +void DeleteTrayMenuInStore(TrayMenuStore* store, const char* ID) { + + TrayMenu *menu = MustGetTrayMenuFromStore(store, ID); + pthread_mutex_lock(&store->lock); + hashmap_remove(&store->trayMenuMap, ID, strlen(ID)); + pthread_mutex_unlock(&store->lock); + DeleteTrayMenu(menu); +} + +void UpdateTrayMenuLabelInStore(TrayMenuStore* store, const char* JSON) { + // Parse the JSON + JsonNode *parsedUpdate = mustParseJSON(JSON); + + // Get the data out + const char* ID = mustJSONString(parsedUpdate, "ID"); + const char* Label = mustJSONString(parsedUpdate, "Label"); + + // Check we have this menu + TrayMenu *menu = MustGetTrayMenuFromStore(store, ID); + + const char *fontName = getJSONString(parsedUpdate, "FontName"); + const char *RGBA = getJSONString(parsedUpdate, "RGBA"); + int fontSize = 0; + getJSONInt(parsedUpdate, "FontSize", &fontSize); + const char *tooltip = getJSONString(parsedUpdate, "Tooltip"); + bool disabled = false; + getJSONBool(parsedUpdate, "Disabled", &disabled); + + JsonNode *styledLabel = getJSONObject(parsedUpdate, "StyledLabel"); + + UpdateTrayLabel(menu, Label, fontName, fontSize, RGBA, tooltip, disabled, styledLabel); + + json_delete(parsedUpdate); +} + +void UpdateTrayMenuInStore(TrayMenuStore* store, const char* menuJSON) { + TrayMenu* newMenu = NewTrayMenu(menuJSON); +// DumpTrayMenu(newMenu); + + // Get the current menu + TrayMenu *currentMenu = GetTrayMenuFromStore(store, newMenu->ID); + + // If we don't have a menu, we create one + if ( currentMenu == NULL ) { + // Store the new menu + pthread_mutex_lock(&store->lock); + hashmap_put(&store->trayMenuMap, newMenu->ID, strlen(newMenu->ID), newMenu); + pthread_mutex_unlock(&store->lock); + + // Show it + ShowTrayMenu(newMenu); + return; + } +// DumpTrayMenu(currentMenu); + + // Save the status bar reference + newMenu->statusbaritem = currentMenu->statusbaritem; + + pthread_mutex_lock(&store->lock); + hashmap_remove(&store->trayMenuMap, newMenu->ID, strlen(newMenu->ID)); + pthread_mutex_unlock(&store->lock); + + // Delete the current menu + DeleteTrayMenuKeepStatusBarItem(currentMenu); + + pthread_mutex_lock(&store->lock); + hashmap_put(&store->trayMenuMap, newMenu->ID, strlen(newMenu->ID), newMenu); + pthread_mutex_unlock(&store->lock); + + // Show the updated menu + ShowTrayMenu(newMenu); +} diff --git a/v2/internal/ffenestri/traymenustore_darwin.h b/v2/internal/ffenestri/traymenustore_darwin.h new file mode 100644 index 000000000..a09a9e004 --- /dev/null +++ b/v2/internal/ffenestri/traymenustore_darwin.h @@ -0,0 +1,36 @@ +// +// Created by Lea Anthony on 7/1/21. +// + +#ifndef TRAYMENUSTORE_DARWIN_H +#define TRAYMENUSTORE_DARWIN_H + +#include "traymenu_darwin.h" + +#include + +typedef struct { + + int dummy; + + // This is our tray menu map + // It maps tray IDs to TrayMenu* + struct hashmap_s trayMenuMap; + + pthread_mutex_t lock; + +} TrayMenuStore; + +TrayMenuStore* NewTrayMenuStore(); + +void AddTrayMenuToStore(TrayMenuStore* store, const char* menuJSON); +void UpdateTrayMenuInStore(TrayMenuStore* store, const char* menuJSON); +void ShowTrayMenusInStore(TrayMenuStore* store); +void DeleteTrayMenuStore(TrayMenuStore* store); + +TrayMenu* GetTrayMenuByID(TrayMenuStore* store, const char* menuID); + +void UpdateTrayMenuLabelInStore(TrayMenuStore* store, const char* JSON); +void DeleteTrayMenuInStore(TrayMenuStore* store, const char* id); + +#endif //TRAYMENUSTORE_DARWIN_H diff --git a/v2/internal/ffenestri/vec.c b/v2/internal/ffenestri/vec.c new file mode 100644 index 000000000..6ab8bfa96 --- /dev/null +++ b/v2/internal/ffenestri/vec.c @@ -0,0 +1,115 @@ +// +build !windows + +/** + * Copyright (c) 2014 rxi + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MIT license. See LICENSE for details. + */ + +#include "vec.h" + + +int vec_expand_(char **data, int *length, int *capacity, int memsz) { + if (*length + 1 > *capacity) { + void *ptr; + int n = (*capacity == 0) ? 1 : *capacity << 1; + ptr = realloc(*data, n * memsz); + if (ptr == NULL) return -1; + *data = ptr; + *capacity = n; + } + return 0; +} + + +int vec_reserve_(char **data, int *length, int *capacity, int memsz, int n) { + (void) length; + if (n > *capacity) { + void *ptr = realloc(*data, n * memsz); + if (ptr == NULL) return -1; + *data = ptr; + *capacity = n; + } + return 0; +} + + +int vec_reserve_po2_( + char **data, int *length, int *capacity, int memsz, int n +) { + int n2 = 1; + if (n == 0) return 0; + while (n2 < n) n2 <<= 1; + return vec_reserve_(data, length, capacity, memsz, n2); +} + + +int vec_compact_(char **data, int *length, int *capacity, int memsz) { + if (*length == 0) { + free(*data); + *data = NULL; + *capacity = 0; + return 0; + } else { + void *ptr; + int n = *length; + ptr = realloc(*data, n * memsz); + if (ptr == NULL) return -1; + *capacity = n; + *data = ptr; + } + return 0; +} + + +int vec_insert_(char **data, int *length, int *capacity, int memsz, + int idx +) { + int err = vec_expand_(data, length, capacity, memsz); + if (err) return err; + memmove(*data + (idx + 1) * memsz, + *data + idx * memsz, + (*length - idx) * memsz); + return 0; +} + + +void vec_splice_(char **data, int *length, int *capacity, int memsz, + int start, int count +) { + (void) capacity; + memmove(*data + start * memsz, + *data + (start + count) * memsz, + (*length - start - count) * memsz); +} + + +void vec_swapsplice_(char **data, int *length, int *capacity, int memsz, + int start, int count +) { + (void) capacity; + memmove(*data + start * memsz, + *data + (*length - count) * memsz, + count * memsz); +} + + +void vec_swap_(char **data, int *length, int *capacity, int memsz, + int idx1, int idx2 +) { + unsigned char *a, *b, tmp; + int count; + (void) length; + (void) capacity; + if (idx1 == idx2) return; + a = (unsigned char*) *data + idx1 * memsz; + b = (unsigned char*) *data + idx2 * memsz; + count = memsz; + while (count--) { + tmp = *a; + *a = *b; + *b = tmp; + a++, b++; + } +} diff --git a/v2/internal/ffenestri/vec.h b/v2/internal/ffenestri/vec.h new file mode 100644 index 000000000..19362c987 --- /dev/null +++ b/v2/internal/ffenestri/vec.h @@ -0,0 +1,181 @@ +/** + * Copyright (c) 2014 rxi + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef VEC_H +#define VEC_H + +#include +#include + +#define VEC_VERSION "0.2.1" + + +#define vec_unpack_(v)\ + (char**)&(v)->data, &(v)->length, &(v)->capacity, sizeof(*(v)->data) + + +#define vec_t(T)\ + struct { T *data; int length, capacity; } + + +#define vec_init(v)\ + memset((v), 0, sizeof(*(v))) + + +#define vec_deinit(v)\ + ( free((v)->data),\ + vec_init(v) ) + + +#define vec_push(v, val)\ + ( vec_expand_(vec_unpack_(v)) ? -1 :\ + ((v)->data[(v)->length++] = (val), 0), 0 ) + + +#define vec_pop(v)\ + (v)->data[--(v)->length] + + +#define vec_splice(v, start, count)\ + ( vec_splice_(vec_unpack_(v), start, count),\ + (v)->length -= (count) ) + + +#define vec_swapsplice(v, start, count)\ + ( vec_swapsplice_(vec_unpack_(v), start, count),\ + (v)->length -= (count) ) + + +#define vec_insert(v, idx, val)\ + ( vec_insert_(vec_unpack_(v), idx) ? -1 :\ + ((v)->data[idx] = (val), 0), (v)->length++, 0 ) + + +#define vec_sort(v, fn)\ + qsort((v)->data, (v)->length, sizeof(*(v)->data), fn) + + +#define vec_swap(v, idx1, idx2)\ + vec_swap_(vec_unpack_(v), idx1, idx2) + + +#define vec_truncate(v, len)\ + ((v)->length = (len) < (v)->length ? (len) : (v)->length) + + +#define vec_clear(v)\ + ((v)->length = 0) + + +#define vec_first(v)\ + (v)->data[0] + + +#define vec_last(v)\ + (v)->data[(v)->length - 1] + + +#define vec_reserve(v, n)\ + vec_reserve_(vec_unpack_(v), n) + + +#define vec_compact(v)\ + vec_compact_(vec_unpack_(v)) + + +#define vec_pusharr(v, arr, count)\ + do {\ + int i__, n__ = (count);\ + if (vec_reserve_po2_(vec_unpack_(v), (v)->length + n__) != 0) break;\ + for (i__ = 0; i__ < n__; i__++) {\ + (v)->data[(v)->length++] = (arr)[i__];\ + }\ + } while (0) + + +#define vec_extend(v, v2)\ + vec_pusharr((v), (v2)->data, (v2)->length) + + +#define vec_find(v, val, idx)\ + do {\ + for ((idx) = 0; (idx) < (v)->length; (idx)++) {\ + if ((v)->data[(idx)] == (val)) break;\ + }\ + if ((idx) == (v)->length) (idx) = -1;\ + } while (0) + + +#define vec_remove(v, val)\ + do {\ + int idx__;\ + vec_find(v, val, idx__);\ + if (idx__ != -1) vec_splice(v, idx__, 1);\ + } while (0) + + +#define vec_reverse(v)\ + do {\ + int i__ = (v)->length / 2;\ + while (i__--) {\ + vec_swap((v), i__, (v)->length - (i__ + 1));\ + }\ + } while (0) + + +#define vec_foreach(v, var, iter)\ + if ( (v)->length > 0 )\ + for ( (iter) = 0;\ + (iter) < (v)->length && (((var) = (v)->data[(iter)]), 1);\ + ++(iter)) + + +#define vec_foreach_rev(v, var, iter)\ + if ( (v)->length > 0 )\ + for ( (iter) = (v)->length - 1;\ + (iter) >= 0 && (((var) = (v)->data[(iter)]), 1);\ + --(iter)) + + +#define vec_foreach_ptr(v, var, iter)\ + if ( (v)->length > 0 )\ + for ( (iter) = 0;\ + (iter) < (v)->length && (((var) = &(v)->data[(iter)]), 1);\ + ++(iter)) + + +#define vec_foreach_ptr_rev(v, var, iter)\ + if ( (v)->length > 0 )\ + for ( (iter) = (v)->length - 1;\ + (iter) >= 0 && (((var) = &(v)->data[(iter)]), 1);\ + --(iter)) + + + +int vec_expand_(char **data, int *length, int *capacity, int memsz); +int vec_reserve_(char **data, int *length, int *capacity, int memsz, int n); +int vec_reserve_po2_(char **data, int *length, int *capacity, int memsz, + int n); +int vec_compact_(char **data, int *length, int *capacity, int memsz); +int vec_insert_(char **data, int *length, int *capacity, int memsz, + int idx); +void vec_splice_(char **data, int *length, int *capacity, int memsz, + int start, int count); +void vec_swapsplice_(char **data, int *length, int *capacity, int memsz, + int start, int count); +void vec_swap_(char **data, int *length, int *capacity, int memsz, + int idx1, int idx2); + + +typedef vec_t(void*) vec_void_t; +typedef vec_t(char*) vec_str_t; +typedef vec_t(int) vec_int_t; +typedef vec_t(char) vec_char_t; +typedef vec_t(float) vec_float_t; +typedef vec_t(double) vec_double_t; + +#endif \ No newline at end of file diff --git a/v2/internal/ffenestri/windows/EventToken.h b/v2/internal/ffenestri/windows/EventToken.h new file mode 100644 index 000000000..885405b6b --- /dev/null +++ b/v2/internal/ffenestri/windows/EventToken.h @@ -0,0 +1,68 @@ + + +/* this ALWAYS GENERATED file contains the definitions for the interfaces */ + + + /* File created by MIDL compiler version 8.01.0622 */ +/* @@MIDL_FILE_HEADING( ) */ + + + +/* verify that the version is high enough to compile this file*/ +#ifndef __REQUIRED_RPCNDR_H_VERSION__ +#define __REQUIRED_RPCNDR_H_VERSION__ 500 +#endif + +/* verify that the version is high enough to compile this file*/ +#ifndef __REQUIRED_RPCSAL_H_VERSION__ +#define __REQUIRED_RPCSAL_H_VERSION__ 100 +#endif + +#include "rpc.h" +#include "rpcndr.h" + +#ifndef __RPCNDR_H_VERSION__ +#error this stub requires an updated version of +#endif /* __RPCNDR_H_VERSION__ */ + + +#ifndef __eventtoken_h__ +#define __eventtoken_h__ + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +/* Forward Declarations */ + +#ifdef __cplusplus +extern "C"{ +#endif + + +/* interface __MIDL_itf_eventtoken_0000_0000 */ +/* [local] */ + +// Microsoft Windows +// Copyright (c) Microsoft Corporation. All rights reserved. +#pragma once +typedef struct EventRegistrationToken + { + __int64 value; + } EventRegistrationToken; + + + +extern RPC_IF_HANDLE __MIDL_itf_eventtoken_0000_0000_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_eventtoken_0000_0000_v0_0_s_ifspec; + +/* Additional Prototypes for ALL interfaces */ + +/* end of Additional Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/v2/internal/ffenestri/windows/WebView2.h b/v2/internal/ffenestri/windows/WebView2.h new file mode 100644 index 000000000..44cd67035 --- /dev/null +++ b/v2/internal/ffenestri/windows/WebView2.h @@ -0,0 +1,12693 @@ + + +/* this ALWAYS GENERATED file contains the definitions for the interfaces */ + + + /* File created by MIDL compiler version 8.xx.xxxx */ +/* at a redacted point in time + */ +/* Compiler settings for ../../edge_embedded_browser/client/win/current/webview2.idl: + Oicf, W1, Zp8, env=Win64 (32b run), target_arch=AMD64 8.xx.xxxx + protocol : dce , ms_ext, c_ext, robust + error checks: allocation ref bounds_check enum stub_data + VC __declspec() decoration level: + __declspec(uuid()), __declspec(selectany), __declspec(novtable) + DECLSPEC_UUID(), MIDL_INTERFACE() +*/ +/* @@MIDL_FILE_HEADING( ) */ + +#pragma warning( disable: 4049 ) /* more than 64k source lines */ + + +/* verify that the version is high enough to compile this file*/ +#ifndef __REQUIRED_RPCNDR_H_VERSION__ +#define __REQUIRED_RPCNDR_H_VERSION__ 475 +#endif + +#include "rpc.h" +#include "rpcndr.h" + +#ifndef __RPCNDR_H_VERSION__ +#error this stub requires an updated version of +#endif /* __RPCNDR_H_VERSION__ */ + + +#ifndef __webview2_h__ +#define __webview2_h__ + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +/* Forward Declarations */ + +#ifndef __ICoreWebView2AcceleratorKeyPressedEventArgs_FWD_DEFINED__ +#define __ICoreWebView2AcceleratorKeyPressedEventArgs_FWD_DEFINED__ +typedef interface ICoreWebView2AcceleratorKeyPressedEventArgs ICoreWebView2AcceleratorKeyPressedEventArgs; + +#endif /* __ICoreWebView2AcceleratorKeyPressedEventArgs_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2AcceleratorKeyPressedEventHandler_FWD_DEFINED__ +#define __ICoreWebView2AcceleratorKeyPressedEventHandler_FWD_DEFINED__ +typedef interface ICoreWebView2AcceleratorKeyPressedEventHandler ICoreWebView2AcceleratorKeyPressedEventHandler; + +#endif /* __ICoreWebView2AcceleratorKeyPressedEventHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2AddScriptToExecuteOnDocumentCreatedCompletedHandler_FWD_DEFINED__ +#define __ICoreWebView2AddScriptToExecuteOnDocumentCreatedCompletedHandler_FWD_DEFINED__ +typedef interface ICoreWebView2AddScriptToExecuteOnDocumentCreatedCompletedHandler ICoreWebView2AddScriptToExecuteOnDocumentCreatedCompletedHandler; + +#endif /* __ICoreWebView2AddScriptToExecuteOnDocumentCreatedCompletedHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2CallDevToolsProtocolMethodCompletedHandler_FWD_DEFINED__ +#define __ICoreWebView2CallDevToolsProtocolMethodCompletedHandler_FWD_DEFINED__ +typedef interface ICoreWebView2CallDevToolsProtocolMethodCompletedHandler ICoreWebView2CallDevToolsProtocolMethodCompletedHandler; + +#endif /* __ICoreWebView2CallDevToolsProtocolMethodCompletedHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2CapturePreviewCompletedHandler_FWD_DEFINED__ +#define __ICoreWebView2CapturePreviewCompletedHandler_FWD_DEFINED__ +typedef interface ICoreWebView2CapturePreviewCompletedHandler ICoreWebView2CapturePreviewCompletedHandler; + +#endif /* __ICoreWebView2CapturePreviewCompletedHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2_FWD_DEFINED__ +#define __ICoreWebView2_FWD_DEFINED__ +typedef interface ICoreWebView2 ICoreWebView2; + +#endif /* __ICoreWebView2_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2_2_FWD_DEFINED__ +#define __ICoreWebView2_2_FWD_DEFINED__ +typedef interface ICoreWebView2_2 ICoreWebView2_2; + +#endif /* __ICoreWebView2_2_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2_3_FWD_DEFINED__ +#define __ICoreWebView2_3_FWD_DEFINED__ +typedef interface ICoreWebView2_3 ICoreWebView2_3; + +#endif /* __ICoreWebView2_3_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2CompositionController_FWD_DEFINED__ +#define __ICoreWebView2CompositionController_FWD_DEFINED__ +typedef interface ICoreWebView2CompositionController ICoreWebView2CompositionController; + +#endif /* __ICoreWebView2CompositionController_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2CompositionController2_FWD_DEFINED__ +#define __ICoreWebView2CompositionController2_FWD_DEFINED__ +typedef interface ICoreWebView2CompositionController2 ICoreWebView2CompositionController2; + +#endif /* __ICoreWebView2CompositionController2_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2Controller_FWD_DEFINED__ +#define __ICoreWebView2Controller_FWD_DEFINED__ +typedef interface ICoreWebView2Controller ICoreWebView2Controller; + +#endif /* __ICoreWebView2Controller_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2Controller2_FWD_DEFINED__ +#define __ICoreWebView2Controller2_FWD_DEFINED__ +typedef interface ICoreWebView2Controller2 ICoreWebView2Controller2; + +#endif /* __ICoreWebView2Controller2_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2Controller3_FWD_DEFINED__ +#define __ICoreWebView2Controller3_FWD_DEFINED__ +typedef interface ICoreWebView2Controller3 ICoreWebView2Controller3; + +#endif /* __ICoreWebView2Controller3_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2ContentLoadingEventArgs_FWD_DEFINED__ +#define __ICoreWebView2ContentLoadingEventArgs_FWD_DEFINED__ +typedef interface ICoreWebView2ContentLoadingEventArgs ICoreWebView2ContentLoadingEventArgs; + +#endif /* __ICoreWebView2ContentLoadingEventArgs_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2ContentLoadingEventHandler_FWD_DEFINED__ +#define __ICoreWebView2ContentLoadingEventHandler_FWD_DEFINED__ +typedef interface ICoreWebView2ContentLoadingEventHandler ICoreWebView2ContentLoadingEventHandler; + +#endif /* __ICoreWebView2ContentLoadingEventHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2Cookie_FWD_DEFINED__ +#define __ICoreWebView2Cookie_FWD_DEFINED__ +typedef interface ICoreWebView2Cookie ICoreWebView2Cookie; + +#endif /* __ICoreWebView2Cookie_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2CookieList_FWD_DEFINED__ +#define __ICoreWebView2CookieList_FWD_DEFINED__ +typedef interface ICoreWebView2CookieList ICoreWebView2CookieList; + +#endif /* __ICoreWebView2CookieList_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2CookieManager_FWD_DEFINED__ +#define __ICoreWebView2CookieManager_FWD_DEFINED__ +typedef interface ICoreWebView2CookieManager ICoreWebView2CookieManager; + +#endif /* __ICoreWebView2CookieManager_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2CreateCoreWebView2CompositionControllerCompletedHandler_FWD_DEFINED__ +#define __ICoreWebView2CreateCoreWebView2CompositionControllerCompletedHandler_FWD_DEFINED__ +typedef interface ICoreWebView2CreateCoreWebView2CompositionControllerCompletedHandler ICoreWebView2CreateCoreWebView2CompositionControllerCompletedHandler; + +#endif /* __ICoreWebView2CreateCoreWebView2CompositionControllerCompletedHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2CreateCoreWebView2ControllerCompletedHandler_FWD_DEFINED__ +#define __ICoreWebView2CreateCoreWebView2ControllerCompletedHandler_FWD_DEFINED__ +typedef interface ICoreWebView2CreateCoreWebView2ControllerCompletedHandler ICoreWebView2CreateCoreWebView2ControllerCompletedHandler; + +#endif /* __ICoreWebView2CreateCoreWebView2ControllerCompletedHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler_FWD_DEFINED__ +#define __ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler_FWD_DEFINED__ +typedef interface ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler; + +#endif /* __ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2ContainsFullScreenElementChangedEventHandler_FWD_DEFINED__ +#define __ICoreWebView2ContainsFullScreenElementChangedEventHandler_FWD_DEFINED__ +typedef interface ICoreWebView2ContainsFullScreenElementChangedEventHandler ICoreWebView2ContainsFullScreenElementChangedEventHandler; + +#endif /* __ICoreWebView2ContainsFullScreenElementChangedEventHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2CursorChangedEventHandler_FWD_DEFINED__ +#define __ICoreWebView2CursorChangedEventHandler_FWD_DEFINED__ +typedef interface ICoreWebView2CursorChangedEventHandler ICoreWebView2CursorChangedEventHandler; + +#endif /* __ICoreWebView2CursorChangedEventHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2DocumentTitleChangedEventHandler_FWD_DEFINED__ +#define __ICoreWebView2DocumentTitleChangedEventHandler_FWD_DEFINED__ +typedef interface ICoreWebView2DocumentTitleChangedEventHandler ICoreWebView2DocumentTitleChangedEventHandler; + +#endif /* __ICoreWebView2DocumentTitleChangedEventHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2DOMContentLoadedEventArgs_FWD_DEFINED__ +#define __ICoreWebView2DOMContentLoadedEventArgs_FWD_DEFINED__ +typedef interface ICoreWebView2DOMContentLoadedEventArgs ICoreWebView2DOMContentLoadedEventArgs; + +#endif /* __ICoreWebView2DOMContentLoadedEventArgs_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2DOMContentLoadedEventHandler_FWD_DEFINED__ +#define __ICoreWebView2DOMContentLoadedEventHandler_FWD_DEFINED__ +typedef interface ICoreWebView2DOMContentLoadedEventHandler ICoreWebView2DOMContentLoadedEventHandler; + +#endif /* __ICoreWebView2DOMContentLoadedEventHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2Deferral_FWD_DEFINED__ +#define __ICoreWebView2Deferral_FWD_DEFINED__ +typedef interface ICoreWebView2Deferral ICoreWebView2Deferral; + +#endif /* __ICoreWebView2Deferral_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2DevToolsProtocolEventReceivedEventArgs_FWD_DEFINED__ +#define __ICoreWebView2DevToolsProtocolEventReceivedEventArgs_FWD_DEFINED__ +typedef interface ICoreWebView2DevToolsProtocolEventReceivedEventArgs ICoreWebView2DevToolsProtocolEventReceivedEventArgs; + +#endif /* __ICoreWebView2DevToolsProtocolEventReceivedEventArgs_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2DevToolsProtocolEventReceivedEventHandler_FWD_DEFINED__ +#define __ICoreWebView2DevToolsProtocolEventReceivedEventHandler_FWD_DEFINED__ +typedef interface ICoreWebView2DevToolsProtocolEventReceivedEventHandler ICoreWebView2DevToolsProtocolEventReceivedEventHandler; + +#endif /* __ICoreWebView2DevToolsProtocolEventReceivedEventHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2DevToolsProtocolEventReceiver_FWD_DEFINED__ +#define __ICoreWebView2DevToolsProtocolEventReceiver_FWD_DEFINED__ +typedef interface ICoreWebView2DevToolsProtocolEventReceiver ICoreWebView2DevToolsProtocolEventReceiver; + +#endif /* __ICoreWebView2DevToolsProtocolEventReceiver_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2Environment_FWD_DEFINED__ +#define __ICoreWebView2Environment_FWD_DEFINED__ +typedef interface ICoreWebView2Environment ICoreWebView2Environment; + +#endif /* __ICoreWebView2Environment_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2Environment2_FWD_DEFINED__ +#define __ICoreWebView2Environment2_FWD_DEFINED__ +typedef interface ICoreWebView2Environment2 ICoreWebView2Environment2; + +#endif /* __ICoreWebView2Environment2_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2Environment3_FWD_DEFINED__ +#define __ICoreWebView2Environment3_FWD_DEFINED__ +typedef interface ICoreWebView2Environment3 ICoreWebView2Environment3; + +#endif /* __ICoreWebView2Environment3_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2Environment4_FWD_DEFINED__ +#define __ICoreWebView2Environment4_FWD_DEFINED__ +typedef interface ICoreWebView2Environment4 ICoreWebView2Environment4; + +#endif /* __ICoreWebView2Environment4_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2EnvironmentOptions_FWD_DEFINED__ +#define __ICoreWebView2EnvironmentOptions_FWD_DEFINED__ +typedef interface ICoreWebView2EnvironmentOptions ICoreWebView2EnvironmentOptions; + +#endif /* __ICoreWebView2EnvironmentOptions_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2ExecuteScriptCompletedHandler_FWD_DEFINED__ +#define __ICoreWebView2ExecuteScriptCompletedHandler_FWD_DEFINED__ +typedef interface ICoreWebView2ExecuteScriptCompletedHandler ICoreWebView2ExecuteScriptCompletedHandler; + +#endif /* __ICoreWebView2ExecuteScriptCompletedHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2FrameInfo_FWD_DEFINED__ +#define __ICoreWebView2FrameInfo_FWD_DEFINED__ +typedef interface ICoreWebView2FrameInfo ICoreWebView2FrameInfo; + +#endif /* __ICoreWebView2FrameInfo_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2FrameInfoCollection_FWD_DEFINED__ +#define __ICoreWebView2FrameInfoCollection_FWD_DEFINED__ +typedef interface ICoreWebView2FrameInfoCollection ICoreWebView2FrameInfoCollection; + +#endif /* __ICoreWebView2FrameInfoCollection_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2FrameInfoCollectionIterator_FWD_DEFINED__ +#define __ICoreWebView2FrameInfoCollectionIterator_FWD_DEFINED__ +typedef interface ICoreWebView2FrameInfoCollectionIterator ICoreWebView2FrameInfoCollectionIterator; + +#endif /* __ICoreWebView2FrameInfoCollectionIterator_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2FocusChangedEventHandler_FWD_DEFINED__ +#define __ICoreWebView2FocusChangedEventHandler_FWD_DEFINED__ +typedef interface ICoreWebView2FocusChangedEventHandler ICoreWebView2FocusChangedEventHandler; + +#endif /* __ICoreWebView2FocusChangedEventHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2GetCookiesCompletedHandler_FWD_DEFINED__ +#define __ICoreWebView2GetCookiesCompletedHandler_FWD_DEFINED__ +typedef interface ICoreWebView2GetCookiesCompletedHandler ICoreWebView2GetCookiesCompletedHandler; + +#endif /* __ICoreWebView2GetCookiesCompletedHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2HistoryChangedEventHandler_FWD_DEFINED__ +#define __ICoreWebView2HistoryChangedEventHandler_FWD_DEFINED__ +typedef interface ICoreWebView2HistoryChangedEventHandler ICoreWebView2HistoryChangedEventHandler; + +#endif /* __ICoreWebView2HistoryChangedEventHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2HttpHeadersCollectionIterator_FWD_DEFINED__ +#define __ICoreWebView2HttpHeadersCollectionIterator_FWD_DEFINED__ +typedef interface ICoreWebView2HttpHeadersCollectionIterator ICoreWebView2HttpHeadersCollectionIterator; + +#endif /* __ICoreWebView2HttpHeadersCollectionIterator_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2HttpRequestHeaders_FWD_DEFINED__ +#define __ICoreWebView2HttpRequestHeaders_FWD_DEFINED__ +typedef interface ICoreWebView2HttpRequestHeaders ICoreWebView2HttpRequestHeaders; + +#endif /* __ICoreWebView2HttpRequestHeaders_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2HttpResponseHeaders_FWD_DEFINED__ +#define __ICoreWebView2HttpResponseHeaders_FWD_DEFINED__ +typedef interface ICoreWebView2HttpResponseHeaders ICoreWebView2HttpResponseHeaders; + +#endif /* __ICoreWebView2HttpResponseHeaders_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2Interop_FWD_DEFINED__ +#define __ICoreWebView2Interop_FWD_DEFINED__ +typedef interface ICoreWebView2Interop ICoreWebView2Interop; + +#endif /* __ICoreWebView2Interop_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2MoveFocusRequestedEventArgs_FWD_DEFINED__ +#define __ICoreWebView2MoveFocusRequestedEventArgs_FWD_DEFINED__ +typedef interface ICoreWebView2MoveFocusRequestedEventArgs ICoreWebView2MoveFocusRequestedEventArgs; + +#endif /* __ICoreWebView2MoveFocusRequestedEventArgs_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2MoveFocusRequestedEventHandler_FWD_DEFINED__ +#define __ICoreWebView2MoveFocusRequestedEventHandler_FWD_DEFINED__ +typedef interface ICoreWebView2MoveFocusRequestedEventHandler ICoreWebView2MoveFocusRequestedEventHandler; + +#endif /* __ICoreWebView2MoveFocusRequestedEventHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2NavigationCompletedEventArgs_FWD_DEFINED__ +#define __ICoreWebView2NavigationCompletedEventArgs_FWD_DEFINED__ +typedef interface ICoreWebView2NavigationCompletedEventArgs ICoreWebView2NavigationCompletedEventArgs; + +#endif /* __ICoreWebView2NavigationCompletedEventArgs_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2NavigationCompletedEventHandler_FWD_DEFINED__ +#define __ICoreWebView2NavigationCompletedEventHandler_FWD_DEFINED__ +typedef interface ICoreWebView2NavigationCompletedEventHandler ICoreWebView2NavigationCompletedEventHandler; + +#endif /* __ICoreWebView2NavigationCompletedEventHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2NavigationStartingEventArgs_FWD_DEFINED__ +#define __ICoreWebView2NavigationStartingEventArgs_FWD_DEFINED__ +typedef interface ICoreWebView2NavigationStartingEventArgs ICoreWebView2NavigationStartingEventArgs; + +#endif /* __ICoreWebView2NavigationStartingEventArgs_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2NavigationStartingEventHandler_FWD_DEFINED__ +#define __ICoreWebView2NavigationStartingEventHandler_FWD_DEFINED__ +typedef interface ICoreWebView2NavigationStartingEventHandler ICoreWebView2NavigationStartingEventHandler; + +#endif /* __ICoreWebView2NavigationStartingEventHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2NewBrowserVersionAvailableEventHandler_FWD_DEFINED__ +#define __ICoreWebView2NewBrowserVersionAvailableEventHandler_FWD_DEFINED__ +typedef interface ICoreWebView2NewBrowserVersionAvailableEventHandler ICoreWebView2NewBrowserVersionAvailableEventHandler; + +#endif /* __ICoreWebView2NewBrowserVersionAvailableEventHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2NewWindowRequestedEventArgs_FWD_DEFINED__ +#define __ICoreWebView2NewWindowRequestedEventArgs_FWD_DEFINED__ +typedef interface ICoreWebView2NewWindowRequestedEventArgs ICoreWebView2NewWindowRequestedEventArgs; + +#endif /* __ICoreWebView2NewWindowRequestedEventArgs_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2NewWindowRequestedEventHandler_FWD_DEFINED__ +#define __ICoreWebView2NewWindowRequestedEventHandler_FWD_DEFINED__ +typedef interface ICoreWebView2NewWindowRequestedEventHandler ICoreWebView2NewWindowRequestedEventHandler; + +#endif /* __ICoreWebView2NewWindowRequestedEventHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2PermissionRequestedEventArgs_FWD_DEFINED__ +#define __ICoreWebView2PermissionRequestedEventArgs_FWD_DEFINED__ +typedef interface ICoreWebView2PermissionRequestedEventArgs ICoreWebView2PermissionRequestedEventArgs; + +#endif /* __ICoreWebView2PermissionRequestedEventArgs_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2PermissionRequestedEventHandler_FWD_DEFINED__ +#define __ICoreWebView2PermissionRequestedEventHandler_FWD_DEFINED__ +typedef interface ICoreWebView2PermissionRequestedEventHandler ICoreWebView2PermissionRequestedEventHandler; + +#endif /* __ICoreWebView2PermissionRequestedEventHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2PointerInfo_FWD_DEFINED__ +#define __ICoreWebView2PointerInfo_FWD_DEFINED__ +typedef interface ICoreWebView2PointerInfo ICoreWebView2PointerInfo; + +#endif /* __ICoreWebView2PointerInfo_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2ProcessFailedEventArgs_FWD_DEFINED__ +#define __ICoreWebView2ProcessFailedEventArgs_FWD_DEFINED__ +typedef interface ICoreWebView2ProcessFailedEventArgs ICoreWebView2ProcessFailedEventArgs; + +#endif /* __ICoreWebView2ProcessFailedEventArgs_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2ProcessFailedEventArgs2_FWD_DEFINED__ +#define __ICoreWebView2ProcessFailedEventArgs2_FWD_DEFINED__ +typedef interface ICoreWebView2ProcessFailedEventArgs2 ICoreWebView2ProcessFailedEventArgs2; + +#endif /* __ICoreWebView2ProcessFailedEventArgs2_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2ProcessFailedEventHandler_FWD_DEFINED__ +#define __ICoreWebView2ProcessFailedEventHandler_FWD_DEFINED__ +typedef interface ICoreWebView2ProcessFailedEventHandler ICoreWebView2ProcessFailedEventHandler; + +#endif /* __ICoreWebView2ProcessFailedEventHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2RasterizationScaleChangedEventHandler_FWD_DEFINED__ +#define __ICoreWebView2RasterizationScaleChangedEventHandler_FWD_DEFINED__ +typedef interface ICoreWebView2RasterizationScaleChangedEventHandler ICoreWebView2RasterizationScaleChangedEventHandler; + +#endif /* __ICoreWebView2RasterizationScaleChangedEventHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2ScriptDialogOpeningEventArgs_FWD_DEFINED__ +#define __ICoreWebView2ScriptDialogOpeningEventArgs_FWD_DEFINED__ +typedef interface ICoreWebView2ScriptDialogOpeningEventArgs ICoreWebView2ScriptDialogOpeningEventArgs; + +#endif /* __ICoreWebView2ScriptDialogOpeningEventArgs_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2ScriptDialogOpeningEventHandler_FWD_DEFINED__ +#define __ICoreWebView2ScriptDialogOpeningEventHandler_FWD_DEFINED__ +typedef interface ICoreWebView2ScriptDialogOpeningEventHandler ICoreWebView2ScriptDialogOpeningEventHandler; + +#endif /* __ICoreWebView2ScriptDialogOpeningEventHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2Settings_FWD_DEFINED__ +#define __ICoreWebView2Settings_FWD_DEFINED__ +typedef interface ICoreWebView2Settings ICoreWebView2Settings; + +#endif /* __ICoreWebView2Settings_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2Settings2_FWD_DEFINED__ +#define __ICoreWebView2Settings2_FWD_DEFINED__ +typedef interface ICoreWebView2Settings2 ICoreWebView2Settings2; + +#endif /* __ICoreWebView2Settings2_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2Settings3_FWD_DEFINED__ +#define __ICoreWebView2Settings3_FWD_DEFINED__ +typedef interface ICoreWebView2Settings3 ICoreWebView2Settings3; + +#endif /* __ICoreWebView2Settings3_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2SourceChangedEventArgs_FWD_DEFINED__ +#define __ICoreWebView2SourceChangedEventArgs_FWD_DEFINED__ +typedef interface ICoreWebView2SourceChangedEventArgs ICoreWebView2SourceChangedEventArgs; + +#endif /* __ICoreWebView2SourceChangedEventArgs_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2SourceChangedEventHandler_FWD_DEFINED__ +#define __ICoreWebView2SourceChangedEventHandler_FWD_DEFINED__ +typedef interface ICoreWebView2SourceChangedEventHandler ICoreWebView2SourceChangedEventHandler; + +#endif /* __ICoreWebView2SourceChangedEventHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2TrySuspendCompletedHandler_FWD_DEFINED__ +#define __ICoreWebView2TrySuspendCompletedHandler_FWD_DEFINED__ +typedef interface ICoreWebView2TrySuspendCompletedHandler ICoreWebView2TrySuspendCompletedHandler; + +#endif /* __ICoreWebView2TrySuspendCompletedHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2WebMessageReceivedEventArgs_FWD_DEFINED__ +#define __ICoreWebView2WebMessageReceivedEventArgs_FWD_DEFINED__ +typedef interface ICoreWebView2WebMessageReceivedEventArgs ICoreWebView2WebMessageReceivedEventArgs; + +#endif /* __ICoreWebView2WebMessageReceivedEventArgs_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2WebMessageReceivedEventHandler_FWD_DEFINED__ +#define __ICoreWebView2WebMessageReceivedEventHandler_FWD_DEFINED__ +typedef interface ICoreWebView2WebMessageReceivedEventHandler ICoreWebView2WebMessageReceivedEventHandler; + +#endif /* __ICoreWebView2WebMessageReceivedEventHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2WebResourceRequest_FWD_DEFINED__ +#define __ICoreWebView2WebResourceRequest_FWD_DEFINED__ +typedef interface ICoreWebView2WebResourceRequest ICoreWebView2WebResourceRequest; + +#endif /* __ICoreWebView2WebResourceRequest_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2WebResourceRequestedEventArgs_FWD_DEFINED__ +#define __ICoreWebView2WebResourceRequestedEventArgs_FWD_DEFINED__ +typedef interface ICoreWebView2WebResourceRequestedEventArgs ICoreWebView2WebResourceRequestedEventArgs; + +#endif /* __ICoreWebView2WebResourceRequestedEventArgs_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2WebResourceRequestedEventHandler_FWD_DEFINED__ +#define __ICoreWebView2WebResourceRequestedEventHandler_FWD_DEFINED__ +typedef interface ICoreWebView2WebResourceRequestedEventHandler ICoreWebView2WebResourceRequestedEventHandler; + +#endif /* __ICoreWebView2WebResourceRequestedEventHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2WebResourceResponse_FWD_DEFINED__ +#define __ICoreWebView2WebResourceResponse_FWD_DEFINED__ +typedef interface ICoreWebView2WebResourceResponse ICoreWebView2WebResourceResponse; + +#endif /* __ICoreWebView2WebResourceResponse_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2WebResourceResponseReceivedEventHandler_FWD_DEFINED__ +#define __ICoreWebView2WebResourceResponseReceivedEventHandler_FWD_DEFINED__ +typedef interface ICoreWebView2WebResourceResponseReceivedEventHandler ICoreWebView2WebResourceResponseReceivedEventHandler; + +#endif /* __ICoreWebView2WebResourceResponseReceivedEventHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2WebResourceResponseReceivedEventArgs_FWD_DEFINED__ +#define __ICoreWebView2WebResourceResponseReceivedEventArgs_FWD_DEFINED__ +typedef interface ICoreWebView2WebResourceResponseReceivedEventArgs ICoreWebView2WebResourceResponseReceivedEventArgs; + +#endif /* __ICoreWebView2WebResourceResponseReceivedEventArgs_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2WebResourceResponseView_FWD_DEFINED__ +#define __ICoreWebView2WebResourceResponseView_FWD_DEFINED__ +typedef interface ICoreWebView2WebResourceResponseView ICoreWebView2WebResourceResponseView; + +#endif /* __ICoreWebView2WebResourceResponseView_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2WebResourceResponseViewGetContentCompletedHandler_FWD_DEFINED__ +#define __ICoreWebView2WebResourceResponseViewGetContentCompletedHandler_FWD_DEFINED__ +typedef interface ICoreWebView2WebResourceResponseViewGetContentCompletedHandler ICoreWebView2WebResourceResponseViewGetContentCompletedHandler; + +#endif /* __ICoreWebView2WebResourceResponseViewGetContentCompletedHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2WindowCloseRequestedEventHandler_FWD_DEFINED__ +#define __ICoreWebView2WindowCloseRequestedEventHandler_FWD_DEFINED__ +typedef interface ICoreWebView2WindowCloseRequestedEventHandler ICoreWebView2WindowCloseRequestedEventHandler; + +#endif /* __ICoreWebView2WindowCloseRequestedEventHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2WindowFeatures_FWD_DEFINED__ +#define __ICoreWebView2WindowFeatures_FWD_DEFINED__ +typedef interface ICoreWebView2WindowFeatures ICoreWebView2WindowFeatures; + +#endif /* __ICoreWebView2WindowFeatures_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2ZoomFactorChangedEventHandler_FWD_DEFINED__ +#define __ICoreWebView2ZoomFactorChangedEventHandler_FWD_DEFINED__ +typedef interface ICoreWebView2ZoomFactorChangedEventHandler ICoreWebView2ZoomFactorChangedEventHandler; + +#endif /* __ICoreWebView2ZoomFactorChangedEventHandler_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2CompositionControllerInterop_FWD_DEFINED__ +#define __ICoreWebView2CompositionControllerInterop_FWD_DEFINED__ +typedef interface ICoreWebView2CompositionControllerInterop ICoreWebView2CompositionControllerInterop; + +#endif /* __ICoreWebView2CompositionControllerInterop_FWD_DEFINED__ */ + + +#ifndef __ICoreWebView2EnvironmentInterop_FWD_DEFINED__ +#define __ICoreWebView2EnvironmentInterop_FWD_DEFINED__ +typedef interface ICoreWebView2EnvironmentInterop ICoreWebView2EnvironmentInterop; + +#endif /* __ICoreWebView2EnvironmentInterop_FWD_DEFINED__ */ + + +/* header files for imported files */ +#include "objidl.h" +#include "oaidl.h" +#include "EventToken.h" + +#ifdef __cplusplus +extern "C"{ +#endif + + + +#ifndef __WebView2_LIBRARY_DEFINED__ +#define __WebView2_LIBRARY_DEFINED__ + +/* library WebView2 */ +/* [version][uuid] */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef /* [v1_enum] */ +enum COREWEBVIEW2_CAPTURE_PREVIEW_IMAGE_FORMAT + { + COREWEBVIEW2_CAPTURE_PREVIEW_IMAGE_FORMAT_PNG = 0, + COREWEBVIEW2_CAPTURE_PREVIEW_IMAGE_FORMAT_JPEG = ( COREWEBVIEW2_CAPTURE_PREVIEW_IMAGE_FORMAT_PNG + 1 ) + } COREWEBVIEW2_CAPTURE_PREVIEW_IMAGE_FORMAT; + +typedef /* [v1_enum] */ +enum COREWEBVIEW2_COOKIE_SAME_SITE_KIND + { + COREWEBVIEW2_COOKIE_SAME_SITE_KIND_NONE = 0, + COREWEBVIEW2_COOKIE_SAME_SITE_KIND_LAX = ( COREWEBVIEW2_COOKIE_SAME_SITE_KIND_NONE + 1 ) , + COREWEBVIEW2_COOKIE_SAME_SITE_KIND_STRICT = ( COREWEBVIEW2_COOKIE_SAME_SITE_KIND_LAX + 1 ) + } COREWEBVIEW2_COOKIE_SAME_SITE_KIND; + +typedef /* [v1_enum] */ +enum COREWEBVIEW2_HOST_RESOURCE_ACCESS_KIND + { + COREWEBVIEW2_HOST_RESOURCE_ACCESS_KIND_DENY = 0, + COREWEBVIEW2_HOST_RESOURCE_ACCESS_KIND_ALLOW = ( COREWEBVIEW2_HOST_RESOURCE_ACCESS_KIND_DENY + 1 ) , + COREWEBVIEW2_HOST_RESOURCE_ACCESS_KIND_DENY_CORS = ( COREWEBVIEW2_HOST_RESOURCE_ACCESS_KIND_ALLOW + 1 ) + } COREWEBVIEW2_HOST_RESOURCE_ACCESS_KIND; + +typedef /* [v1_enum] */ +enum COREWEBVIEW2_SCRIPT_DIALOG_KIND + { + COREWEBVIEW2_SCRIPT_DIALOG_KIND_ALERT = 0, + COREWEBVIEW2_SCRIPT_DIALOG_KIND_CONFIRM = ( COREWEBVIEW2_SCRIPT_DIALOG_KIND_ALERT + 1 ) , + COREWEBVIEW2_SCRIPT_DIALOG_KIND_PROMPT = ( COREWEBVIEW2_SCRIPT_DIALOG_KIND_CONFIRM + 1 ) , + COREWEBVIEW2_SCRIPT_DIALOG_KIND_BEFOREUNLOAD = ( COREWEBVIEW2_SCRIPT_DIALOG_KIND_PROMPT + 1 ) + } COREWEBVIEW2_SCRIPT_DIALOG_KIND; + +typedef /* [v1_enum] */ +enum COREWEBVIEW2_PROCESS_FAILED_KIND + { + COREWEBVIEW2_PROCESS_FAILED_KIND_BROWSER_PROCESS_EXITED = 0, + COREWEBVIEW2_PROCESS_FAILED_KIND_RENDER_PROCESS_EXITED = ( COREWEBVIEW2_PROCESS_FAILED_KIND_BROWSER_PROCESS_EXITED + 1 ) , + COREWEBVIEW2_PROCESS_FAILED_KIND_RENDER_PROCESS_UNRESPONSIVE = ( COREWEBVIEW2_PROCESS_FAILED_KIND_RENDER_PROCESS_EXITED + 1 ) , + COREWEBVIEW2_PROCESS_FAILED_KIND_FRAME_RENDER_PROCESS_EXITED = ( COREWEBVIEW2_PROCESS_FAILED_KIND_RENDER_PROCESS_UNRESPONSIVE + 1 ) , + COREWEBVIEW2_PROCESS_FAILED_KIND_UTILITY_PROCESS_EXITED = ( COREWEBVIEW2_PROCESS_FAILED_KIND_FRAME_RENDER_PROCESS_EXITED + 1 ) , + COREWEBVIEW2_PROCESS_FAILED_KIND_SANDBOX_HELPER_PROCESS_EXITED = ( COREWEBVIEW2_PROCESS_FAILED_KIND_UTILITY_PROCESS_EXITED + 1 ) , + COREWEBVIEW2_PROCESS_FAILED_KIND_GPU_PROCESS_EXITED = ( COREWEBVIEW2_PROCESS_FAILED_KIND_SANDBOX_HELPER_PROCESS_EXITED + 1 ) , + COREWEBVIEW2_PROCESS_FAILED_KIND_PPAPI_PLUGIN_PROCESS_EXITED = ( COREWEBVIEW2_PROCESS_FAILED_KIND_GPU_PROCESS_EXITED + 1 ) , + COREWEBVIEW2_PROCESS_FAILED_KIND_PPAPI_BROKER_PROCESS_EXITED = ( COREWEBVIEW2_PROCESS_FAILED_KIND_PPAPI_PLUGIN_PROCESS_EXITED + 1 ) , + COREWEBVIEW2_PROCESS_FAILED_KIND_UNKNOWN_PROCESS_EXITED = ( COREWEBVIEW2_PROCESS_FAILED_KIND_PPAPI_BROKER_PROCESS_EXITED + 1 ) + } COREWEBVIEW2_PROCESS_FAILED_KIND; + +typedef /* [v1_enum] */ +enum COREWEBVIEW2_PROCESS_FAILED_REASON + { + COREWEBVIEW2_PROCESS_FAILED_REASON_UNEXPECTED = 0, + COREWEBVIEW2_PROCESS_FAILED_REASON_UNRESPONSIVE = ( COREWEBVIEW2_PROCESS_FAILED_REASON_UNEXPECTED + 1 ) , + COREWEBVIEW2_PROCESS_FAILED_REASON_TERMINATED = ( COREWEBVIEW2_PROCESS_FAILED_REASON_UNRESPONSIVE + 1 ) , + COREWEBVIEW2_PROCESS_FAILED_REASON_CRASHED = ( COREWEBVIEW2_PROCESS_FAILED_REASON_TERMINATED + 1 ) , + COREWEBVIEW2_PROCESS_FAILED_REASON_LAUNCH_FAILED = ( COREWEBVIEW2_PROCESS_FAILED_REASON_CRASHED + 1 ) , + COREWEBVIEW2_PROCESS_FAILED_REASON_OUT_OF_MEMORY = ( COREWEBVIEW2_PROCESS_FAILED_REASON_LAUNCH_FAILED + 1 ) + } COREWEBVIEW2_PROCESS_FAILED_REASON; + +typedef /* [v1_enum] */ +enum COREWEBVIEW2_PERMISSION_KIND + { + COREWEBVIEW2_PERMISSION_KIND_UNKNOWN_PERMISSION = 0, + COREWEBVIEW2_PERMISSION_KIND_MICROPHONE = ( COREWEBVIEW2_PERMISSION_KIND_UNKNOWN_PERMISSION + 1 ) , + COREWEBVIEW2_PERMISSION_KIND_CAMERA = ( COREWEBVIEW2_PERMISSION_KIND_MICROPHONE + 1 ) , + COREWEBVIEW2_PERMISSION_KIND_GEOLOCATION = ( COREWEBVIEW2_PERMISSION_KIND_CAMERA + 1 ) , + COREWEBVIEW2_PERMISSION_KIND_NOTIFICATIONS = ( COREWEBVIEW2_PERMISSION_KIND_GEOLOCATION + 1 ) , + COREWEBVIEW2_PERMISSION_KIND_OTHER_SENSORS = ( COREWEBVIEW2_PERMISSION_KIND_NOTIFICATIONS + 1 ) , + COREWEBVIEW2_PERMISSION_KIND_CLIPBOARD_READ = ( COREWEBVIEW2_PERMISSION_KIND_OTHER_SENSORS + 1 ) + } COREWEBVIEW2_PERMISSION_KIND; + +typedef /* [v1_enum] */ +enum COREWEBVIEW2_PERMISSION_STATE + { + COREWEBVIEW2_PERMISSION_STATE_DEFAULT = 0, + COREWEBVIEW2_PERMISSION_STATE_ALLOW = ( COREWEBVIEW2_PERMISSION_STATE_DEFAULT + 1 ) , + COREWEBVIEW2_PERMISSION_STATE_DENY = ( COREWEBVIEW2_PERMISSION_STATE_ALLOW + 1 ) + } COREWEBVIEW2_PERMISSION_STATE; + +typedef /* [v1_enum] */ +enum COREWEBVIEW2_WEB_ERROR_STATUS + { + COREWEBVIEW2_WEB_ERROR_STATUS_UNKNOWN = 0, + COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_COMMON_NAME_IS_INCORRECT = ( COREWEBVIEW2_WEB_ERROR_STATUS_UNKNOWN + 1 ) , + COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_EXPIRED = ( COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_COMMON_NAME_IS_INCORRECT + 1 ) , + COREWEBVIEW2_WEB_ERROR_STATUS_CLIENT_CERTIFICATE_CONTAINS_ERRORS = ( COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_EXPIRED + 1 ) , + COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_REVOKED = ( COREWEBVIEW2_WEB_ERROR_STATUS_CLIENT_CERTIFICATE_CONTAINS_ERRORS + 1 ) , + COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_IS_INVALID = ( COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_REVOKED + 1 ) , + COREWEBVIEW2_WEB_ERROR_STATUS_SERVER_UNREACHABLE = ( COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_IS_INVALID + 1 ) , + COREWEBVIEW2_WEB_ERROR_STATUS_TIMEOUT = ( COREWEBVIEW2_WEB_ERROR_STATUS_SERVER_UNREACHABLE + 1 ) , + COREWEBVIEW2_WEB_ERROR_STATUS_ERROR_HTTP_INVALID_SERVER_RESPONSE = ( COREWEBVIEW2_WEB_ERROR_STATUS_TIMEOUT + 1 ) , + COREWEBVIEW2_WEB_ERROR_STATUS_CONNECTION_ABORTED = ( COREWEBVIEW2_WEB_ERROR_STATUS_ERROR_HTTP_INVALID_SERVER_RESPONSE + 1 ) , + COREWEBVIEW2_WEB_ERROR_STATUS_CONNECTION_RESET = ( COREWEBVIEW2_WEB_ERROR_STATUS_CONNECTION_ABORTED + 1 ) , + COREWEBVIEW2_WEB_ERROR_STATUS_DISCONNECTED = ( COREWEBVIEW2_WEB_ERROR_STATUS_CONNECTION_RESET + 1 ) , + COREWEBVIEW2_WEB_ERROR_STATUS_CANNOT_CONNECT = ( COREWEBVIEW2_WEB_ERROR_STATUS_DISCONNECTED + 1 ) , + COREWEBVIEW2_WEB_ERROR_STATUS_HOST_NAME_NOT_RESOLVED = ( COREWEBVIEW2_WEB_ERROR_STATUS_CANNOT_CONNECT + 1 ) , + COREWEBVIEW2_WEB_ERROR_STATUS_OPERATION_CANCELED = ( COREWEBVIEW2_WEB_ERROR_STATUS_HOST_NAME_NOT_RESOLVED + 1 ) , + COREWEBVIEW2_WEB_ERROR_STATUS_REDIRECT_FAILED = ( COREWEBVIEW2_WEB_ERROR_STATUS_OPERATION_CANCELED + 1 ) , + COREWEBVIEW2_WEB_ERROR_STATUS_UNEXPECTED_ERROR = ( COREWEBVIEW2_WEB_ERROR_STATUS_REDIRECT_FAILED + 1 ) + } COREWEBVIEW2_WEB_ERROR_STATUS; + +typedef /* [v1_enum] */ +enum COREWEBVIEW2_WEB_RESOURCE_CONTEXT + { + COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL = 0, + COREWEBVIEW2_WEB_RESOURCE_CONTEXT_DOCUMENT = ( COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL + 1 ) , + COREWEBVIEW2_WEB_RESOURCE_CONTEXT_STYLESHEET = ( COREWEBVIEW2_WEB_RESOURCE_CONTEXT_DOCUMENT + 1 ) , + COREWEBVIEW2_WEB_RESOURCE_CONTEXT_IMAGE = ( COREWEBVIEW2_WEB_RESOURCE_CONTEXT_STYLESHEET + 1 ) , + COREWEBVIEW2_WEB_RESOURCE_CONTEXT_MEDIA = ( COREWEBVIEW2_WEB_RESOURCE_CONTEXT_IMAGE + 1 ) , + COREWEBVIEW2_WEB_RESOURCE_CONTEXT_FONT = ( COREWEBVIEW2_WEB_RESOURCE_CONTEXT_MEDIA + 1 ) , + COREWEBVIEW2_WEB_RESOURCE_CONTEXT_SCRIPT = ( COREWEBVIEW2_WEB_RESOURCE_CONTEXT_FONT + 1 ) , + COREWEBVIEW2_WEB_RESOURCE_CONTEXT_XML_HTTP_REQUEST = ( COREWEBVIEW2_WEB_RESOURCE_CONTEXT_SCRIPT + 1 ) , + COREWEBVIEW2_WEB_RESOURCE_CONTEXT_FETCH = ( COREWEBVIEW2_WEB_RESOURCE_CONTEXT_XML_HTTP_REQUEST + 1 ) , + COREWEBVIEW2_WEB_RESOURCE_CONTEXT_TEXT_TRACK = ( COREWEBVIEW2_WEB_RESOURCE_CONTEXT_FETCH + 1 ) , + COREWEBVIEW2_WEB_RESOURCE_CONTEXT_EVENT_SOURCE = ( COREWEBVIEW2_WEB_RESOURCE_CONTEXT_TEXT_TRACK + 1 ) , + COREWEBVIEW2_WEB_RESOURCE_CONTEXT_WEBSOCKET = ( COREWEBVIEW2_WEB_RESOURCE_CONTEXT_EVENT_SOURCE + 1 ) , + COREWEBVIEW2_WEB_RESOURCE_CONTEXT_MANIFEST = ( COREWEBVIEW2_WEB_RESOURCE_CONTEXT_WEBSOCKET + 1 ) , + COREWEBVIEW2_WEB_RESOURCE_CONTEXT_SIGNED_EXCHANGE = ( COREWEBVIEW2_WEB_RESOURCE_CONTEXT_MANIFEST + 1 ) , + COREWEBVIEW2_WEB_RESOURCE_CONTEXT_PING = ( COREWEBVIEW2_WEB_RESOURCE_CONTEXT_SIGNED_EXCHANGE + 1 ) , + COREWEBVIEW2_WEB_RESOURCE_CONTEXT_CSP_VIOLATION_REPORT = ( COREWEBVIEW2_WEB_RESOURCE_CONTEXT_PING + 1 ) , + COREWEBVIEW2_WEB_RESOURCE_CONTEXT_OTHER = ( COREWEBVIEW2_WEB_RESOURCE_CONTEXT_CSP_VIOLATION_REPORT + 1 ) + } COREWEBVIEW2_WEB_RESOURCE_CONTEXT; + +typedef /* [v1_enum] */ +enum COREWEBVIEW2_MOVE_FOCUS_REASON + { + COREWEBVIEW2_MOVE_FOCUS_REASON_PROGRAMMATIC = 0, + COREWEBVIEW2_MOVE_FOCUS_REASON_NEXT = ( COREWEBVIEW2_MOVE_FOCUS_REASON_PROGRAMMATIC + 1 ) , + COREWEBVIEW2_MOVE_FOCUS_REASON_PREVIOUS = ( COREWEBVIEW2_MOVE_FOCUS_REASON_NEXT + 1 ) + } COREWEBVIEW2_MOVE_FOCUS_REASON; + +typedef /* [v1_enum] */ +enum COREWEBVIEW2_KEY_EVENT_KIND + { + COREWEBVIEW2_KEY_EVENT_KIND_KEY_DOWN = 0, + COREWEBVIEW2_KEY_EVENT_KIND_KEY_UP = ( COREWEBVIEW2_KEY_EVENT_KIND_KEY_DOWN + 1 ) , + COREWEBVIEW2_KEY_EVENT_KIND_SYSTEM_KEY_DOWN = ( COREWEBVIEW2_KEY_EVENT_KIND_KEY_UP + 1 ) , + COREWEBVIEW2_KEY_EVENT_KIND_SYSTEM_KEY_UP = ( COREWEBVIEW2_KEY_EVENT_KIND_SYSTEM_KEY_DOWN + 1 ) + } COREWEBVIEW2_KEY_EVENT_KIND; + +typedef struct COREWEBVIEW2_PHYSICAL_KEY_STATUS + { + UINT32 RepeatCount; + UINT32 ScanCode; + BOOL IsExtendedKey; + BOOL IsMenuKeyDown; + BOOL WasKeyDown; + BOOL IsKeyReleased; + } COREWEBVIEW2_PHYSICAL_KEY_STATUS; + +typedef struct COREWEBVIEW2_COLOR + { + BYTE A; + BYTE R; + BYTE G; + BYTE B; + } COREWEBVIEW2_COLOR; + +typedef /* [v1_enum] */ +enum COREWEBVIEW2_MOUSE_EVENT_KIND + { + COREWEBVIEW2_MOUSE_EVENT_KIND_HORIZONTAL_WHEEL = 0x20e, + COREWEBVIEW2_MOUSE_EVENT_KIND_LEFT_BUTTON_DOUBLE_CLICK = 0x203, + COREWEBVIEW2_MOUSE_EVENT_KIND_LEFT_BUTTON_DOWN = 0x201, + COREWEBVIEW2_MOUSE_EVENT_KIND_LEFT_BUTTON_UP = 0x202, + COREWEBVIEW2_MOUSE_EVENT_KIND_LEAVE = 0x2a3, + COREWEBVIEW2_MOUSE_EVENT_KIND_MIDDLE_BUTTON_DOUBLE_CLICK = 0x209, + COREWEBVIEW2_MOUSE_EVENT_KIND_MIDDLE_BUTTON_DOWN = 0x207, + COREWEBVIEW2_MOUSE_EVENT_KIND_MIDDLE_BUTTON_UP = 0x208, + COREWEBVIEW2_MOUSE_EVENT_KIND_MOVE = 0x200, + COREWEBVIEW2_MOUSE_EVENT_KIND_RIGHT_BUTTON_DOUBLE_CLICK = 0x206, + COREWEBVIEW2_MOUSE_EVENT_KIND_RIGHT_BUTTON_DOWN = 0x204, + COREWEBVIEW2_MOUSE_EVENT_KIND_RIGHT_BUTTON_UP = 0x205, + COREWEBVIEW2_MOUSE_EVENT_KIND_WHEEL = 0x20a, + COREWEBVIEW2_MOUSE_EVENT_KIND_X_BUTTON_DOUBLE_CLICK = 0x20d, + COREWEBVIEW2_MOUSE_EVENT_KIND_X_BUTTON_DOWN = 0x20b, + COREWEBVIEW2_MOUSE_EVENT_KIND_X_BUTTON_UP = 0x20c + } COREWEBVIEW2_MOUSE_EVENT_KIND; + +typedef /* [v1_enum] */ +enum COREWEBVIEW2_MOUSE_EVENT_VIRTUAL_KEYS + { + COREWEBVIEW2_MOUSE_EVENT_VIRTUAL_KEYS_NONE = 0, + COREWEBVIEW2_MOUSE_EVENT_VIRTUAL_KEYS_LEFT_BUTTON = 0x1, + COREWEBVIEW2_MOUSE_EVENT_VIRTUAL_KEYS_RIGHT_BUTTON = 0x2, + COREWEBVIEW2_MOUSE_EVENT_VIRTUAL_KEYS_SHIFT = 0x4, + COREWEBVIEW2_MOUSE_EVENT_VIRTUAL_KEYS_CONTROL = 0x8, + COREWEBVIEW2_MOUSE_EVENT_VIRTUAL_KEYS_MIDDLE_BUTTON = 0x10, + COREWEBVIEW2_MOUSE_EVENT_VIRTUAL_KEYS_X_BUTTON1 = 0x20, + COREWEBVIEW2_MOUSE_EVENT_VIRTUAL_KEYS_X_BUTTON2 = 0x40 + } COREWEBVIEW2_MOUSE_EVENT_VIRTUAL_KEYS; + +DEFINE_ENUM_FLAG_OPERATORS(COREWEBVIEW2_MOUSE_EVENT_VIRTUAL_KEYS); +typedef /* [v1_enum] */ +enum COREWEBVIEW2_POINTER_EVENT_KIND + { + COREWEBVIEW2_POINTER_EVENT_KIND_ACTIVATE = 0x24b, + COREWEBVIEW2_POINTER_EVENT_KIND_DOWN = 0x246, + COREWEBVIEW2_POINTER_EVENT_KIND_ENTER = 0x249, + COREWEBVIEW2_POINTER_EVENT_KIND_LEAVE = 0x24a, + COREWEBVIEW2_POINTER_EVENT_KIND_UP = 0x247, + COREWEBVIEW2_POINTER_EVENT_KIND_UPDATE = 0x245 + } COREWEBVIEW2_POINTER_EVENT_KIND; + +typedef /* [v1_enum] */ +enum COREWEBVIEW2_BOUNDS_MODE + { + COREWEBVIEW2_BOUNDS_MODE_USE_RAW_PIXELS = 0, + COREWEBVIEW2_BOUNDS_MODE_USE_RASTERIZATION_SCALE = ( COREWEBVIEW2_BOUNDS_MODE_USE_RAW_PIXELS + 1 ) + } COREWEBVIEW2_BOUNDS_MODE; + +STDAPI CreateCoreWebView2EnvironmentWithOptions(PCWSTR browserExecutableFolder, PCWSTR userDataFolder, ICoreWebView2EnvironmentOptions* environmentOptions, ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler* environmentCreatedHandler); +STDAPI CreateCoreWebView2Environment(ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler* environmentCreatedHandler); +STDAPI GetAvailableCoreWebView2BrowserVersionString(PCWSTR browserExecutableFolder, LPWSTR* versionInfo); +STDAPI CompareBrowserVersions(PCWSTR version1, PCWSTR version2, int* result); + +EXTERN_C const IID LIBID_WebView2; + +#ifndef __ICoreWebView2AcceleratorKeyPressedEventArgs_INTERFACE_DEFINED__ +#define __ICoreWebView2AcceleratorKeyPressedEventArgs_INTERFACE_DEFINED__ + +/* interface ICoreWebView2AcceleratorKeyPressedEventArgs */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2AcceleratorKeyPressedEventArgs = {0x9f760f8a,0xfb79,0x42be,{0x99,0x90,0x7b,0x56,0x90,0x0f,0xa9,0xc7}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("9f760f8a-fb79-42be-9990-7b56900fa9c7") + ICoreWebView2AcceleratorKeyPressedEventArgs : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_KeyEventKind( + /* [retval][out] */ COREWEBVIEW2_KEY_EVENT_KIND *keyEventKind) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_VirtualKey( + /* [retval][out] */ UINT *virtualKey) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_KeyEventLParam( + /* [retval][out] */ INT *lParam) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_PhysicalKeyStatus( + /* [retval][out] */ COREWEBVIEW2_PHYSICAL_KEY_STATUS *physicalKeyStatus) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Handled( + /* [retval][out] */ BOOL *handled) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_Handled( + /* [in] */ BOOL handled) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2AcceleratorKeyPressedEventArgsVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2AcceleratorKeyPressedEventArgs * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2AcceleratorKeyPressedEventArgs * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2AcceleratorKeyPressedEventArgs * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_KeyEventKind )( + ICoreWebView2AcceleratorKeyPressedEventArgs * This, + /* [retval][out] */ COREWEBVIEW2_KEY_EVENT_KIND *keyEventKind); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_VirtualKey )( + ICoreWebView2AcceleratorKeyPressedEventArgs * This, + /* [retval][out] */ UINT *virtualKey); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_KeyEventLParam )( + ICoreWebView2AcceleratorKeyPressedEventArgs * This, + /* [retval][out] */ INT *lParam); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_PhysicalKeyStatus )( + ICoreWebView2AcceleratorKeyPressedEventArgs * This, + /* [retval][out] */ COREWEBVIEW2_PHYSICAL_KEY_STATUS *physicalKeyStatus); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Handled )( + ICoreWebView2AcceleratorKeyPressedEventArgs * This, + /* [retval][out] */ BOOL *handled); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_Handled )( + ICoreWebView2AcceleratorKeyPressedEventArgs * This, + /* [in] */ BOOL handled); + + END_INTERFACE + } ICoreWebView2AcceleratorKeyPressedEventArgsVtbl; + + interface ICoreWebView2AcceleratorKeyPressedEventArgs + { + CONST_VTBL struct ICoreWebView2AcceleratorKeyPressedEventArgsVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2AcceleratorKeyPressedEventArgs_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2AcceleratorKeyPressedEventArgs_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2AcceleratorKeyPressedEventArgs_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2AcceleratorKeyPressedEventArgs_get_KeyEventKind(This,keyEventKind) \ + ( (This)->lpVtbl -> get_KeyEventKind(This,keyEventKind) ) + +#define ICoreWebView2AcceleratorKeyPressedEventArgs_get_VirtualKey(This,virtualKey) \ + ( (This)->lpVtbl -> get_VirtualKey(This,virtualKey) ) + +#define ICoreWebView2AcceleratorKeyPressedEventArgs_get_KeyEventLParam(This,lParam) \ + ( (This)->lpVtbl -> get_KeyEventLParam(This,lParam) ) + +#define ICoreWebView2AcceleratorKeyPressedEventArgs_get_PhysicalKeyStatus(This,physicalKeyStatus) \ + ( (This)->lpVtbl -> get_PhysicalKeyStatus(This,physicalKeyStatus) ) + +#define ICoreWebView2AcceleratorKeyPressedEventArgs_get_Handled(This,handled) \ + ( (This)->lpVtbl -> get_Handled(This,handled) ) + +#define ICoreWebView2AcceleratorKeyPressedEventArgs_put_Handled(This,handled) \ + ( (This)->lpVtbl -> put_Handled(This,handled) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2AcceleratorKeyPressedEventArgs_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2AcceleratorKeyPressedEventHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2AcceleratorKeyPressedEventHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2AcceleratorKeyPressedEventHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2AcceleratorKeyPressedEventHandler = {0xb29c7e28,0xfa79,0x41a8,{0x8e,0x44,0x65,0x81,0x1c,0x76,0xdc,0xb2}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("b29c7e28-fa79-41a8-8e44-65811c76dcb2") + ICoreWebView2AcceleratorKeyPressedEventHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + /* [in] */ ICoreWebView2Controller *sender, + /* [in] */ ICoreWebView2AcceleratorKeyPressedEventArgs *args) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2AcceleratorKeyPressedEventHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2AcceleratorKeyPressedEventHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2AcceleratorKeyPressedEventHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2AcceleratorKeyPressedEventHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2AcceleratorKeyPressedEventHandler * This, + /* [in] */ ICoreWebView2Controller *sender, + /* [in] */ ICoreWebView2AcceleratorKeyPressedEventArgs *args); + + END_INTERFACE + } ICoreWebView2AcceleratorKeyPressedEventHandlerVtbl; + + interface ICoreWebView2AcceleratorKeyPressedEventHandler + { + CONST_VTBL struct ICoreWebView2AcceleratorKeyPressedEventHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2AcceleratorKeyPressedEventHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2AcceleratorKeyPressedEventHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2AcceleratorKeyPressedEventHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2AcceleratorKeyPressedEventHandler_Invoke(This,sender,args) \ + ( (This)->lpVtbl -> Invoke(This,sender,args) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2AcceleratorKeyPressedEventHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2AddScriptToExecuteOnDocumentCreatedCompletedHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2AddScriptToExecuteOnDocumentCreatedCompletedHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2AddScriptToExecuteOnDocumentCreatedCompletedHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2AddScriptToExecuteOnDocumentCreatedCompletedHandler = {0xb99369f3,0x9b11,0x47b5,{0xbc,0x6f,0x8e,0x78,0x95,0xfc,0xea,0x17}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("b99369f3-9b11-47b5-bc6f-8e7895fcea17") + ICoreWebView2AddScriptToExecuteOnDocumentCreatedCompletedHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + /* [in] */ HRESULT errorCode, + /* [in] */ LPCWSTR id) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2AddScriptToExecuteOnDocumentCreatedCompletedHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2AddScriptToExecuteOnDocumentCreatedCompletedHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2AddScriptToExecuteOnDocumentCreatedCompletedHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2AddScriptToExecuteOnDocumentCreatedCompletedHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2AddScriptToExecuteOnDocumentCreatedCompletedHandler * This, + /* [in] */ HRESULT errorCode, + /* [in] */ LPCWSTR id); + + END_INTERFACE + } ICoreWebView2AddScriptToExecuteOnDocumentCreatedCompletedHandlerVtbl; + + interface ICoreWebView2AddScriptToExecuteOnDocumentCreatedCompletedHandler + { + CONST_VTBL struct ICoreWebView2AddScriptToExecuteOnDocumentCreatedCompletedHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2AddScriptToExecuteOnDocumentCreatedCompletedHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2AddScriptToExecuteOnDocumentCreatedCompletedHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2AddScriptToExecuteOnDocumentCreatedCompletedHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2AddScriptToExecuteOnDocumentCreatedCompletedHandler_Invoke(This,errorCode,id) \ + ( (This)->lpVtbl -> Invoke(This,errorCode,id) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2AddScriptToExecuteOnDocumentCreatedCompletedHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2CallDevToolsProtocolMethodCompletedHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2CallDevToolsProtocolMethodCompletedHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2CallDevToolsProtocolMethodCompletedHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2CallDevToolsProtocolMethodCompletedHandler = {0x5c4889f0,0x5ef6,0x4c5a,{0x95,0x2c,0xd8,0xf1,0xb9,0x2d,0x05,0x74}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("5c4889f0-5ef6-4c5a-952c-d8f1b92d0574") + ICoreWebView2CallDevToolsProtocolMethodCompletedHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + /* [in] */ HRESULT errorCode, + /* [in] */ LPCWSTR returnObjectAsJson) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2CallDevToolsProtocolMethodCompletedHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2CallDevToolsProtocolMethodCompletedHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2CallDevToolsProtocolMethodCompletedHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2CallDevToolsProtocolMethodCompletedHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2CallDevToolsProtocolMethodCompletedHandler * This, + /* [in] */ HRESULT errorCode, + /* [in] */ LPCWSTR returnObjectAsJson); + + END_INTERFACE + } ICoreWebView2CallDevToolsProtocolMethodCompletedHandlerVtbl; + + interface ICoreWebView2CallDevToolsProtocolMethodCompletedHandler + { + CONST_VTBL struct ICoreWebView2CallDevToolsProtocolMethodCompletedHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2CallDevToolsProtocolMethodCompletedHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2CallDevToolsProtocolMethodCompletedHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2CallDevToolsProtocolMethodCompletedHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2CallDevToolsProtocolMethodCompletedHandler_Invoke(This,errorCode,returnObjectAsJson) \ + ( (This)->lpVtbl -> Invoke(This,errorCode,returnObjectAsJson) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2CallDevToolsProtocolMethodCompletedHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2CapturePreviewCompletedHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2CapturePreviewCompletedHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2CapturePreviewCompletedHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2CapturePreviewCompletedHandler = {0x697e05e9,0x3d8f,0x45fa,{0x96,0xf4,0x8f,0xfe,0x1e,0xde,0xda,0xf5}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("697e05e9-3d8f-45fa-96f4-8ffe1ededaf5") + ICoreWebView2CapturePreviewCompletedHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + /* [in] */ HRESULT errorCode) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2CapturePreviewCompletedHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2CapturePreviewCompletedHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2CapturePreviewCompletedHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2CapturePreviewCompletedHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2CapturePreviewCompletedHandler * This, + /* [in] */ HRESULT errorCode); + + END_INTERFACE + } ICoreWebView2CapturePreviewCompletedHandlerVtbl; + + interface ICoreWebView2CapturePreviewCompletedHandler + { + CONST_VTBL struct ICoreWebView2CapturePreviewCompletedHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2CapturePreviewCompletedHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2CapturePreviewCompletedHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2CapturePreviewCompletedHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2CapturePreviewCompletedHandler_Invoke(This,errorCode) \ + ( (This)->lpVtbl -> Invoke(This,errorCode) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2CapturePreviewCompletedHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2_INTERFACE_DEFINED__ +#define __ICoreWebView2_INTERFACE_DEFINED__ + +/* interface ICoreWebView2 */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2 = {0x76eceacb,0x0462,0x4d94,{0xac,0x83,0x42,0x3a,0x67,0x93,0x77,0x5e}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("76eceacb-0462-4d94-ac83-423a6793775e") + ICoreWebView2 : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Settings( + /* [retval][out] */ ICoreWebView2Settings **settings) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Source( + /* [retval][out] */ LPWSTR *uri) = 0; + + virtual HRESULT STDMETHODCALLTYPE Navigate( + /* [in] */ LPCWSTR uri) = 0; + + virtual HRESULT STDMETHODCALLTYPE NavigateToString( + /* [in] */ LPCWSTR htmlContent) = 0; + + virtual HRESULT STDMETHODCALLTYPE add_NavigationStarting( + /* [in] */ ICoreWebView2NavigationStartingEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token) = 0; + + virtual HRESULT STDMETHODCALLTYPE remove_NavigationStarting( + /* [in] */ EventRegistrationToken token) = 0; + + virtual HRESULT STDMETHODCALLTYPE add_ContentLoading( + /* [in] */ ICoreWebView2ContentLoadingEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token) = 0; + + virtual HRESULT STDMETHODCALLTYPE remove_ContentLoading( + /* [in] */ EventRegistrationToken token) = 0; + + virtual HRESULT STDMETHODCALLTYPE add_SourceChanged( + /* [in] */ ICoreWebView2SourceChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token) = 0; + + virtual HRESULT STDMETHODCALLTYPE remove_SourceChanged( + /* [in] */ EventRegistrationToken token) = 0; + + virtual HRESULT STDMETHODCALLTYPE add_HistoryChanged( + /* [in] */ ICoreWebView2HistoryChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token) = 0; + + virtual HRESULT STDMETHODCALLTYPE remove_HistoryChanged( + /* [in] */ EventRegistrationToken token) = 0; + + virtual HRESULT STDMETHODCALLTYPE add_NavigationCompleted( + /* [in] */ ICoreWebView2NavigationCompletedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token) = 0; + + virtual HRESULT STDMETHODCALLTYPE remove_NavigationCompleted( + /* [in] */ EventRegistrationToken token) = 0; + + virtual HRESULT STDMETHODCALLTYPE add_FrameNavigationStarting( + /* [in] */ ICoreWebView2NavigationStartingEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token) = 0; + + virtual HRESULT STDMETHODCALLTYPE remove_FrameNavigationStarting( + /* [in] */ EventRegistrationToken token) = 0; + + virtual HRESULT STDMETHODCALLTYPE add_FrameNavigationCompleted( + /* [in] */ ICoreWebView2NavigationCompletedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token) = 0; + + virtual HRESULT STDMETHODCALLTYPE remove_FrameNavigationCompleted( + /* [in] */ EventRegistrationToken token) = 0; + + virtual HRESULT STDMETHODCALLTYPE add_ScriptDialogOpening( + /* [in] */ ICoreWebView2ScriptDialogOpeningEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token) = 0; + + virtual HRESULT STDMETHODCALLTYPE remove_ScriptDialogOpening( + /* [in] */ EventRegistrationToken token) = 0; + + virtual HRESULT STDMETHODCALLTYPE add_PermissionRequested( + /* [in] */ ICoreWebView2PermissionRequestedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token) = 0; + + virtual HRESULT STDMETHODCALLTYPE remove_PermissionRequested( + /* [in] */ EventRegistrationToken token) = 0; + + virtual HRESULT STDMETHODCALLTYPE add_ProcessFailed( + /* [in] */ ICoreWebView2ProcessFailedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token) = 0; + + virtual HRESULT STDMETHODCALLTYPE remove_ProcessFailed( + /* [in] */ EventRegistrationToken token) = 0; + + virtual HRESULT STDMETHODCALLTYPE AddScriptToExecuteOnDocumentCreated( + /* [in] */ LPCWSTR javaScript, + /* [in] */ ICoreWebView2AddScriptToExecuteOnDocumentCreatedCompletedHandler *handler) = 0; + + virtual HRESULT STDMETHODCALLTYPE RemoveScriptToExecuteOnDocumentCreated( + /* [in] */ LPCWSTR id) = 0; + + virtual HRESULT STDMETHODCALLTYPE ExecuteScript( + /* [in] */ LPCWSTR javaScript, + /* [in] */ ICoreWebView2ExecuteScriptCompletedHandler *handler) = 0; + + virtual HRESULT STDMETHODCALLTYPE CapturePreview( + /* [in] */ COREWEBVIEW2_CAPTURE_PREVIEW_IMAGE_FORMAT imageFormat, + /* [in] */ IStream *imageStream, + /* [in] */ ICoreWebView2CapturePreviewCompletedHandler *handler) = 0; + + virtual HRESULT STDMETHODCALLTYPE Reload( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE PostWebMessageAsJson( + /* [in] */ LPCWSTR webMessageAsJson) = 0; + + virtual HRESULT STDMETHODCALLTYPE PostWebMessageAsString( + /* [in] */ LPCWSTR webMessageAsString) = 0; + + virtual HRESULT STDMETHODCALLTYPE add_WebMessageReceived( + /* [in] */ ICoreWebView2WebMessageReceivedEventHandler *handler, + /* [out] */ EventRegistrationToken *token) = 0; + + virtual HRESULT STDMETHODCALLTYPE remove_WebMessageReceived( + /* [in] */ EventRegistrationToken token) = 0; + + virtual HRESULT STDMETHODCALLTYPE CallDevToolsProtocolMethod( + /* [in] */ LPCWSTR methodName, + /* [in] */ LPCWSTR parametersAsJson, + /* [in] */ ICoreWebView2CallDevToolsProtocolMethodCompletedHandler *handler) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_BrowserProcessId( + /* [retval][out] */ UINT32 *value) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_CanGoBack( + /* [retval][out] */ BOOL *canGoBack) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_CanGoForward( + /* [retval][out] */ BOOL *canGoForward) = 0; + + virtual HRESULT STDMETHODCALLTYPE GoBack( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GoForward( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDevToolsProtocolEventReceiver( + /* [in] */ LPCWSTR eventName, + /* [retval][out] */ ICoreWebView2DevToolsProtocolEventReceiver **receiver) = 0; + + virtual HRESULT STDMETHODCALLTYPE Stop( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE add_NewWindowRequested( + /* [in] */ ICoreWebView2NewWindowRequestedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token) = 0; + + virtual HRESULT STDMETHODCALLTYPE remove_NewWindowRequested( + /* [in] */ EventRegistrationToken token) = 0; + + virtual HRESULT STDMETHODCALLTYPE add_DocumentTitleChanged( + /* [in] */ ICoreWebView2DocumentTitleChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token) = 0; + + virtual HRESULT STDMETHODCALLTYPE remove_DocumentTitleChanged( + /* [in] */ EventRegistrationToken token) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_DocumentTitle( + /* [retval][out] */ LPWSTR *title) = 0; + + virtual HRESULT STDMETHODCALLTYPE AddHostObjectToScript( + /* [in] */ LPCWSTR name, + /* [in] */ VARIANT *object) = 0; + + virtual HRESULT STDMETHODCALLTYPE RemoveHostObjectFromScript( + /* [in] */ LPCWSTR name) = 0; + + virtual HRESULT STDMETHODCALLTYPE OpenDevToolsWindow( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE add_ContainsFullScreenElementChanged( + /* [in] */ ICoreWebView2ContainsFullScreenElementChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token) = 0; + + virtual HRESULT STDMETHODCALLTYPE remove_ContainsFullScreenElementChanged( + /* [in] */ EventRegistrationToken token) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_ContainsFullScreenElement( + /* [retval][out] */ BOOL *containsFullScreenElement) = 0; + + virtual HRESULT STDMETHODCALLTYPE add_WebResourceRequested( + /* [in] */ ICoreWebView2WebResourceRequestedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token) = 0; + + virtual HRESULT STDMETHODCALLTYPE remove_WebResourceRequested( + /* [in] */ EventRegistrationToken token) = 0; + + virtual HRESULT STDMETHODCALLTYPE AddWebResourceRequestedFilter( + /* [in] */ const LPCWSTR uri, + /* [in] */ const COREWEBVIEW2_WEB_RESOURCE_CONTEXT resourceContext) = 0; + + virtual HRESULT STDMETHODCALLTYPE RemoveWebResourceRequestedFilter( + /* [in] */ const LPCWSTR uri, + /* [in] */ const COREWEBVIEW2_WEB_RESOURCE_CONTEXT resourceContext) = 0; + + virtual HRESULT STDMETHODCALLTYPE add_WindowCloseRequested( + /* [in] */ ICoreWebView2WindowCloseRequestedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token) = 0; + + virtual HRESULT STDMETHODCALLTYPE remove_WindowCloseRequested( + /* [in] */ EventRegistrationToken token) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2 * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Settings )( + ICoreWebView2 * This, + /* [retval][out] */ ICoreWebView2Settings **settings); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Source )( + ICoreWebView2 * This, + /* [retval][out] */ LPWSTR *uri); + + HRESULT ( STDMETHODCALLTYPE *Navigate )( + ICoreWebView2 * This, + /* [in] */ LPCWSTR uri); + + HRESULT ( STDMETHODCALLTYPE *NavigateToString )( + ICoreWebView2 * This, + /* [in] */ LPCWSTR htmlContent); + + HRESULT ( STDMETHODCALLTYPE *add_NavigationStarting )( + ICoreWebView2 * This, + /* [in] */ ICoreWebView2NavigationStartingEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_NavigationStarting )( + ICoreWebView2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_ContentLoading )( + ICoreWebView2 * This, + /* [in] */ ICoreWebView2ContentLoadingEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_ContentLoading )( + ICoreWebView2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_SourceChanged )( + ICoreWebView2 * This, + /* [in] */ ICoreWebView2SourceChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_SourceChanged )( + ICoreWebView2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_HistoryChanged )( + ICoreWebView2 * This, + /* [in] */ ICoreWebView2HistoryChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_HistoryChanged )( + ICoreWebView2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_NavigationCompleted )( + ICoreWebView2 * This, + /* [in] */ ICoreWebView2NavigationCompletedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_NavigationCompleted )( + ICoreWebView2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_FrameNavigationStarting )( + ICoreWebView2 * This, + /* [in] */ ICoreWebView2NavigationStartingEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_FrameNavigationStarting )( + ICoreWebView2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_FrameNavigationCompleted )( + ICoreWebView2 * This, + /* [in] */ ICoreWebView2NavigationCompletedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_FrameNavigationCompleted )( + ICoreWebView2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_ScriptDialogOpening )( + ICoreWebView2 * This, + /* [in] */ ICoreWebView2ScriptDialogOpeningEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_ScriptDialogOpening )( + ICoreWebView2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_PermissionRequested )( + ICoreWebView2 * This, + /* [in] */ ICoreWebView2PermissionRequestedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_PermissionRequested )( + ICoreWebView2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_ProcessFailed )( + ICoreWebView2 * This, + /* [in] */ ICoreWebView2ProcessFailedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_ProcessFailed )( + ICoreWebView2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *AddScriptToExecuteOnDocumentCreated )( + ICoreWebView2 * This, + /* [in] */ LPCWSTR javaScript, + /* [in] */ ICoreWebView2AddScriptToExecuteOnDocumentCreatedCompletedHandler *handler); + + HRESULT ( STDMETHODCALLTYPE *RemoveScriptToExecuteOnDocumentCreated )( + ICoreWebView2 * This, + /* [in] */ LPCWSTR id); + + HRESULT ( STDMETHODCALLTYPE *ExecuteScript )( + ICoreWebView2 * This, + /* [in] */ LPCWSTR javaScript, + /* [in] */ ICoreWebView2ExecuteScriptCompletedHandler *handler); + + HRESULT ( STDMETHODCALLTYPE *CapturePreview )( + ICoreWebView2 * This, + /* [in] */ COREWEBVIEW2_CAPTURE_PREVIEW_IMAGE_FORMAT imageFormat, + /* [in] */ IStream *imageStream, + /* [in] */ ICoreWebView2CapturePreviewCompletedHandler *handler); + + HRESULT ( STDMETHODCALLTYPE *Reload )( + ICoreWebView2 * This); + + HRESULT ( STDMETHODCALLTYPE *PostWebMessageAsJson )( + ICoreWebView2 * This, + /* [in] */ LPCWSTR webMessageAsJson); + + HRESULT ( STDMETHODCALLTYPE *PostWebMessageAsString )( + ICoreWebView2 * This, + /* [in] */ LPCWSTR webMessageAsString); + + HRESULT ( STDMETHODCALLTYPE *add_WebMessageReceived )( + ICoreWebView2 * This, + /* [in] */ ICoreWebView2WebMessageReceivedEventHandler *handler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_WebMessageReceived )( + ICoreWebView2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *CallDevToolsProtocolMethod )( + ICoreWebView2 * This, + /* [in] */ LPCWSTR methodName, + /* [in] */ LPCWSTR parametersAsJson, + /* [in] */ ICoreWebView2CallDevToolsProtocolMethodCompletedHandler *handler); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_BrowserProcessId )( + ICoreWebView2 * This, + /* [retval][out] */ UINT32 *value); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_CanGoBack )( + ICoreWebView2 * This, + /* [retval][out] */ BOOL *canGoBack); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_CanGoForward )( + ICoreWebView2 * This, + /* [retval][out] */ BOOL *canGoForward); + + HRESULT ( STDMETHODCALLTYPE *GoBack )( + ICoreWebView2 * This); + + HRESULT ( STDMETHODCALLTYPE *GoForward )( + ICoreWebView2 * This); + + HRESULT ( STDMETHODCALLTYPE *GetDevToolsProtocolEventReceiver )( + ICoreWebView2 * This, + /* [in] */ LPCWSTR eventName, + /* [retval][out] */ ICoreWebView2DevToolsProtocolEventReceiver **receiver); + + HRESULT ( STDMETHODCALLTYPE *Stop )( + ICoreWebView2 * This); + + HRESULT ( STDMETHODCALLTYPE *add_NewWindowRequested )( + ICoreWebView2 * This, + /* [in] */ ICoreWebView2NewWindowRequestedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_NewWindowRequested )( + ICoreWebView2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_DocumentTitleChanged )( + ICoreWebView2 * This, + /* [in] */ ICoreWebView2DocumentTitleChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_DocumentTitleChanged )( + ICoreWebView2 * This, + /* [in] */ EventRegistrationToken token); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_DocumentTitle )( + ICoreWebView2 * This, + /* [retval][out] */ LPWSTR *title); + + HRESULT ( STDMETHODCALLTYPE *AddHostObjectToScript )( + ICoreWebView2 * This, + /* [in] */ LPCWSTR name, + /* [in] */ VARIANT *object); + + HRESULT ( STDMETHODCALLTYPE *RemoveHostObjectFromScript )( + ICoreWebView2 * This, + /* [in] */ LPCWSTR name); + + HRESULT ( STDMETHODCALLTYPE *OpenDevToolsWindow )( + ICoreWebView2 * This); + + HRESULT ( STDMETHODCALLTYPE *add_ContainsFullScreenElementChanged )( + ICoreWebView2 * This, + /* [in] */ ICoreWebView2ContainsFullScreenElementChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_ContainsFullScreenElementChanged )( + ICoreWebView2 * This, + /* [in] */ EventRegistrationToken token); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_ContainsFullScreenElement )( + ICoreWebView2 * This, + /* [retval][out] */ BOOL *containsFullScreenElement); + + HRESULT ( STDMETHODCALLTYPE *add_WebResourceRequested )( + ICoreWebView2 * This, + /* [in] */ ICoreWebView2WebResourceRequestedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_WebResourceRequested )( + ICoreWebView2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *AddWebResourceRequestedFilter )( + ICoreWebView2 * This, + /* [in] */ const LPCWSTR uri, + /* [in] */ const COREWEBVIEW2_WEB_RESOURCE_CONTEXT resourceContext); + + HRESULT ( STDMETHODCALLTYPE *RemoveWebResourceRequestedFilter )( + ICoreWebView2 * This, + /* [in] */ const LPCWSTR uri, + /* [in] */ const COREWEBVIEW2_WEB_RESOURCE_CONTEXT resourceContext); + + HRESULT ( STDMETHODCALLTYPE *add_WindowCloseRequested )( + ICoreWebView2 * This, + /* [in] */ ICoreWebView2WindowCloseRequestedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_WindowCloseRequested )( + ICoreWebView2 * This, + /* [in] */ EventRegistrationToken token); + + END_INTERFACE + } ICoreWebView2Vtbl; + + interface ICoreWebView2 + { + CONST_VTBL struct ICoreWebView2Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2_get_Settings(This,settings) \ + ( (This)->lpVtbl -> get_Settings(This,settings) ) + +#define ICoreWebView2_get_Source(This,uri) \ + ( (This)->lpVtbl -> get_Source(This,uri) ) + +#define ICoreWebView2_Navigate(This,uri) \ + ( (This)->lpVtbl -> Navigate(This,uri) ) + +#define ICoreWebView2_NavigateToString(This,htmlContent) \ + ( (This)->lpVtbl -> NavigateToString(This,htmlContent) ) + +#define ICoreWebView2_add_NavigationStarting(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_NavigationStarting(This,eventHandler,token) ) + +#define ICoreWebView2_remove_NavigationStarting(This,token) \ + ( (This)->lpVtbl -> remove_NavigationStarting(This,token) ) + +#define ICoreWebView2_add_ContentLoading(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_ContentLoading(This,eventHandler,token) ) + +#define ICoreWebView2_remove_ContentLoading(This,token) \ + ( (This)->lpVtbl -> remove_ContentLoading(This,token) ) + +#define ICoreWebView2_add_SourceChanged(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_SourceChanged(This,eventHandler,token) ) + +#define ICoreWebView2_remove_SourceChanged(This,token) \ + ( (This)->lpVtbl -> remove_SourceChanged(This,token) ) + +#define ICoreWebView2_add_HistoryChanged(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_HistoryChanged(This,eventHandler,token) ) + +#define ICoreWebView2_remove_HistoryChanged(This,token) \ + ( (This)->lpVtbl -> remove_HistoryChanged(This,token) ) + +#define ICoreWebView2_add_NavigationCompleted(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_NavigationCompleted(This,eventHandler,token) ) + +#define ICoreWebView2_remove_NavigationCompleted(This,token) \ + ( (This)->lpVtbl -> remove_NavigationCompleted(This,token) ) + +#define ICoreWebView2_add_FrameNavigationStarting(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_FrameNavigationStarting(This,eventHandler,token) ) + +#define ICoreWebView2_remove_FrameNavigationStarting(This,token) \ + ( (This)->lpVtbl -> remove_FrameNavigationStarting(This,token) ) + +#define ICoreWebView2_add_FrameNavigationCompleted(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_FrameNavigationCompleted(This,eventHandler,token) ) + +#define ICoreWebView2_remove_FrameNavigationCompleted(This,token) \ + ( (This)->lpVtbl -> remove_FrameNavigationCompleted(This,token) ) + +#define ICoreWebView2_add_ScriptDialogOpening(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_ScriptDialogOpening(This,eventHandler,token) ) + +#define ICoreWebView2_remove_ScriptDialogOpening(This,token) \ + ( (This)->lpVtbl -> remove_ScriptDialogOpening(This,token) ) + +#define ICoreWebView2_add_PermissionRequested(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_PermissionRequested(This,eventHandler,token) ) + +#define ICoreWebView2_remove_PermissionRequested(This,token) \ + ( (This)->lpVtbl -> remove_PermissionRequested(This,token) ) + +#define ICoreWebView2_add_ProcessFailed(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_ProcessFailed(This,eventHandler,token) ) + +#define ICoreWebView2_remove_ProcessFailed(This,token) \ + ( (This)->lpVtbl -> remove_ProcessFailed(This,token) ) + +#define ICoreWebView2_AddScriptToExecuteOnDocumentCreated(This,javaScript,handler) \ + ( (This)->lpVtbl -> AddScriptToExecuteOnDocumentCreated(This,javaScript,handler) ) + +#define ICoreWebView2_RemoveScriptToExecuteOnDocumentCreated(This,id) \ + ( (This)->lpVtbl -> RemoveScriptToExecuteOnDocumentCreated(This,id) ) + +#define ICoreWebView2_ExecuteScript(This,javaScript,handler) \ + ( (This)->lpVtbl -> ExecuteScript(This,javaScript,handler) ) + +#define ICoreWebView2_CapturePreview(This,imageFormat,imageStream,handler) \ + ( (This)->lpVtbl -> CapturePreview(This,imageFormat,imageStream,handler) ) + +#define ICoreWebView2_Reload(This) \ + ( (This)->lpVtbl -> Reload(This) ) + +#define ICoreWebView2_PostWebMessageAsJson(This,webMessageAsJson) \ + ( (This)->lpVtbl -> PostWebMessageAsJson(This,webMessageAsJson) ) + +#define ICoreWebView2_PostWebMessageAsString(This,webMessageAsString) \ + ( (This)->lpVtbl -> PostWebMessageAsString(This,webMessageAsString) ) + +#define ICoreWebView2_add_WebMessageReceived(This,handler,token) \ + ( (This)->lpVtbl -> add_WebMessageReceived(This,handler,token) ) + +#define ICoreWebView2_remove_WebMessageReceived(This,token) \ + ( (This)->lpVtbl -> remove_WebMessageReceived(This,token) ) + +#define ICoreWebView2_CallDevToolsProtocolMethod(This,methodName,parametersAsJson,handler) \ + ( (This)->lpVtbl -> CallDevToolsProtocolMethod(This,methodName,parametersAsJson,handler) ) + +#define ICoreWebView2_get_BrowserProcessId(This,value) \ + ( (This)->lpVtbl -> get_BrowserProcessId(This,value) ) + +#define ICoreWebView2_get_CanGoBack(This,canGoBack) \ + ( (This)->lpVtbl -> get_CanGoBack(This,canGoBack) ) + +#define ICoreWebView2_get_CanGoForward(This,canGoForward) \ + ( (This)->lpVtbl -> get_CanGoForward(This,canGoForward) ) + +#define ICoreWebView2_GoBack(This) \ + ( (This)->lpVtbl -> GoBack(This) ) + +#define ICoreWebView2_GoForward(This) \ + ( (This)->lpVtbl -> GoForward(This) ) + +#define ICoreWebView2_GetDevToolsProtocolEventReceiver(This,eventName,receiver) \ + ( (This)->lpVtbl -> GetDevToolsProtocolEventReceiver(This,eventName,receiver) ) + +#define ICoreWebView2_Stop(This) \ + ( (This)->lpVtbl -> Stop(This) ) + +#define ICoreWebView2_add_NewWindowRequested(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_NewWindowRequested(This,eventHandler,token) ) + +#define ICoreWebView2_remove_NewWindowRequested(This,token) \ + ( (This)->lpVtbl -> remove_NewWindowRequested(This,token) ) + +#define ICoreWebView2_add_DocumentTitleChanged(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_DocumentTitleChanged(This,eventHandler,token) ) + +#define ICoreWebView2_remove_DocumentTitleChanged(This,token) \ + ( (This)->lpVtbl -> remove_DocumentTitleChanged(This,token) ) + +#define ICoreWebView2_get_DocumentTitle(This,title) \ + ( (This)->lpVtbl -> get_DocumentTitle(This,title) ) + +#define ICoreWebView2_AddHostObjectToScript(This,name,object) \ + ( (This)->lpVtbl -> AddHostObjectToScript(This,name,object) ) + +#define ICoreWebView2_RemoveHostObjectFromScript(This,name) \ + ( (This)->lpVtbl -> RemoveHostObjectFromScript(This,name) ) + +#define ICoreWebView2_OpenDevToolsWindow(This) \ + ( (This)->lpVtbl -> OpenDevToolsWindow(This) ) + +#define ICoreWebView2_add_ContainsFullScreenElementChanged(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_ContainsFullScreenElementChanged(This,eventHandler,token) ) + +#define ICoreWebView2_remove_ContainsFullScreenElementChanged(This,token) \ + ( (This)->lpVtbl -> remove_ContainsFullScreenElementChanged(This,token) ) + +#define ICoreWebView2_get_ContainsFullScreenElement(This,containsFullScreenElement) \ + ( (This)->lpVtbl -> get_ContainsFullScreenElement(This,containsFullScreenElement) ) + +#define ICoreWebView2_add_WebResourceRequested(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_WebResourceRequested(This,eventHandler,token) ) + +#define ICoreWebView2_remove_WebResourceRequested(This,token) \ + ( (This)->lpVtbl -> remove_WebResourceRequested(This,token) ) + +#define ICoreWebView2_AddWebResourceRequestedFilter(This,uri,resourceContext) \ + ( (This)->lpVtbl -> AddWebResourceRequestedFilter(This,uri,resourceContext) ) + +#define ICoreWebView2_RemoveWebResourceRequestedFilter(This,uri,resourceContext) \ + ( (This)->lpVtbl -> RemoveWebResourceRequestedFilter(This,uri,resourceContext) ) + +#define ICoreWebView2_add_WindowCloseRequested(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_WindowCloseRequested(This,eventHandler,token) ) + +#define ICoreWebView2_remove_WindowCloseRequested(This,token) \ + ( (This)->lpVtbl -> remove_WindowCloseRequested(This,token) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2_2_INTERFACE_DEFINED__ +#define __ICoreWebView2_2_INTERFACE_DEFINED__ + +/* interface ICoreWebView2_2 */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2_2 = {0x9E8F0CF8,0xE670,0x4B5E,{0xB2,0xBC,0x73,0xE0,0x61,0xE3,0x18,0x4C}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("9E8F0CF8-E670-4B5E-B2BC-73E061E3184C") + ICoreWebView2_2 : public ICoreWebView2 + { + public: + virtual HRESULT STDMETHODCALLTYPE add_WebResourceResponseReceived( + /* [in] */ ICoreWebView2WebResourceResponseReceivedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token) = 0; + + virtual HRESULT STDMETHODCALLTYPE remove_WebResourceResponseReceived( + /* [in] */ EventRegistrationToken token) = 0; + + virtual HRESULT STDMETHODCALLTYPE NavigateWithWebResourceRequest( + /* [in] */ ICoreWebView2WebResourceRequest *request) = 0; + + virtual HRESULT STDMETHODCALLTYPE add_DOMContentLoaded( + /* [in] */ ICoreWebView2DOMContentLoadedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token) = 0; + + virtual HRESULT STDMETHODCALLTYPE remove_DOMContentLoaded( + /* [in] */ EventRegistrationToken token) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_CookieManager( + /* [retval][out] */ ICoreWebView2CookieManager **cookieManager) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Environment( + /* [retval][out] */ ICoreWebView2Environment **environment) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2_2Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2_2 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2_2 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2_2 * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Settings )( + ICoreWebView2_2 * This, + /* [retval][out] */ ICoreWebView2Settings **settings); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Source )( + ICoreWebView2_2 * This, + /* [retval][out] */ LPWSTR *uri); + + HRESULT ( STDMETHODCALLTYPE *Navigate )( + ICoreWebView2_2 * This, + /* [in] */ LPCWSTR uri); + + HRESULT ( STDMETHODCALLTYPE *NavigateToString )( + ICoreWebView2_2 * This, + /* [in] */ LPCWSTR htmlContent); + + HRESULT ( STDMETHODCALLTYPE *add_NavigationStarting )( + ICoreWebView2_2 * This, + /* [in] */ ICoreWebView2NavigationStartingEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_NavigationStarting )( + ICoreWebView2_2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_ContentLoading )( + ICoreWebView2_2 * This, + /* [in] */ ICoreWebView2ContentLoadingEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_ContentLoading )( + ICoreWebView2_2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_SourceChanged )( + ICoreWebView2_2 * This, + /* [in] */ ICoreWebView2SourceChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_SourceChanged )( + ICoreWebView2_2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_HistoryChanged )( + ICoreWebView2_2 * This, + /* [in] */ ICoreWebView2HistoryChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_HistoryChanged )( + ICoreWebView2_2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_NavigationCompleted )( + ICoreWebView2_2 * This, + /* [in] */ ICoreWebView2NavigationCompletedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_NavigationCompleted )( + ICoreWebView2_2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_FrameNavigationStarting )( + ICoreWebView2_2 * This, + /* [in] */ ICoreWebView2NavigationStartingEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_FrameNavigationStarting )( + ICoreWebView2_2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_FrameNavigationCompleted )( + ICoreWebView2_2 * This, + /* [in] */ ICoreWebView2NavigationCompletedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_FrameNavigationCompleted )( + ICoreWebView2_2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_ScriptDialogOpening )( + ICoreWebView2_2 * This, + /* [in] */ ICoreWebView2ScriptDialogOpeningEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_ScriptDialogOpening )( + ICoreWebView2_2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_PermissionRequested )( + ICoreWebView2_2 * This, + /* [in] */ ICoreWebView2PermissionRequestedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_PermissionRequested )( + ICoreWebView2_2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_ProcessFailed )( + ICoreWebView2_2 * This, + /* [in] */ ICoreWebView2ProcessFailedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_ProcessFailed )( + ICoreWebView2_2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *AddScriptToExecuteOnDocumentCreated )( + ICoreWebView2_2 * This, + /* [in] */ LPCWSTR javaScript, + /* [in] */ ICoreWebView2AddScriptToExecuteOnDocumentCreatedCompletedHandler *handler); + + HRESULT ( STDMETHODCALLTYPE *RemoveScriptToExecuteOnDocumentCreated )( + ICoreWebView2_2 * This, + /* [in] */ LPCWSTR id); + + HRESULT ( STDMETHODCALLTYPE *ExecuteScript )( + ICoreWebView2_2 * This, + /* [in] */ LPCWSTR javaScript, + /* [in] */ ICoreWebView2ExecuteScriptCompletedHandler *handler); + + HRESULT ( STDMETHODCALLTYPE *CapturePreview )( + ICoreWebView2_2 * This, + /* [in] */ COREWEBVIEW2_CAPTURE_PREVIEW_IMAGE_FORMAT imageFormat, + /* [in] */ IStream *imageStream, + /* [in] */ ICoreWebView2CapturePreviewCompletedHandler *handler); + + HRESULT ( STDMETHODCALLTYPE *Reload )( + ICoreWebView2_2 * This); + + HRESULT ( STDMETHODCALLTYPE *PostWebMessageAsJson )( + ICoreWebView2_2 * This, + /* [in] */ LPCWSTR webMessageAsJson); + + HRESULT ( STDMETHODCALLTYPE *PostWebMessageAsString )( + ICoreWebView2_2 * This, + /* [in] */ LPCWSTR webMessageAsString); + + HRESULT ( STDMETHODCALLTYPE *add_WebMessageReceived )( + ICoreWebView2_2 * This, + /* [in] */ ICoreWebView2WebMessageReceivedEventHandler *handler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_WebMessageReceived )( + ICoreWebView2_2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *CallDevToolsProtocolMethod )( + ICoreWebView2_2 * This, + /* [in] */ LPCWSTR methodName, + /* [in] */ LPCWSTR parametersAsJson, + /* [in] */ ICoreWebView2CallDevToolsProtocolMethodCompletedHandler *handler); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_BrowserProcessId )( + ICoreWebView2_2 * This, + /* [retval][out] */ UINT32 *value); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_CanGoBack )( + ICoreWebView2_2 * This, + /* [retval][out] */ BOOL *canGoBack); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_CanGoForward )( + ICoreWebView2_2 * This, + /* [retval][out] */ BOOL *canGoForward); + + HRESULT ( STDMETHODCALLTYPE *GoBack )( + ICoreWebView2_2 * This); + + HRESULT ( STDMETHODCALLTYPE *GoForward )( + ICoreWebView2_2 * This); + + HRESULT ( STDMETHODCALLTYPE *GetDevToolsProtocolEventReceiver )( + ICoreWebView2_2 * This, + /* [in] */ LPCWSTR eventName, + /* [retval][out] */ ICoreWebView2DevToolsProtocolEventReceiver **receiver); + + HRESULT ( STDMETHODCALLTYPE *Stop )( + ICoreWebView2_2 * This); + + HRESULT ( STDMETHODCALLTYPE *add_NewWindowRequested )( + ICoreWebView2_2 * This, + /* [in] */ ICoreWebView2NewWindowRequestedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_NewWindowRequested )( + ICoreWebView2_2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_DocumentTitleChanged )( + ICoreWebView2_2 * This, + /* [in] */ ICoreWebView2DocumentTitleChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_DocumentTitleChanged )( + ICoreWebView2_2 * This, + /* [in] */ EventRegistrationToken token); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_DocumentTitle )( + ICoreWebView2_2 * This, + /* [retval][out] */ LPWSTR *title); + + HRESULT ( STDMETHODCALLTYPE *AddHostObjectToScript )( + ICoreWebView2_2 * This, + /* [in] */ LPCWSTR name, + /* [in] */ VARIANT *object); + + HRESULT ( STDMETHODCALLTYPE *RemoveHostObjectFromScript )( + ICoreWebView2_2 * This, + /* [in] */ LPCWSTR name); + + HRESULT ( STDMETHODCALLTYPE *OpenDevToolsWindow )( + ICoreWebView2_2 * This); + + HRESULT ( STDMETHODCALLTYPE *add_ContainsFullScreenElementChanged )( + ICoreWebView2_2 * This, + /* [in] */ ICoreWebView2ContainsFullScreenElementChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_ContainsFullScreenElementChanged )( + ICoreWebView2_2 * This, + /* [in] */ EventRegistrationToken token); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_ContainsFullScreenElement )( + ICoreWebView2_2 * This, + /* [retval][out] */ BOOL *containsFullScreenElement); + + HRESULT ( STDMETHODCALLTYPE *add_WebResourceRequested )( + ICoreWebView2_2 * This, + /* [in] */ ICoreWebView2WebResourceRequestedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_WebResourceRequested )( + ICoreWebView2_2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *AddWebResourceRequestedFilter )( + ICoreWebView2_2 * This, + /* [in] */ const LPCWSTR uri, + /* [in] */ const COREWEBVIEW2_WEB_RESOURCE_CONTEXT resourceContext); + + HRESULT ( STDMETHODCALLTYPE *RemoveWebResourceRequestedFilter )( + ICoreWebView2_2 * This, + /* [in] */ const LPCWSTR uri, + /* [in] */ const COREWEBVIEW2_WEB_RESOURCE_CONTEXT resourceContext); + + HRESULT ( STDMETHODCALLTYPE *add_WindowCloseRequested )( + ICoreWebView2_2 * This, + /* [in] */ ICoreWebView2WindowCloseRequestedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_WindowCloseRequested )( + ICoreWebView2_2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_WebResourceResponseReceived )( + ICoreWebView2_2 * This, + /* [in] */ ICoreWebView2WebResourceResponseReceivedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_WebResourceResponseReceived )( + ICoreWebView2_2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *NavigateWithWebResourceRequest )( + ICoreWebView2_2 * This, + /* [in] */ ICoreWebView2WebResourceRequest *request); + + HRESULT ( STDMETHODCALLTYPE *add_DOMContentLoaded )( + ICoreWebView2_2 * This, + /* [in] */ ICoreWebView2DOMContentLoadedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_DOMContentLoaded )( + ICoreWebView2_2 * This, + /* [in] */ EventRegistrationToken token); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_CookieManager )( + ICoreWebView2_2 * This, + /* [retval][out] */ ICoreWebView2CookieManager **cookieManager); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Environment )( + ICoreWebView2_2 * This, + /* [retval][out] */ ICoreWebView2Environment **environment); + + END_INTERFACE + } ICoreWebView2_2Vtbl; + + interface ICoreWebView2_2 + { + CONST_VTBL struct ICoreWebView2_2Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2_2_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2_2_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2_2_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2_2_get_Settings(This,settings) \ + ( (This)->lpVtbl -> get_Settings(This,settings) ) + +#define ICoreWebView2_2_get_Source(This,uri) \ + ( (This)->lpVtbl -> get_Source(This,uri) ) + +#define ICoreWebView2_2_Navigate(This,uri) \ + ( (This)->lpVtbl -> Navigate(This,uri) ) + +#define ICoreWebView2_2_NavigateToString(This,htmlContent) \ + ( (This)->lpVtbl -> NavigateToString(This,htmlContent) ) + +#define ICoreWebView2_2_add_NavigationStarting(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_NavigationStarting(This,eventHandler,token) ) + +#define ICoreWebView2_2_remove_NavigationStarting(This,token) \ + ( (This)->lpVtbl -> remove_NavigationStarting(This,token) ) + +#define ICoreWebView2_2_add_ContentLoading(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_ContentLoading(This,eventHandler,token) ) + +#define ICoreWebView2_2_remove_ContentLoading(This,token) \ + ( (This)->lpVtbl -> remove_ContentLoading(This,token) ) + +#define ICoreWebView2_2_add_SourceChanged(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_SourceChanged(This,eventHandler,token) ) + +#define ICoreWebView2_2_remove_SourceChanged(This,token) \ + ( (This)->lpVtbl -> remove_SourceChanged(This,token) ) + +#define ICoreWebView2_2_add_HistoryChanged(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_HistoryChanged(This,eventHandler,token) ) + +#define ICoreWebView2_2_remove_HistoryChanged(This,token) \ + ( (This)->lpVtbl -> remove_HistoryChanged(This,token) ) + +#define ICoreWebView2_2_add_NavigationCompleted(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_NavigationCompleted(This,eventHandler,token) ) + +#define ICoreWebView2_2_remove_NavigationCompleted(This,token) \ + ( (This)->lpVtbl -> remove_NavigationCompleted(This,token) ) + +#define ICoreWebView2_2_add_FrameNavigationStarting(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_FrameNavigationStarting(This,eventHandler,token) ) + +#define ICoreWebView2_2_remove_FrameNavigationStarting(This,token) \ + ( (This)->lpVtbl -> remove_FrameNavigationStarting(This,token) ) + +#define ICoreWebView2_2_add_FrameNavigationCompleted(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_FrameNavigationCompleted(This,eventHandler,token) ) + +#define ICoreWebView2_2_remove_FrameNavigationCompleted(This,token) \ + ( (This)->lpVtbl -> remove_FrameNavigationCompleted(This,token) ) + +#define ICoreWebView2_2_add_ScriptDialogOpening(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_ScriptDialogOpening(This,eventHandler,token) ) + +#define ICoreWebView2_2_remove_ScriptDialogOpening(This,token) \ + ( (This)->lpVtbl -> remove_ScriptDialogOpening(This,token) ) + +#define ICoreWebView2_2_add_PermissionRequested(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_PermissionRequested(This,eventHandler,token) ) + +#define ICoreWebView2_2_remove_PermissionRequested(This,token) \ + ( (This)->lpVtbl -> remove_PermissionRequested(This,token) ) + +#define ICoreWebView2_2_add_ProcessFailed(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_ProcessFailed(This,eventHandler,token) ) + +#define ICoreWebView2_2_remove_ProcessFailed(This,token) \ + ( (This)->lpVtbl -> remove_ProcessFailed(This,token) ) + +#define ICoreWebView2_2_AddScriptToExecuteOnDocumentCreated(This,javaScript,handler) \ + ( (This)->lpVtbl -> AddScriptToExecuteOnDocumentCreated(This,javaScript,handler) ) + +#define ICoreWebView2_2_RemoveScriptToExecuteOnDocumentCreated(This,id) \ + ( (This)->lpVtbl -> RemoveScriptToExecuteOnDocumentCreated(This,id) ) + +#define ICoreWebView2_2_ExecuteScript(This,javaScript,handler) \ + ( (This)->lpVtbl -> ExecuteScript(This,javaScript,handler) ) + +#define ICoreWebView2_2_CapturePreview(This,imageFormat,imageStream,handler) \ + ( (This)->lpVtbl -> CapturePreview(This,imageFormat,imageStream,handler) ) + +#define ICoreWebView2_2_Reload(This) \ + ( (This)->lpVtbl -> Reload(This) ) + +#define ICoreWebView2_2_PostWebMessageAsJson(This,webMessageAsJson) \ + ( (This)->lpVtbl -> PostWebMessageAsJson(This,webMessageAsJson) ) + +#define ICoreWebView2_2_PostWebMessageAsString(This,webMessageAsString) \ + ( (This)->lpVtbl -> PostWebMessageAsString(This,webMessageAsString) ) + +#define ICoreWebView2_2_add_WebMessageReceived(This,handler,token) \ + ( (This)->lpVtbl -> add_WebMessageReceived(This,handler,token) ) + +#define ICoreWebView2_2_remove_WebMessageReceived(This,token) \ + ( (This)->lpVtbl -> remove_WebMessageReceived(This,token) ) + +#define ICoreWebView2_2_CallDevToolsProtocolMethod(This,methodName,parametersAsJson,handler) \ + ( (This)->lpVtbl -> CallDevToolsProtocolMethod(This,methodName,parametersAsJson,handler) ) + +#define ICoreWebView2_2_get_BrowserProcessId(This,value) \ + ( (This)->lpVtbl -> get_BrowserProcessId(This,value) ) + +#define ICoreWebView2_2_get_CanGoBack(This,canGoBack) \ + ( (This)->lpVtbl -> get_CanGoBack(This,canGoBack) ) + +#define ICoreWebView2_2_get_CanGoForward(This,canGoForward) \ + ( (This)->lpVtbl -> get_CanGoForward(This,canGoForward) ) + +#define ICoreWebView2_2_GoBack(This) \ + ( (This)->lpVtbl -> GoBack(This) ) + +#define ICoreWebView2_2_GoForward(This) \ + ( (This)->lpVtbl -> GoForward(This) ) + +#define ICoreWebView2_2_GetDevToolsProtocolEventReceiver(This,eventName,receiver) \ + ( (This)->lpVtbl -> GetDevToolsProtocolEventReceiver(This,eventName,receiver) ) + +#define ICoreWebView2_2_Stop(This) \ + ( (This)->lpVtbl -> Stop(This) ) + +#define ICoreWebView2_2_add_NewWindowRequested(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_NewWindowRequested(This,eventHandler,token) ) + +#define ICoreWebView2_2_remove_NewWindowRequested(This,token) \ + ( (This)->lpVtbl -> remove_NewWindowRequested(This,token) ) + +#define ICoreWebView2_2_add_DocumentTitleChanged(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_DocumentTitleChanged(This,eventHandler,token) ) + +#define ICoreWebView2_2_remove_DocumentTitleChanged(This,token) \ + ( (This)->lpVtbl -> remove_DocumentTitleChanged(This,token) ) + +#define ICoreWebView2_2_get_DocumentTitle(This,title) \ + ( (This)->lpVtbl -> get_DocumentTitle(This,title) ) + +#define ICoreWebView2_2_AddHostObjectToScript(This,name,object) \ + ( (This)->lpVtbl -> AddHostObjectToScript(This,name,object) ) + +#define ICoreWebView2_2_RemoveHostObjectFromScript(This,name) \ + ( (This)->lpVtbl -> RemoveHostObjectFromScript(This,name) ) + +#define ICoreWebView2_2_OpenDevToolsWindow(This) \ + ( (This)->lpVtbl -> OpenDevToolsWindow(This) ) + +#define ICoreWebView2_2_add_ContainsFullScreenElementChanged(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_ContainsFullScreenElementChanged(This,eventHandler,token) ) + +#define ICoreWebView2_2_remove_ContainsFullScreenElementChanged(This,token) \ + ( (This)->lpVtbl -> remove_ContainsFullScreenElementChanged(This,token) ) + +#define ICoreWebView2_2_get_ContainsFullScreenElement(This,containsFullScreenElement) \ + ( (This)->lpVtbl -> get_ContainsFullScreenElement(This,containsFullScreenElement) ) + +#define ICoreWebView2_2_add_WebResourceRequested(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_WebResourceRequested(This,eventHandler,token) ) + +#define ICoreWebView2_2_remove_WebResourceRequested(This,token) \ + ( (This)->lpVtbl -> remove_WebResourceRequested(This,token) ) + +#define ICoreWebView2_2_AddWebResourceRequestedFilter(This,uri,resourceContext) \ + ( (This)->lpVtbl -> AddWebResourceRequestedFilter(This,uri,resourceContext) ) + +#define ICoreWebView2_2_RemoveWebResourceRequestedFilter(This,uri,resourceContext) \ + ( (This)->lpVtbl -> RemoveWebResourceRequestedFilter(This,uri,resourceContext) ) + +#define ICoreWebView2_2_add_WindowCloseRequested(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_WindowCloseRequested(This,eventHandler,token) ) + +#define ICoreWebView2_2_remove_WindowCloseRequested(This,token) \ + ( (This)->lpVtbl -> remove_WindowCloseRequested(This,token) ) + + +#define ICoreWebView2_2_add_WebResourceResponseReceived(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_WebResourceResponseReceived(This,eventHandler,token) ) + +#define ICoreWebView2_2_remove_WebResourceResponseReceived(This,token) \ + ( (This)->lpVtbl -> remove_WebResourceResponseReceived(This,token) ) + +#define ICoreWebView2_2_NavigateWithWebResourceRequest(This,request) \ + ( (This)->lpVtbl -> NavigateWithWebResourceRequest(This,request) ) + +#define ICoreWebView2_2_add_DOMContentLoaded(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_DOMContentLoaded(This,eventHandler,token) ) + +#define ICoreWebView2_2_remove_DOMContentLoaded(This,token) \ + ( (This)->lpVtbl -> remove_DOMContentLoaded(This,token) ) + +#define ICoreWebView2_2_get_CookieManager(This,cookieManager) \ + ( (This)->lpVtbl -> get_CookieManager(This,cookieManager) ) + +#define ICoreWebView2_2_get_Environment(This,environment) \ + ( (This)->lpVtbl -> get_Environment(This,environment) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2_2_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2_3_INTERFACE_DEFINED__ +#define __ICoreWebView2_3_INTERFACE_DEFINED__ + +/* interface ICoreWebView2_3 */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2_3 = {0xA0D6DF20,0x3B92,0x416D,{0xAA,0x0C,0x43,0x7A,0x9C,0x72,0x78,0x57}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("A0D6DF20-3B92-416D-AA0C-437A9C727857") + ICoreWebView2_3 : public ICoreWebView2_2 + { + public: + virtual HRESULT STDMETHODCALLTYPE TrySuspend( + /* [in] */ ICoreWebView2TrySuspendCompletedHandler *handler) = 0; + + virtual HRESULT STDMETHODCALLTYPE Resume( void) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_IsSuspended( + /* [retval][out] */ BOOL *isSuspended) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetVirtualHostNameToFolderMapping( + /* [in] */ LPCWSTR hostName, + /* [in] */ LPCWSTR folderPath, + /* [in] */ COREWEBVIEW2_HOST_RESOURCE_ACCESS_KIND accessKind) = 0; + + virtual HRESULT STDMETHODCALLTYPE ClearVirtualHostNameToFolderMapping( + /* [in] */ LPCWSTR hostName) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2_3Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2_3 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2_3 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2_3 * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Settings )( + ICoreWebView2_3 * This, + /* [retval][out] */ ICoreWebView2Settings **settings); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Source )( + ICoreWebView2_3 * This, + /* [retval][out] */ LPWSTR *uri); + + HRESULT ( STDMETHODCALLTYPE *Navigate )( + ICoreWebView2_3 * This, + /* [in] */ LPCWSTR uri); + + HRESULT ( STDMETHODCALLTYPE *NavigateToString )( + ICoreWebView2_3 * This, + /* [in] */ LPCWSTR htmlContent); + + HRESULT ( STDMETHODCALLTYPE *add_NavigationStarting )( + ICoreWebView2_3 * This, + /* [in] */ ICoreWebView2NavigationStartingEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_NavigationStarting )( + ICoreWebView2_3 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_ContentLoading )( + ICoreWebView2_3 * This, + /* [in] */ ICoreWebView2ContentLoadingEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_ContentLoading )( + ICoreWebView2_3 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_SourceChanged )( + ICoreWebView2_3 * This, + /* [in] */ ICoreWebView2SourceChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_SourceChanged )( + ICoreWebView2_3 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_HistoryChanged )( + ICoreWebView2_3 * This, + /* [in] */ ICoreWebView2HistoryChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_HistoryChanged )( + ICoreWebView2_3 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_NavigationCompleted )( + ICoreWebView2_3 * This, + /* [in] */ ICoreWebView2NavigationCompletedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_NavigationCompleted )( + ICoreWebView2_3 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_FrameNavigationStarting )( + ICoreWebView2_3 * This, + /* [in] */ ICoreWebView2NavigationStartingEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_FrameNavigationStarting )( + ICoreWebView2_3 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_FrameNavigationCompleted )( + ICoreWebView2_3 * This, + /* [in] */ ICoreWebView2NavigationCompletedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_FrameNavigationCompleted )( + ICoreWebView2_3 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_ScriptDialogOpening )( + ICoreWebView2_3 * This, + /* [in] */ ICoreWebView2ScriptDialogOpeningEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_ScriptDialogOpening )( + ICoreWebView2_3 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_PermissionRequested )( + ICoreWebView2_3 * This, + /* [in] */ ICoreWebView2PermissionRequestedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_PermissionRequested )( + ICoreWebView2_3 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_ProcessFailed )( + ICoreWebView2_3 * This, + /* [in] */ ICoreWebView2ProcessFailedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_ProcessFailed )( + ICoreWebView2_3 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *AddScriptToExecuteOnDocumentCreated )( + ICoreWebView2_3 * This, + /* [in] */ LPCWSTR javaScript, + /* [in] */ ICoreWebView2AddScriptToExecuteOnDocumentCreatedCompletedHandler *handler); + + HRESULT ( STDMETHODCALLTYPE *RemoveScriptToExecuteOnDocumentCreated )( + ICoreWebView2_3 * This, + /* [in] */ LPCWSTR id); + + HRESULT ( STDMETHODCALLTYPE *ExecuteScript )( + ICoreWebView2_3 * This, + /* [in] */ LPCWSTR javaScript, + /* [in] */ ICoreWebView2ExecuteScriptCompletedHandler *handler); + + HRESULT ( STDMETHODCALLTYPE *CapturePreview )( + ICoreWebView2_3 * This, + /* [in] */ COREWEBVIEW2_CAPTURE_PREVIEW_IMAGE_FORMAT imageFormat, + /* [in] */ IStream *imageStream, + /* [in] */ ICoreWebView2CapturePreviewCompletedHandler *handler); + + HRESULT ( STDMETHODCALLTYPE *Reload )( + ICoreWebView2_3 * This); + + HRESULT ( STDMETHODCALLTYPE *PostWebMessageAsJson )( + ICoreWebView2_3 * This, + /* [in] */ LPCWSTR webMessageAsJson); + + HRESULT ( STDMETHODCALLTYPE *PostWebMessageAsString )( + ICoreWebView2_3 * This, + /* [in] */ LPCWSTR webMessageAsString); + + HRESULT ( STDMETHODCALLTYPE *add_WebMessageReceived )( + ICoreWebView2_3 * This, + /* [in] */ ICoreWebView2WebMessageReceivedEventHandler *handler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_WebMessageReceived )( + ICoreWebView2_3 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *CallDevToolsProtocolMethod )( + ICoreWebView2_3 * This, + /* [in] */ LPCWSTR methodName, + /* [in] */ LPCWSTR parametersAsJson, + /* [in] */ ICoreWebView2CallDevToolsProtocolMethodCompletedHandler *handler); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_BrowserProcessId )( + ICoreWebView2_3 * This, + /* [retval][out] */ UINT32 *value); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_CanGoBack )( + ICoreWebView2_3 * This, + /* [retval][out] */ BOOL *canGoBack); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_CanGoForward )( + ICoreWebView2_3 * This, + /* [retval][out] */ BOOL *canGoForward); + + HRESULT ( STDMETHODCALLTYPE *GoBack )( + ICoreWebView2_3 * This); + + HRESULT ( STDMETHODCALLTYPE *GoForward )( + ICoreWebView2_3 * This); + + HRESULT ( STDMETHODCALLTYPE *GetDevToolsProtocolEventReceiver )( + ICoreWebView2_3 * This, + /* [in] */ LPCWSTR eventName, + /* [retval][out] */ ICoreWebView2DevToolsProtocolEventReceiver **receiver); + + HRESULT ( STDMETHODCALLTYPE *Stop )( + ICoreWebView2_3 * This); + + HRESULT ( STDMETHODCALLTYPE *add_NewWindowRequested )( + ICoreWebView2_3 * This, + /* [in] */ ICoreWebView2NewWindowRequestedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_NewWindowRequested )( + ICoreWebView2_3 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_DocumentTitleChanged )( + ICoreWebView2_3 * This, + /* [in] */ ICoreWebView2DocumentTitleChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_DocumentTitleChanged )( + ICoreWebView2_3 * This, + /* [in] */ EventRegistrationToken token); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_DocumentTitle )( + ICoreWebView2_3 * This, + /* [retval][out] */ LPWSTR *title); + + HRESULT ( STDMETHODCALLTYPE *AddHostObjectToScript )( + ICoreWebView2_3 * This, + /* [in] */ LPCWSTR name, + /* [in] */ VARIANT *object); + + HRESULT ( STDMETHODCALLTYPE *RemoveHostObjectFromScript )( + ICoreWebView2_3 * This, + /* [in] */ LPCWSTR name); + + HRESULT ( STDMETHODCALLTYPE *OpenDevToolsWindow )( + ICoreWebView2_3 * This); + + HRESULT ( STDMETHODCALLTYPE *add_ContainsFullScreenElementChanged )( + ICoreWebView2_3 * This, + /* [in] */ ICoreWebView2ContainsFullScreenElementChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_ContainsFullScreenElementChanged )( + ICoreWebView2_3 * This, + /* [in] */ EventRegistrationToken token); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_ContainsFullScreenElement )( + ICoreWebView2_3 * This, + /* [retval][out] */ BOOL *containsFullScreenElement); + + HRESULT ( STDMETHODCALLTYPE *add_WebResourceRequested )( + ICoreWebView2_3 * This, + /* [in] */ ICoreWebView2WebResourceRequestedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_WebResourceRequested )( + ICoreWebView2_3 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *AddWebResourceRequestedFilter )( + ICoreWebView2_3 * This, + /* [in] */ const LPCWSTR uri, + /* [in] */ const COREWEBVIEW2_WEB_RESOURCE_CONTEXT resourceContext); + + HRESULT ( STDMETHODCALLTYPE *RemoveWebResourceRequestedFilter )( + ICoreWebView2_3 * This, + /* [in] */ const LPCWSTR uri, + /* [in] */ const COREWEBVIEW2_WEB_RESOURCE_CONTEXT resourceContext); + + HRESULT ( STDMETHODCALLTYPE *add_WindowCloseRequested )( + ICoreWebView2_3 * This, + /* [in] */ ICoreWebView2WindowCloseRequestedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_WindowCloseRequested )( + ICoreWebView2_3 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_WebResourceResponseReceived )( + ICoreWebView2_3 * This, + /* [in] */ ICoreWebView2WebResourceResponseReceivedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_WebResourceResponseReceived )( + ICoreWebView2_3 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *NavigateWithWebResourceRequest )( + ICoreWebView2_3 * This, + /* [in] */ ICoreWebView2WebResourceRequest *request); + + HRESULT ( STDMETHODCALLTYPE *add_DOMContentLoaded )( + ICoreWebView2_3 * This, + /* [in] */ ICoreWebView2DOMContentLoadedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_DOMContentLoaded )( + ICoreWebView2_3 * This, + /* [in] */ EventRegistrationToken token); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_CookieManager )( + ICoreWebView2_3 * This, + /* [retval][out] */ ICoreWebView2CookieManager **cookieManager); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Environment )( + ICoreWebView2_3 * This, + /* [retval][out] */ ICoreWebView2Environment **environment); + + HRESULT ( STDMETHODCALLTYPE *TrySuspend )( + ICoreWebView2_3 * This, + /* [in] */ ICoreWebView2TrySuspendCompletedHandler *handler); + + HRESULT ( STDMETHODCALLTYPE *Resume )( + ICoreWebView2_3 * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_IsSuspended )( + ICoreWebView2_3 * This, + /* [retval][out] */ BOOL *isSuspended); + + HRESULT ( STDMETHODCALLTYPE *SetVirtualHostNameToFolderMapping )( + ICoreWebView2_3 * This, + /* [in] */ LPCWSTR hostName, + /* [in] */ LPCWSTR folderPath, + /* [in] */ COREWEBVIEW2_HOST_RESOURCE_ACCESS_KIND accessKind); + + HRESULT ( STDMETHODCALLTYPE *ClearVirtualHostNameToFolderMapping )( + ICoreWebView2_3 * This, + /* [in] */ LPCWSTR hostName); + + END_INTERFACE + } ICoreWebView2_3Vtbl; + + interface ICoreWebView2_3 + { + CONST_VTBL struct ICoreWebView2_3Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2_3_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2_3_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2_3_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2_3_get_Settings(This,settings) \ + ( (This)->lpVtbl -> get_Settings(This,settings) ) + +#define ICoreWebView2_3_get_Source(This,uri) \ + ( (This)->lpVtbl -> get_Source(This,uri) ) + +#define ICoreWebView2_3_Navigate(This,uri) \ + ( (This)->lpVtbl -> Navigate(This,uri) ) + +#define ICoreWebView2_3_NavigateToString(This,htmlContent) \ + ( (This)->lpVtbl -> NavigateToString(This,htmlContent) ) + +#define ICoreWebView2_3_add_NavigationStarting(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_NavigationStarting(This,eventHandler,token) ) + +#define ICoreWebView2_3_remove_NavigationStarting(This,token) \ + ( (This)->lpVtbl -> remove_NavigationStarting(This,token) ) + +#define ICoreWebView2_3_add_ContentLoading(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_ContentLoading(This,eventHandler,token) ) + +#define ICoreWebView2_3_remove_ContentLoading(This,token) \ + ( (This)->lpVtbl -> remove_ContentLoading(This,token) ) + +#define ICoreWebView2_3_add_SourceChanged(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_SourceChanged(This,eventHandler,token) ) + +#define ICoreWebView2_3_remove_SourceChanged(This,token) \ + ( (This)->lpVtbl -> remove_SourceChanged(This,token) ) + +#define ICoreWebView2_3_add_HistoryChanged(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_HistoryChanged(This,eventHandler,token) ) + +#define ICoreWebView2_3_remove_HistoryChanged(This,token) \ + ( (This)->lpVtbl -> remove_HistoryChanged(This,token) ) + +#define ICoreWebView2_3_add_NavigationCompleted(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_NavigationCompleted(This,eventHandler,token) ) + +#define ICoreWebView2_3_remove_NavigationCompleted(This,token) \ + ( (This)->lpVtbl -> remove_NavigationCompleted(This,token) ) + +#define ICoreWebView2_3_add_FrameNavigationStarting(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_FrameNavigationStarting(This,eventHandler,token) ) + +#define ICoreWebView2_3_remove_FrameNavigationStarting(This,token) \ + ( (This)->lpVtbl -> remove_FrameNavigationStarting(This,token) ) + +#define ICoreWebView2_3_add_FrameNavigationCompleted(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_FrameNavigationCompleted(This,eventHandler,token) ) + +#define ICoreWebView2_3_remove_FrameNavigationCompleted(This,token) \ + ( (This)->lpVtbl -> remove_FrameNavigationCompleted(This,token) ) + +#define ICoreWebView2_3_add_ScriptDialogOpening(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_ScriptDialogOpening(This,eventHandler,token) ) + +#define ICoreWebView2_3_remove_ScriptDialogOpening(This,token) \ + ( (This)->lpVtbl -> remove_ScriptDialogOpening(This,token) ) + +#define ICoreWebView2_3_add_PermissionRequested(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_PermissionRequested(This,eventHandler,token) ) + +#define ICoreWebView2_3_remove_PermissionRequested(This,token) \ + ( (This)->lpVtbl -> remove_PermissionRequested(This,token) ) + +#define ICoreWebView2_3_add_ProcessFailed(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_ProcessFailed(This,eventHandler,token) ) + +#define ICoreWebView2_3_remove_ProcessFailed(This,token) \ + ( (This)->lpVtbl -> remove_ProcessFailed(This,token) ) + +#define ICoreWebView2_3_AddScriptToExecuteOnDocumentCreated(This,javaScript,handler) \ + ( (This)->lpVtbl -> AddScriptToExecuteOnDocumentCreated(This,javaScript,handler) ) + +#define ICoreWebView2_3_RemoveScriptToExecuteOnDocumentCreated(This,id) \ + ( (This)->lpVtbl -> RemoveScriptToExecuteOnDocumentCreated(This,id) ) + +#define ICoreWebView2_3_ExecuteScript(This,javaScript,handler) \ + ( (This)->lpVtbl -> ExecuteScript(This,javaScript,handler) ) + +#define ICoreWebView2_3_CapturePreview(This,imageFormat,imageStream,handler) \ + ( (This)->lpVtbl -> CapturePreview(This,imageFormat,imageStream,handler) ) + +#define ICoreWebView2_3_Reload(This) \ + ( (This)->lpVtbl -> Reload(This) ) + +#define ICoreWebView2_3_PostWebMessageAsJson(This,webMessageAsJson) \ + ( (This)->lpVtbl -> PostWebMessageAsJson(This,webMessageAsJson) ) + +#define ICoreWebView2_3_PostWebMessageAsString(This,webMessageAsString) \ + ( (This)->lpVtbl -> PostWebMessageAsString(This,webMessageAsString) ) + +#define ICoreWebView2_3_add_WebMessageReceived(This,handler,token) \ + ( (This)->lpVtbl -> add_WebMessageReceived(This,handler,token) ) + +#define ICoreWebView2_3_remove_WebMessageReceived(This,token) \ + ( (This)->lpVtbl -> remove_WebMessageReceived(This,token) ) + +#define ICoreWebView2_3_CallDevToolsProtocolMethod(This,methodName,parametersAsJson,handler) \ + ( (This)->lpVtbl -> CallDevToolsProtocolMethod(This,methodName,parametersAsJson,handler) ) + +#define ICoreWebView2_3_get_BrowserProcessId(This,value) \ + ( (This)->lpVtbl -> get_BrowserProcessId(This,value) ) + +#define ICoreWebView2_3_get_CanGoBack(This,canGoBack) \ + ( (This)->lpVtbl -> get_CanGoBack(This,canGoBack) ) + +#define ICoreWebView2_3_get_CanGoForward(This,canGoForward) \ + ( (This)->lpVtbl -> get_CanGoForward(This,canGoForward) ) + +#define ICoreWebView2_3_GoBack(This) \ + ( (This)->lpVtbl -> GoBack(This) ) + +#define ICoreWebView2_3_GoForward(This) \ + ( (This)->lpVtbl -> GoForward(This) ) + +#define ICoreWebView2_3_GetDevToolsProtocolEventReceiver(This,eventName,receiver) \ + ( (This)->lpVtbl -> GetDevToolsProtocolEventReceiver(This,eventName,receiver) ) + +#define ICoreWebView2_3_Stop(This) \ + ( (This)->lpVtbl -> Stop(This) ) + +#define ICoreWebView2_3_add_NewWindowRequested(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_NewWindowRequested(This,eventHandler,token) ) + +#define ICoreWebView2_3_remove_NewWindowRequested(This,token) \ + ( (This)->lpVtbl -> remove_NewWindowRequested(This,token) ) + +#define ICoreWebView2_3_add_DocumentTitleChanged(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_DocumentTitleChanged(This,eventHandler,token) ) + +#define ICoreWebView2_3_remove_DocumentTitleChanged(This,token) \ + ( (This)->lpVtbl -> remove_DocumentTitleChanged(This,token) ) + +#define ICoreWebView2_3_get_DocumentTitle(This,title) \ + ( (This)->lpVtbl -> get_DocumentTitle(This,title) ) + +#define ICoreWebView2_3_AddHostObjectToScript(This,name,object) \ + ( (This)->lpVtbl -> AddHostObjectToScript(This,name,object) ) + +#define ICoreWebView2_3_RemoveHostObjectFromScript(This,name) \ + ( (This)->lpVtbl -> RemoveHostObjectFromScript(This,name) ) + +#define ICoreWebView2_3_OpenDevToolsWindow(This) \ + ( (This)->lpVtbl -> OpenDevToolsWindow(This) ) + +#define ICoreWebView2_3_add_ContainsFullScreenElementChanged(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_ContainsFullScreenElementChanged(This,eventHandler,token) ) + +#define ICoreWebView2_3_remove_ContainsFullScreenElementChanged(This,token) \ + ( (This)->lpVtbl -> remove_ContainsFullScreenElementChanged(This,token) ) + +#define ICoreWebView2_3_get_ContainsFullScreenElement(This,containsFullScreenElement) \ + ( (This)->lpVtbl -> get_ContainsFullScreenElement(This,containsFullScreenElement) ) + +#define ICoreWebView2_3_add_WebResourceRequested(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_WebResourceRequested(This,eventHandler,token) ) + +#define ICoreWebView2_3_remove_WebResourceRequested(This,token) \ + ( (This)->lpVtbl -> remove_WebResourceRequested(This,token) ) + +#define ICoreWebView2_3_AddWebResourceRequestedFilter(This,uri,resourceContext) \ + ( (This)->lpVtbl -> AddWebResourceRequestedFilter(This,uri,resourceContext) ) + +#define ICoreWebView2_3_RemoveWebResourceRequestedFilter(This,uri,resourceContext) \ + ( (This)->lpVtbl -> RemoveWebResourceRequestedFilter(This,uri,resourceContext) ) + +#define ICoreWebView2_3_add_WindowCloseRequested(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_WindowCloseRequested(This,eventHandler,token) ) + +#define ICoreWebView2_3_remove_WindowCloseRequested(This,token) \ + ( (This)->lpVtbl -> remove_WindowCloseRequested(This,token) ) + + +#define ICoreWebView2_3_add_WebResourceResponseReceived(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_WebResourceResponseReceived(This,eventHandler,token) ) + +#define ICoreWebView2_3_remove_WebResourceResponseReceived(This,token) \ + ( (This)->lpVtbl -> remove_WebResourceResponseReceived(This,token) ) + +#define ICoreWebView2_3_NavigateWithWebResourceRequest(This,request) \ + ( (This)->lpVtbl -> NavigateWithWebResourceRequest(This,request) ) + +#define ICoreWebView2_3_add_DOMContentLoaded(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_DOMContentLoaded(This,eventHandler,token) ) + +#define ICoreWebView2_3_remove_DOMContentLoaded(This,token) \ + ( (This)->lpVtbl -> remove_DOMContentLoaded(This,token) ) + +#define ICoreWebView2_3_get_CookieManager(This,cookieManager) \ + ( (This)->lpVtbl -> get_CookieManager(This,cookieManager) ) + +#define ICoreWebView2_3_get_Environment(This,environment) \ + ( (This)->lpVtbl -> get_Environment(This,environment) ) + + +#define ICoreWebView2_3_TrySuspend(This,handler) \ + ( (This)->lpVtbl -> TrySuspend(This,handler) ) + +#define ICoreWebView2_3_Resume(This) \ + ( (This)->lpVtbl -> Resume(This) ) + +#define ICoreWebView2_3_get_IsSuspended(This,isSuspended) \ + ( (This)->lpVtbl -> get_IsSuspended(This,isSuspended) ) + +#define ICoreWebView2_3_SetVirtualHostNameToFolderMapping(This,hostName,folderPath,accessKind) \ + ( (This)->lpVtbl -> SetVirtualHostNameToFolderMapping(This,hostName,folderPath,accessKind) ) + +#define ICoreWebView2_3_ClearVirtualHostNameToFolderMapping(This,hostName) \ + ( (This)->lpVtbl -> ClearVirtualHostNameToFolderMapping(This,hostName) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2_3_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2CompositionController_INTERFACE_DEFINED__ +#define __ICoreWebView2CompositionController_INTERFACE_DEFINED__ + +/* interface ICoreWebView2CompositionController */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2CompositionController = {0x3df9b733,0xb9ae,0x4a15,{0x86,0xb4,0xeb,0x9e,0xe9,0x82,0x64,0x69}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("3df9b733-b9ae-4a15-86b4-eb9ee9826469") + ICoreWebView2CompositionController : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_RootVisualTarget( + /* [retval][out] */ IUnknown **target) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_RootVisualTarget( + /* [in] */ IUnknown *target) = 0; + + virtual HRESULT STDMETHODCALLTYPE SendMouseInput( + /* [in] */ COREWEBVIEW2_MOUSE_EVENT_KIND eventKind, + /* [in] */ COREWEBVIEW2_MOUSE_EVENT_VIRTUAL_KEYS virtualKeys, + /* [in] */ UINT32 mouseData, + /* [in] */ POINT point) = 0; + + virtual HRESULT STDMETHODCALLTYPE SendPointerInput( + /* [in] */ COREWEBVIEW2_POINTER_EVENT_KIND eventKind, + /* [in] */ ICoreWebView2PointerInfo *pointerInfo) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Cursor( + /* [retval][out] */ HCURSOR *cursor) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_SystemCursorId( + /* [retval][out] */ UINT32 *systemCursorId) = 0; + + virtual HRESULT STDMETHODCALLTYPE add_CursorChanged( + /* [in] */ ICoreWebView2CursorChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token) = 0; + + virtual HRESULT STDMETHODCALLTYPE remove_CursorChanged( + /* [in] */ EventRegistrationToken token) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2CompositionControllerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2CompositionController * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2CompositionController * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2CompositionController * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_RootVisualTarget )( + ICoreWebView2CompositionController * This, + /* [retval][out] */ IUnknown **target); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_RootVisualTarget )( + ICoreWebView2CompositionController * This, + /* [in] */ IUnknown *target); + + HRESULT ( STDMETHODCALLTYPE *SendMouseInput )( + ICoreWebView2CompositionController * This, + /* [in] */ COREWEBVIEW2_MOUSE_EVENT_KIND eventKind, + /* [in] */ COREWEBVIEW2_MOUSE_EVENT_VIRTUAL_KEYS virtualKeys, + /* [in] */ UINT32 mouseData, + /* [in] */ POINT point); + + HRESULT ( STDMETHODCALLTYPE *SendPointerInput )( + ICoreWebView2CompositionController * This, + /* [in] */ COREWEBVIEW2_POINTER_EVENT_KIND eventKind, + /* [in] */ ICoreWebView2PointerInfo *pointerInfo); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Cursor )( + ICoreWebView2CompositionController * This, + /* [retval][out] */ HCURSOR *cursor); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_SystemCursorId )( + ICoreWebView2CompositionController * This, + /* [retval][out] */ UINT32 *systemCursorId); + + HRESULT ( STDMETHODCALLTYPE *add_CursorChanged )( + ICoreWebView2CompositionController * This, + /* [in] */ ICoreWebView2CursorChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_CursorChanged )( + ICoreWebView2CompositionController * This, + /* [in] */ EventRegistrationToken token); + + END_INTERFACE + } ICoreWebView2CompositionControllerVtbl; + + interface ICoreWebView2CompositionController + { + CONST_VTBL struct ICoreWebView2CompositionControllerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2CompositionController_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2CompositionController_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2CompositionController_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2CompositionController_get_RootVisualTarget(This,target) \ + ( (This)->lpVtbl -> get_RootVisualTarget(This,target) ) + +#define ICoreWebView2CompositionController_put_RootVisualTarget(This,target) \ + ( (This)->lpVtbl -> put_RootVisualTarget(This,target) ) + +#define ICoreWebView2CompositionController_SendMouseInput(This,eventKind,virtualKeys,mouseData,point) \ + ( (This)->lpVtbl -> SendMouseInput(This,eventKind,virtualKeys,mouseData,point) ) + +#define ICoreWebView2CompositionController_SendPointerInput(This,eventKind,pointerInfo) \ + ( (This)->lpVtbl -> SendPointerInput(This,eventKind,pointerInfo) ) + +#define ICoreWebView2CompositionController_get_Cursor(This,cursor) \ + ( (This)->lpVtbl -> get_Cursor(This,cursor) ) + +#define ICoreWebView2CompositionController_get_SystemCursorId(This,systemCursorId) \ + ( (This)->lpVtbl -> get_SystemCursorId(This,systemCursorId) ) + +#define ICoreWebView2CompositionController_add_CursorChanged(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_CursorChanged(This,eventHandler,token) ) + +#define ICoreWebView2CompositionController_remove_CursorChanged(This,token) \ + ( (This)->lpVtbl -> remove_CursorChanged(This,token) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2CompositionController_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2CompositionController2_INTERFACE_DEFINED__ +#define __ICoreWebView2CompositionController2_INTERFACE_DEFINED__ + +/* interface ICoreWebView2CompositionController2 */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2CompositionController2 = {0x0b6a3d24,0x49cb,0x4806,{0xba,0x20,0xb5,0xe0,0x73,0x4a,0x7b,0x26}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("0b6a3d24-49cb-4806-ba20-b5e0734a7b26") + ICoreWebView2CompositionController2 : public ICoreWebView2CompositionController + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_UIAProvider( + /* [retval][out] */ IUnknown **provider) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2CompositionController2Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2CompositionController2 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2CompositionController2 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2CompositionController2 * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_RootVisualTarget )( + ICoreWebView2CompositionController2 * This, + /* [retval][out] */ IUnknown **target); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_RootVisualTarget )( + ICoreWebView2CompositionController2 * This, + /* [in] */ IUnknown *target); + + HRESULT ( STDMETHODCALLTYPE *SendMouseInput )( + ICoreWebView2CompositionController2 * This, + /* [in] */ COREWEBVIEW2_MOUSE_EVENT_KIND eventKind, + /* [in] */ COREWEBVIEW2_MOUSE_EVENT_VIRTUAL_KEYS virtualKeys, + /* [in] */ UINT32 mouseData, + /* [in] */ POINT point); + + HRESULT ( STDMETHODCALLTYPE *SendPointerInput )( + ICoreWebView2CompositionController2 * This, + /* [in] */ COREWEBVIEW2_POINTER_EVENT_KIND eventKind, + /* [in] */ ICoreWebView2PointerInfo *pointerInfo); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Cursor )( + ICoreWebView2CompositionController2 * This, + /* [retval][out] */ HCURSOR *cursor); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_SystemCursorId )( + ICoreWebView2CompositionController2 * This, + /* [retval][out] */ UINT32 *systemCursorId); + + HRESULT ( STDMETHODCALLTYPE *add_CursorChanged )( + ICoreWebView2CompositionController2 * This, + /* [in] */ ICoreWebView2CursorChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_CursorChanged )( + ICoreWebView2CompositionController2 * This, + /* [in] */ EventRegistrationToken token); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_UIAProvider )( + ICoreWebView2CompositionController2 * This, + /* [retval][out] */ IUnknown **provider); + + END_INTERFACE + } ICoreWebView2CompositionController2Vtbl; + + interface ICoreWebView2CompositionController2 + { + CONST_VTBL struct ICoreWebView2CompositionController2Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2CompositionController2_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2CompositionController2_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2CompositionController2_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2CompositionController2_get_RootVisualTarget(This,target) \ + ( (This)->lpVtbl -> get_RootVisualTarget(This,target) ) + +#define ICoreWebView2CompositionController2_put_RootVisualTarget(This,target) \ + ( (This)->lpVtbl -> put_RootVisualTarget(This,target) ) + +#define ICoreWebView2CompositionController2_SendMouseInput(This,eventKind,virtualKeys,mouseData,point) \ + ( (This)->lpVtbl -> SendMouseInput(This,eventKind,virtualKeys,mouseData,point) ) + +#define ICoreWebView2CompositionController2_SendPointerInput(This,eventKind,pointerInfo) \ + ( (This)->lpVtbl -> SendPointerInput(This,eventKind,pointerInfo) ) + +#define ICoreWebView2CompositionController2_get_Cursor(This,cursor) \ + ( (This)->lpVtbl -> get_Cursor(This,cursor) ) + +#define ICoreWebView2CompositionController2_get_SystemCursorId(This,systemCursorId) \ + ( (This)->lpVtbl -> get_SystemCursorId(This,systemCursorId) ) + +#define ICoreWebView2CompositionController2_add_CursorChanged(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_CursorChanged(This,eventHandler,token) ) + +#define ICoreWebView2CompositionController2_remove_CursorChanged(This,token) \ + ( (This)->lpVtbl -> remove_CursorChanged(This,token) ) + + +#define ICoreWebView2CompositionController2_get_UIAProvider(This,provider) \ + ( (This)->lpVtbl -> get_UIAProvider(This,provider) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2CompositionController2_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2Controller_INTERFACE_DEFINED__ +#define __ICoreWebView2Controller_INTERFACE_DEFINED__ + +/* interface ICoreWebView2Controller */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2Controller = {0x4d00c0d1,0x9434,0x4eb6,{0x80,0x78,0x86,0x97,0xa5,0x60,0x33,0x4f}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("4d00c0d1-9434-4eb6-8078-8697a560334f") + ICoreWebView2Controller : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_IsVisible( + /* [retval][out] */ BOOL *isVisible) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_IsVisible( + /* [in] */ BOOL isVisible) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Bounds( + /* [retval][out] */ RECT *bounds) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_Bounds( + /* [in] */ RECT bounds) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_ZoomFactor( + /* [retval][out] */ double *zoomFactor) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_ZoomFactor( + /* [in] */ double zoomFactor) = 0; + + virtual HRESULT STDMETHODCALLTYPE add_ZoomFactorChanged( + /* [in] */ ICoreWebView2ZoomFactorChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token) = 0; + + virtual HRESULT STDMETHODCALLTYPE remove_ZoomFactorChanged( + /* [in] */ EventRegistrationToken token) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetBoundsAndZoomFactor( + /* [in] */ RECT bounds, + /* [in] */ double zoomFactor) = 0; + + virtual HRESULT STDMETHODCALLTYPE MoveFocus( + /* [in] */ COREWEBVIEW2_MOVE_FOCUS_REASON reason) = 0; + + virtual HRESULT STDMETHODCALLTYPE add_MoveFocusRequested( + /* [in] */ ICoreWebView2MoveFocusRequestedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token) = 0; + + virtual HRESULT STDMETHODCALLTYPE remove_MoveFocusRequested( + /* [in] */ EventRegistrationToken token) = 0; + + virtual HRESULT STDMETHODCALLTYPE add_GotFocus( + /* [in] */ ICoreWebView2FocusChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token) = 0; + + virtual HRESULT STDMETHODCALLTYPE remove_GotFocus( + /* [in] */ EventRegistrationToken token) = 0; + + virtual HRESULT STDMETHODCALLTYPE add_LostFocus( + /* [in] */ ICoreWebView2FocusChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token) = 0; + + virtual HRESULT STDMETHODCALLTYPE remove_LostFocus( + /* [in] */ EventRegistrationToken token) = 0; + + virtual HRESULT STDMETHODCALLTYPE add_AcceleratorKeyPressed( + /* [in] */ ICoreWebView2AcceleratorKeyPressedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token) = 0; + + virtual HRESULT STDMETHODCALLTYPE remove_AcceleratorKeyPressed( + /* [in] */ EventRegistrationToken token) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_ParentWindow( + /* [retval][out] */ HWND *parentWindow) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_ParentWindow( + /* [in] */ HWND parentWindow) = 0; + + virtual HRESULT STDMETHODCALLTYPE NotifyParentWindowPositionChanged( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE Close( void) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_CoreWebView2( + /* [retval][out] */ ICoreWebView2 **coreWebView2) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2ControllerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2Controller * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2Controller * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2Controller * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_IsVisible )( + ICoreWebView2Controller * This, + /* [retval][out] */ BOOL *isVisible); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_IsVisible )( + ICoreWebView2Controller * This, + /* [in] */ BOOL isVisible); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Bounds )( + ICoreWebView2Controller * This, + /* [retval][out] */ RECT *bounds); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_Bounds )( + ICoreWebView2Controller * This, + /* [in] */ RECT bounds); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_ZoomFactor )( + ICoreWebView2Controller * This, + /* [retval][out] */ double *zoomFactor); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_ZoomFactor )( + ICoreWebView2Controller * This, + /* [in] */ double zoomFactor); + + HRESULT ( STDMETHODCALLTYPE *add_ZoomFactorChanged )( + ICoreWebView2Controller * This, + /* [in] */ ICoreWebView2ZoomFactorChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_ZoomFactorChanged )( + ICoreWebView2Controller * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *SetBoundsAndZoomFactor )( + ICoreWebView2Controller * This, + /* [in] */ RECT bounds, + /* [in] */ double zoomFactor); + + HRESULT ( STDMETHODCALLTYPE *MoveFocus )( + ICoreWebView2Controller * This, + /* [in] */ COREWEBVIEW2_MOVE_FOCUS_REASON reason); + + HRESULT ( STDMETHODCALLTYPE *add_MoveFocusRequested )( + ICoreWebView2Controller * This, + /* [in] */ ICoreWebView2MoveFocusRequestedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_MoveFocusRequested )( + ICoreWebView2Controller * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_GotFocus )( + ICoreWebView2Controller * This, + /* [in] */ ICoreWebView2FocusChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_GotFocus )( + ICoreWebView2Controller * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_LostFocus )( + ICoreWebView2Controller * This, + /* [in] */ ICoreWebView2FocusChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_LostFocus )( + ICoreWebView2Controller * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_AcceleratorKeyPressed )( + ICoreWebView2Controller * This, + /* [in] */ ICoreWebView2AcceleratorKeyPressedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_AcceleratorKeyPressed )( + ICoreWebView2Controller * This, + /* [in] */ EventRegistrationToken token); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_ParentWindow )( + ICoreWebView2Controller * This, + /* [retval][out] */ HWND *parentWindow); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_ParentWindow )( + ICoreWebView2Controller * This, + /* [in] */ HWND parentWindow); + + HRESULT ( STDMETHODCALLTYPE *NotifyParentWindowPositionChanged )( + ICoreWebView2Controller * This); + + HRESULT ( STDMETHODCALLTYPE *Close )( + ICoreWebView2Controller * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_CoreWebView2 )( + ICoreWebView2Controller * This, + /* [retval][out] */ ICoreWebView2 **coreWebView2); + + END_INTERFACE + } ICoreWebView2ControllerVtbl; + + interface ICoreWebView2Controller + { + CONST_VTBL struct ICoreWebView2ControllerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2Controller_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2Controller_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2Controller_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2Controller_get_IsVisible(This,isVisible) \ + ( (This)->lpVtbl -> get_IsVisible(This,isVisible) ) + +#define ICoreWebView2Controller_put_IsVisible(This,isVisible) \ + ( (This)->lpVtbl -> put_IsVisible(This,isVisible) ) + +#define ICoreWebView2Controller_get_Bounds(This,bounds) \ + ( (This)->lpVtbl -> get_Bounds(This,bounds) ) + +#define ICoreWebView2Controller_put_Bounds(This,bounds) \ + ( (This)->lpVtbl -> put_Bounds(This,bounds) ) + +#define ICoreWebView2Controller_get_ZoomFactor(This,zoomFactor) \ + ( (This)->lpVtbl -> get_ZoomFactor(This,zoomFactor) ) + +#define ICoreWebView2Controller_put_ZoomFactor(This,zoomFactor) \ + ( (This)->lpVtbl -> put_ZoomFactor(This,zoomFactor) ) + +#define ICoreWebView2Controller_add_ZoomFactorChanged(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_ZoomFactorChanged(This,eventHandler,token) ) + +#define ICoreWebView2Controller_remove_ZoomFactorChanged(This,token) \ + ( (This)->lpVtbl -> remove_ZoomFactorChanged(This,token) ) + +#define ICoreWebView2Controller_SetBoundsAndZoomFactor(This,bounds,zoomFactor) \ + ( (This)->lpVtbl -> SetBoundsAndZoomFactor(This,bounds,zoomFactor) ) + +#define ICoreWebView2Controller_MoveFocus(This,reason) \ + ( (This)->lpVtbl -> MoveFocus(This,reason) ) + +#define ICoreWebView2Controller_add_MoveFocusRequested(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_MoveFocusRequested(This,eventHandler,token) ) + +#define ICoreWebView2Controller_remove_MoveFocusRequested(This,token) \ + ( (This)->lpVtbl -> remove_MoveFocusRequested(This,token) ) + +#define ICoreWebView2Controller_add_GotFocus(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_GotFocus(This,eventHandler,token) ) + +#define ICoreWebView2Controller_remove_GotFocus(This,token) \ + ( (This)->lpVtbl -> remove_GotFocus(This,token) ) + +#define ICoreWebView2Controller_add_LostFocus(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_LostFocus(This,eventHandler,token) ) + +#define ICoreWebView2Controller_remove_LostFocus(This,token) \ + ( (This)->lpVtbl -> remove_LostFocus(This,token) ) + +#define ICoreWebView2Controller_add_AcceleratorKeyPressed(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_AcceleratorKeyPressed(This,eventHandler,token) ) + +#define ICoreWebView2Controller_remove_AcceleratorKeyPressed(This,token) \ + ( (This)->lpVtbl -> remove_AcceleratorKeyPressed(This,token) ) + +#define ICoreWebView2Controller_get_ParentWindow(This,parentWindow) \ + ( (This)->lpVtbl -> get_ParentWindow(This,parentWindow) ) + +#define ICoreWebView2Controller_put_ParentWindow(This,parentWindow) \ + ( (This)->lpVtbl -> put_ParentWindow(This,parentWindow) ) + +#define ICoreWebView2Controller_NotifyParentWindowPositionChanged(This) \ + ( (This)->lpVtbl -> NotifyParentWindowPositionChanged(This) ) + +#define ICoreWebView2Controller_Close(This) \ + ( (This)->lpVtbl -> Close(This) ) + +#define ICoreWebView2Controller_get_CoreWebView2(This,coreWebView2) \ + ( (This)->lpVtbl -> get_CoreWebView2(This,coreWebView2) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2Controller_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2Controller2_INTERFACE_DEFINED__ +#define __ICoreWebView2Controller2_INTERFACE_DEFINED__ + +/* interface ICoreWebView2Controller2 */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2Controller2 = {0xc979903e,0xd4ca,0x4228,{0x92,0xeb,0x47,0xee,0x3f,0xa9,0x6e,0xab}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("c979903e-d4ca-4228-92eb-47ee3fa96eab") + ICoreWebView2Controller2 : public ICoreWebView2Controller + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_DefaultBackgroundColor( + /* [retval][out] */ COREWEBVIEW2_COLOR *backgroundColor) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_DefaultBackgroundColor( + /* [in] */ COREWEBVIEW2_COLOR backgroundColor) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2Controller2Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2Controller2 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2Controller2 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2Controller2 * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_IsVisible )( + ICoreWebView2Controller2 * This, + /* [retval][out] */ BOOL *isVisible); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_IsVisible )( + ICoreWebView2Controller2 * This, + /* [in] */ BOOL isVisible); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Bounds )( + ICoreWebView2Controller2 * This, + /* [retval][out] */ RECT *bounds); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_Bounds )( + ICoreWebView2Controller2 * This, + /* [in] */ RECT bounds); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_ZoomFactor )( + ICoreWebView2Controller2 * This, + /* [retval][out] */ double *zoomFactor); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_ZoomFactor )( + ICoreWebView2Controller2 * This, + /* [in] */ double zoomFactor); + + HRESULT ( STDMETHODCALLTYPE *add_ZoomFactorChanged )( + ICoreWebView2Controller2 * This, + /* [in] */ ICoreWebView2ZoomFactorChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_ZoomFactorChanged )( + ICoreWebView2Controller2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *SetBoundsAndZoomFactor )( + ICoreWebView2Controller2 * This, + /* [in] */ RECT bounds, + /* [in] */ double zoomFactor); + + HRESULT ( STDMETHODCALLTYPE *MoveFocus )( + ICoreWebView2Controller2 * This, + /* [in] */ COREWEBVIEW2_MOVE_FOCUS_REASON reason); + + HRESULT ( STDMETHODCALLTYPE *add_MoveFocusRequested )( + ICoreWebView2Controller2 * This, + /* [in] */ ICoreWebView2MoveFocusRequestedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_MoveFocusRequested )( + ICoreWebView2Controller2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_GotFocus )( + ICoreWebView2Controller2 * This, + /* [in] */ ICoreWebView2FocusChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_GotFocus )( + ICoreWebView2Controller2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_LostFocus )( + ICoreWebView2Controller2 * This, + /* [in] */ ICoreWebView2FocusChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_LostFocus )( + ICoreWebView2Controller2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_AcceleratorKeyPressed )( + ICoreWebView2Controller2 * This, + /* [in] */ ICoreWebView2AcceleratorKeyPressedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_AcceleratorKeyPressed )( + ICoreWebView2Controller2 * This, + /* [in] */ EventRegistrationToken token); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_ParentWindow )( + ICoreWebView2Controller2 * This, + /* [retval][out] */ HWND *parentWindow); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_ParentWindow )( + ICoreWebView2Controller2 * This, + /* [in] */ HWND parentWindow); + + HRESULT ( STDMETHODCALLTYPE *NotifyParentWindowPositionChanged )( + ICoreWebView2Controller2 * This); + + HRESULT ( STDMETHODCALLTYPE *Close )( + ICoreWebView2Controller2 * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_CoreWebView2 )( + ICoreWebView2Controller2 * This, + /* [retval][out] */ ICoreWebView2 **coreWebView2); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_DefaultBackgroundColor )( + ICoreWebView2Controller2 * This, + /* [retval][out] */ COREWEBVIEW2_COLOR *backgroundColor); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_DefaultBackgroundColor )( + ICoreWebView2Controller2 * This, + /* [in] */ COREWEBVIEW2_COLOR backgroundColor); + + END_INTERFACE + } ICoreWebView2Controller2Vtbl; + + interface ICoreWebView2Controller2 + { + CONST_VTBL struct ICoreWebView2Controller2Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2Controller2_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2Controller2_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2Controller2_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2Controller2_get_IsVisible(This,isVisible) \ + ( (This)->lpVtbl -> get_IsVisible(This,isVisible) ) + +#define ICoreWebView2Controller2_put_IsVisible(This,isVisible) \ + ( (This)->lpVtbl -> put_IsVisible(This,isVisible) ) + +#define ICoreWebView2Controller2_get_Bounds(This,bounds) \ + ( (This)->lpVtbl -> get_Bounds(This,bounds) ) + +#define ICoreWebView2Controller2_put_Bounds(This,bounds) \ + ( (This)->lpVtbl -> put_Bounds(This,bounds) ) + +#define ICoreWebView2Controller2_get_ZoomFactor(This,zoomFactor) \ + ( (This)->lpVtbl -> get_ZoomFactor(This,zoomFactor) ) + +#define ICoreWebView2Controller2_put_ZoomFactor(This,zoomFactor) \ + ( (This)->lpVtbl -> put_ZoomFactor(This,zoomFactor) ) + +#define ICoreWebView2Controller2_add_ZoomFactorChanged(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_ZoomFactorChanged(This,eventHandler,token) ) + +#define ICoreWebView2Controller2_remove_ZoomFactorChanged(This,token) \ + ( (This)->lpVtbl -> remove_ZoomFactorChanged(This,token) ) + +#define ICoreWebView2Controller2_SetBoundsAndZoomFactor(This,bounds,zoomFactor) \ + ( (This)->lpVtbl -> SetBoundsAndZoomFactor(This,bounds,zoomFactor) ) + +#define ICoreWebView2Controller2_MoveFocus(This,reason) \ + ( (This)->lpVtbl -> MoveFocus(This,reason) ) + +#define ICoreWebView2Controller2_add_MoveFocusRequested(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_MoveFocusRequested(This,eventHandler,token) ) + +#define ICoreWebView2Controller2_remove_MoveFocusRequested(This,token) \ + ( (This)->lpVtbl -> remove_MoveFocusRequested(This,token) ) + +#define ICoreWebView2Controller2_add_GotFocus(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_GotFocus(This,eventHandler,token) ) + +#define ICoreWebView2Controller2_remove_GotFocus(This,token) \ + ( (This)->lpVtbl -> remove_GotFocus(This,token) ) + +#define ICoreWebView2Controller2_add_LostFocus(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_LostFocus(This,eventHandler,token) ) + +#define ICoreWebView2Controller2_remove_LostFocus(This,token) \ + ( (This)->lpVtbl -> remove_LostFocus(This,token) ) + +#define ICoreWebView2Controller2_add_AcceleratorKeyPressed(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_AcceleratorKeyPressed(This,eventHandler,token) ) + +#define ICoreWebView2Controller2_remove_AcceleratorKeyPressed(This,token) \ + ( (This)->lpVtbl -> remove_AcceleratorKeyPressed(This,token) ) + +#define ICoreWebView2Controller2_get_ParentWindow(This,parentWindow) \ + ( (This)->lpVtbl -> get_ParentWindow(This,parentWindow) ) + +#define ICoreWebView2Controller2_put_ParentWindow(This,parentWindow) \ + ( (This)->lpVtbl -> put_ParentWindow(This,parentWindow) ) + +#define ICoreWebView2Controller2_NotifyParentWindowPositionChanged(This) \ + ( (This)->lpVtbl -> NotifyParentWindowPositionChanged(This) ) + +#define ICoreWebView2Controller2_Close(This) \ + ( (This)->lpVtbl -> Close(This) ) + +#define ICoreWebView2Controller2_get_CoreWebView2(This,coreWebView2) \ + ( (This)->lpVtbl -> get_CoreWebView2(This,coreWebView2) ) + + +#define ICoreWebView2Controller2_get_DefaultBackgroundColor(This,backgroundColor) \ + ( (This)->lpVtbl -> get_DefaultBackgroundColor(This,backgroundColor) ) + +#define ICoreWebView2Controller2_put_DefaultBackgroundColor(This,backgroundColor) \ + ( (This)->lpVtbl -> put_DefaultBackgroundColor(This,backgroundColor) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2Controller2_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2Controller3_INTERFACE_DEFINED__ +#define __ICoreWebView2Controller3_INTERFACE_DEFINED__ + +/* interface ICoreWebView2Controller3 */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2Controller3 = {0xf9614724,0x5d2b,0x41dc,{0xae,0xf7,0x73,0xd6,0x2b,0x51,0x54,0x3b}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("f9614724-5d2b-41dc-aef7-73d62b51543b") + ICoreWebView2Controller3 : public ICoreWebView2Controller2 + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_RasterizationScale( + /* [retval][out] */ double *scale) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_RasterizationScale( + /* [in] */ double scale) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_ShouldDetectMonitorScaleChanges( + /* [retval][out] */ BOOL *value) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_ShouldDetectMonitorScaleChanges( + /* [in] */ BOOL value) = 0; + + virtual HRESULT STDMETHODCALLTYPE add_RasterizationScaleChanged( + /* [in] */ ICoreWebView2RasterizationScaleChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token) = 0; + + virtual HRESULT STDMETHODCALLTYPE remove_RasterizationScaleChanged( + /* [in] */ EventRegistrationToken token) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_BoundsMode( + /* [retval][out] */ COREWEBVIEW2_BOUNDS_MODE *boundsMode) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_BoundsMode( + /* [in] */ COREWEBVIEW2_BOUNDS_MODE boundsMode) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2Controller3Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2Controller3 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2Controller3 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2Controller3 * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_IsVisible )( + ICoreWebView2Controller3 * This, + /* [retval][out] */ BOOL *isVisible); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_IsVisible )( + ICoreWebView2Controller3 * This, + /* [in] */ BOOL isVisible); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Bounds )( + ICoreWebView2Controller3 * This, + /* [retval][out] */ RECT *bounds); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_Bounds )( + ICoreWebView2Controller3 * This, + /* [in] */ RECT bounds); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_ZoomFactor )( + ICoreWebView2Controller3 * This, + /* [retval][out] */ double *zoomFactor); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_ZoomFactor )( + ICoreWebView2Controller3 * This, + /* [in] */ double zoomFactor); + + HRESULT ( STDMETHODCALLTYPE *add_ZoomFactorChanged )( + ICoreWebView2Controller3 * This, + /* [in] */ ICoreWebView2ZoomFactorChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_ZoomFactorChanged )( + ICoreWebView2Controller3 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *SetBoundsAndZoomFactor )( + ICoreWebView2Controller3 * This, + /* [in] */ RECT bounds, + /* [in] */ double zoomFactor); + + HRESULT ( STDMETHODCALLTYPE *MoveFocus )( + ICoreWebView2Controller3 * This, + /* [in] */ COREWEBVIEW2_MOVE_FOCUS_REASON reason); + + HRESULT ( STDMETHODCALLTYPE *add_MoveFocusRequested )( + ICoreWebView2Controller3 * This, + /* [in] */ ICoreWebView2MoveFocusRequestedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_MoveFocusRequested )( + ICoreWebView2Controller3 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_GotFocus )( + ICoreWebView2Controller3 * This, + /* [in] */ ICoreWebView2FocusChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_GotFocus )( + ICoreWebView2Controller3 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_LostFocus )( + ICoreWebView2Controller3 * This, + /* [in] */ ICoreWebView2FocusChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_LostFocus )( + ICoreWebView2Controller3 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *add_AcceleratorKeyPressed )( + ICoreWebView2Controller3 * This, + /* [in] */ ICoreWebView2AcceleratorKeyPressedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_AcceleratorKeyPressed )( + ICoreWebView2Controller3 * This, + /* [in] */ EventRegistrationToken token); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_ParentWindow )( + ICoreWebView2Controller3 * This, + /* [retval][out] */ HWND *parentWindow); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_ParentWindow )( + ICoreWebView2Controller3 * This, + /* [in] */ HWND parentWindow); + + HRESULT ( STDMETHODCALLTYPE *NotifyParentWindowPositionChanged )( + ICoreWebView2Controller3 * This); + + HRESULT ( STDMETHODCALLTYPE *Close )( + ICoreWebView2Controller3 * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_CoreWebView2 )( + ICoreWebView2Controller3 * This, + /* [retval][out] */ ICoreWebView2 **coreWebView2); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_DefaultBackgroundColor )( + ICoreWebView2Controller3 * This, + /* [retval][out] */ COREWEBVIEW2_COLOR *backgroundColor); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_DefaultBackgroundColor )( + ICoreWebView2Controller3 * This, + /* [in] */ COREWEBVIEW2_COLOR backgroundColor); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_RasterizationScale )( + ICoreWebView2Controller3 * This, + /* [retval][out] */ double *scale); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_RasterizationScale )( + ICoreWebView2Controller3 * This, + /* [in] */ double scale); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_ShouldDetectMonitorScaleChanges )( + ICoreWebView2Controller3 * This, + /* [retval][out] */ BOOL *value); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_ShouldDetectMonitorScaleChanges )( + ICoreWebView2Controller3 * This, + /* [in] */ BOOL value); + + HRESULT ( STDMETHODCALLTYPE *add_RasterizationScaleChanged )( + ICoreWebView2Controller3 * This, + /* [in] */ ICoreWebView2RasterizationScaleChangedEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_RasterizationScaleChanged )( + ICoreWebView2Controller3 * This, + /* [in] */ EventRegistrationToken token); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_BoundsMode )( + ICoreWebView2Controller3 * This, + /* [retval][out] */ COREWEBVIEW2_BOUNDS_MODE *boundsMode); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_BoundsMode )( + ICoreWebView2Controller3 * This, + /* [in] */ COREWEBVIEW2_BOUNDS_MODE boundsMode); + + END_INTERFACE + } ICoreWebView2Controller3Vtbl; + + interface ICoreWebView2Controller3 + { + CONST_VTBL struct ICoreWebView2Controller3Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2Controller3_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2Controller3_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2Controller3_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2Controller3_get_IsVisible(This,isVisible) \ + ( (This)->lpVtbl -> get_IsVisible(This,isVisible) ) + +#define ICoreWebView2Controller3_put_IsVisible(This,isVisible) \ + ( (This)->lpVtbl -> put_IsVisible(This,isVisible) ) + +#define ICoreWebView2Controller3_get_Bounds(This,bounds) \ + ( (This)->lpVtbl -> get_Bounds(This,bounds) ) + +#define ICoreWebView2Controller3_put_Bounds(This,bounds) \ + ( (This)->lpVtbl -> put_Bounds(This,bounds) ) + +#define ICoreWebView2Controller3_get_ZoomFactor(This,zoomFactor) \ + ( (This)->lpVtbl -> get_ZoomFactor(This,zoomFactor) ) + +#define ICoreWebView2Controller3_put_ZoomFactor(This,zoomFactor) \ + ( (This)->lpVtbl -> put_ZoomFactor(This,zoomFactor) ) + +#define ICoreWebView2Controller3_add_ZoomFactorChanged(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_ZoomFactorChanged(This,eventHandler,token) ) + +#define ICoreWebView2Controller3_remove_ZoomFactorChanged(This,token) \ + ( (This)->lpVtbl -> remove_ZoomFactorChanged(This,token) ) + +#define ICoreWebView2Controller3_SetBoundsAndZoomFactor(This,bounds,zoomFactor) \ + ( (This)->lpVtbl -> SetBoundsAndZoomFactor(This,bounds,zoomFactor) ) + +#define ICoreWebView2Controller3_MoveFocus(This,reason) \ + ( (This)->lpVtbl -> MoveFocus(This,reason) ) + +#define ICoreWebView2Controller3_add_MoveFocusRequested(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_MoveFocusRequested(This,eventHandler,token) ) + +#define ICoreWebView2Controller3_remove_MoveFocusRequested(This,token) \ + ( (This)->lpVtbl -> remove_MoveFocusRequested(This,token) ) + +#define ICoreWebView2Controller3_add_GotFocus(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_GotFocus(This,eventHandler,token) ) + +#define ICoreWebView2Controller3_remove_GotFocus(This,token) \ + ( (This)->lpVtbl -> remove_GotFocus(This,token) ) + +#define ICoreWebView2Controller3_add_LostFocus(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_LostFocus(This,eventHandler,token) ) + +#define ICoreWebView2Controller3_remove_LostFocus(This,token) \ + ( (This)->lpVtbl -> remove_LostFocus(This,token) ) + +#define ICoreWebView2Controller3_add_AcceleratorKeyPressed(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_AcceleratorKeyPressed(This,eventHandler,token) ) + +#define ICoreWebView2Controller3_remove_AcceleratorKeyPressed(This,token) \ + ( (This)->lpVtbl -> remove_AcceleratorKeyPressed(This,token) ) + +#define ICoreWebView2Controller3_get_ParentWindow(This,parentWindow) \ + ( (This)->lpVtbl -> get_ParentWindow(This,parentWindow) ) + +#define ICoreWebView2Controller3_put_ParentWindow(This,parentWindow) \ + ( (This)->lpVtbl -> put_ParentWindow(This,parentWindow) ) + +#define ICoreWebView2Controller3_NotifyParentWindowPositionChanged(This) \ + ( (This)->lpVtbl -> NotifyParentWindowPositionChanged(This) ) + +#define ICoreWebView2Controller3_Close(This) \ + ( (This)->lpVtbl -> Close(This) ) + +#define ICoreWebView2Controller3_get_CoreWebView2(This,coreWebView2) \ + ( (This)->lpVtbl -> get_CoreWebView2(This,coreWebView2) ) + + +#define ICoreWebView2Controller3_get_DefaultBackgroundColor(This,backgroundColor) \ + ( (This)->lpVtbl -> get_DefaultBackgroundColor(This,backgroundColor) ) + +#define ICoreWebView2Controller3_put_DefaultBackgroundColor(This,backgroundColor) \ + ( (This)->lpVtbl -> put_DefaultBackgroundColor(This,backgroundColor) ) + + +#define ICoreWebView2Controller3_get_RasterizationScale(This,scale) \ + ( (This)->lpVtbl -> get_RasterizationScale(This,scale) ) + +#define ICoreWebView2Controller3_put_RasterizationScale(This,scale) \ + ( (This)->lpVtbl -> put_RasterizationScale(This,scale) ) + +#define ICoreWebView2Controller3_get_ShouldDetectMonitorScaleChanges(This,value) \ + ( (This)->lpVtbl -> get_ShouldDetectMonitorScaleChanges(This,value) ) + +#define ICoreWebView2Controller3_put_ShouldDetectMonitorScaleChanges(This,value) \ + ( (This)->lpVtbl -> put_ShouldDetectMonitorScaleChanges(This,value) ) + +#define ICoreWebView2Controller3_add_RasterizationScaleChanged(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_RasterizationScaleChanged(This,eventHandler,token) ) + +#define ICoreWebView2Controller3_remove_RasterizationScaleChanged(This,token) \ + ( (This)->lpVtbl -> remove_RasterizationScaleChanged(This,token) ) + +#define ICoreWebView2Controller3_get_BoundsMode(This,boundsMode) \ + ( (This)->lpVtbl -> get_BoundsMode(This,boundsMode) ) + +#define ICoreWebView2Controller3_put_BoundsMode(This,boundsMode) \ + ( (This)->lpVtbl -> put_BoundsMode(This,boundsMode) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2Controller3_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2ContentLoadingEventArgs_INTERFACE_DEFINED__ +#define __ICoreWebView2ContentLoadingEventArgs_INTERFACE_DEFINED__ + +/* interface ICoreWebView2ContentLoadingEventArgs */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2ContentLoadingEventArgs = {0x0c8a1275,0x9b6b,0x4901,{0x87,0xad,0x70,0xdf,0x25,0xba,0xfa,0x6e}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("0c8a1275-9b6b-4901-87ad-70df25bafa6e") + ICoreWebView2ContentLoadingEventArgs : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_IsErrorPage( + /* [retval][out] */ BOOL *isErrorPage) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_NavigationId( + /* [retval][out] */ UINT64 *navigationId) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2ContentLoadingEventArgsVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2ContentLoadingEventArgs * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2ContentLoadingEventArgs * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2ContentLoadingEventArgs * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_IsErrorPage )( + ICoreWebView2ContentLoadingEventArgs * This, + /* [retval][out] */ BOOL *isErrorPage); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_NavigationId )( + ICoreWebView2ContentLoadingEventArgs * This, + /* [retval][out] */ UINT64 *navigationId); + + END_INTERFACE + } ICoreWebView2ContentLoadingEventArgsVtbl; + + interface ICoreWebView2ContentLoadingEventArgs + { + CONST_VTBL struct ICoreWebView2ContentLoadingEventArgsVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2ContentLoadingEventArgs_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2ContentLoadingEventArgs_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2ContentLoadingEventArgs_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2ContentLoadingEventArgs_get_IsErrorPage(This,isErrorPage) \ + ( (This)->lpVtbl -> get_IsErrorPage(This,isErrorPage) ) + +#define ICoreWebView2ContentLoadingEventArgs_get_NavigationId(This,navigationId) \ + ( (This)->lpVtbl -> get_NavigationId(This,navigationId) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2ContentLoadingEventArgs_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2ContentLoadingEventHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2ContentLoadingEventHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2ContentLoadingEventHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2ContentLoadingEventHandler = {0x364471e7,0xf2be,0x4910,{0xbd,0xba,0xd7,0x20,0x77,0xd5,0x1c,0x4b}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("364471e7-f2be-4910-bdba-d72077d51c4b") + ICoreWebView2ContentLoadingEventHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + /* [in] */ ICoreWebView2 *sender, + /* [in] */ ICoreWebView2ContentLoadingEventArgs *args) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2ContentLoadingEventHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2ContentLoadingEventHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2ContentLoadingEventHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2ContentLoadingEventHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2ContentLoadingEventHandler * This, + /* [in] */ ICoreWebView2 *sender, + /* [in] */ ICoreWebView2ContentLoadingEventArgs *args); + + END_INTERFACE + } ICoreWebView2ContentLoadingEventHandlerVtbl; + + interface ICoreWebView2ContentLoadingEventHandler + { + CONST_VTBL struct ICoreWebView2ContentLoadingEventHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2ContentLoadingEventHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2ContentLoadingEventHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2ContentLoadingEventHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2ContentLoadingEventHandler_Invoke(This,sender,args) \ + ( (This)->lpVtbl -> Invoke(This,sender,args) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2ContentLoadingEventHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2Cookie_INTERFACE_DEFINED__ +#define __ICoreWebView2Cookie_INTERFACE_DEFINED__ + +/* interface ICoreWebView2Cookie */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2Cookie = {0xAD26D6BE,0x1486,0x43E6,{0xBF,0x87,0xA2,0x03,0x40,0x06,0xCA,0x21}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("AD26D6BE-1486-43E6-BF87-A2034006CA21") + ICoreWebView2Cookie : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Name( + /* [retval][out] */ LPWSTR *name) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Value( + /* [retval][out] */ LPWSTR *value) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_Value( + /* [in] */ LPCWSTR value) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Domain( + /* [retval][out] */ LPWSTR *domain) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Path( + /* [retval][out] */ LPWSTR *path) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Expires( + /* [retval][out] */ double *expires) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_Expires( + /* [in] */ double expires) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_IsHttpOnly( + /* [retval][out] */ BOOL *isHttpOnly) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_IsHttpOnly( + /* [in] */ BOOL isHttpOnly) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_SameSite( + /* [retval][out] */ COREWEBVIEW2_COOKIE_SAME_SITE_KIND *sameSite) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_SameSite( + /* [in] */ COREWEBVIEW2_COOKIE_SAME_SITE_KIND sameSite) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_IsSecure( + /* [retval][out] */ BOOL *isSecure) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_IsSecure( + /* [in] */ BOOL isSecure) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_IsSession( + /* [retval][out] */ BOOL *isSession) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2CookieVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2Cookie * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2Cookie * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2Cookie * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Name )( + ICoreWebView2Cookie * This, + /* [retval][out] */ LPWSTR *name); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Value )( + ICoreWebView2Cookie * This, + /* [retval][out] */ LPWSTR *value); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_Value )( + ICoreWebView2Cookie * This, + /* [in] */ LPCWSTR value); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Domain )( + ICoreWebView2Cookie * This, + /* [retval][out] */ LPWSTR *domain); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Path )( + ICoreWebView2Cookie * This, + /* [retval][out] */ LPWSTR *path); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Expires )( + ICoreWebView2Cookie * This, + /* [retval][out] */ double *expires); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_Expires )( + ICoreWebView2Cookie * This, + /* [in] */ double expires); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_IsHttpOnly )( + ICoreWebView2Cookie * This, + /* [retval][out] */ BOOL *isHttpOnly); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_IsHttpOnly )( + ICoreWebView2Cookie * This, + /* [in] */ BOOL isHttpOnly); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_SameSite )( + ICoreWebView2Cookie * This, + /* [retval][out] */ COREWEBVIEW2_COOKIE_SAME_SITE_KIND *sameSite); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_SameSite )( + ICoreWebView2Cookie * This, + /* [in] */ COREWEBVIEW2_COOKIE_SAME_SITE_KIND sameSite); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_IsSecure )( + ICoreWebView2Cookie * This, + /* [retval][out] */ BOOL *isSecure); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_IsSecure )( + ICoreWebView2Cookie * This, + /* [in] */ BOOL isSecure); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_IsSession )( + ICoreWebView2Cookie * This, + /* [retval][out] */ BOOL *isSession); + + END_INTERFACE + } ICoreWebView2CookieVtbl; + + interface ICoreWebView2Cookie + { + CONST_VTBL struct ICoreWebView2CookieVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2Cookie_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2Cookie_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2Cookie_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2Cookie_get_Name(This,name) \ + ( (This)->lpVtbl -> get_Name(This,name) ) + +#define ICoreWebView2Cookie_get_Value(This,value) \ + ( (This)->lpVtbl -> get_Value(This,value) ) + +#define ICoreWebView2Cookie_put_Value(This,value) \ + ( (This)->lpVtbl -> put_Value(This,value) ) + +#define ICoreWebView2Cookie_get_Domain(This,domain) \ + ( (This)->lpVtbl -> get_Domain(This,domain) ) + +#define ICoreWebView2Cookie_get_Path(This,path) \ + ( (This)->lpVtbl -> get_Path(This,path) ) + +#define ICoreWebView2Cookie_get_Expires(This,expires) \ + ( (This)->lpVtbl -> get_Expires(This,expires) ) + +#define ICoreWebView2Cookie_put_Expires(This,expires) \ + ( (This)->lpVtbl -> put_Expires(This,expires) ) + +#define ICoreWebView2Cookie_get_IsHttpOnly(This,isHttpOnly) \ + ( (This)->lpVtbl -> get_IsHttpOnly(This,isHttpOnly) ) + +#define ICoreWebView2Cookie_put_IsHttpOnly(This,isHttpOnly) \ + ( (This)->lpVtbl -> put_IsHttpOnly(This,isHttpOnly) ) + +#define ICoreWebView2Cookie_get_SameSite(This,sameSite) \ + ( (This)->lpVtbl -> get_SameSite(This,sameSite) ) + +#define ICoreWebView2Cookie_put_SameSite(This,sameSite) \ + ( (This)->lpVtbl -> put_SameSite(This,sameSite) ) + +#define ICoreWebView2Cookie_get_IsSecure(This,isSecure) \ + ( (This)->lpVtbl -> get_IsSecure(This,isSecure) ) + +#define ICoreWebView2Cookie_put_IsSecure(This,isSecure) \ + ( (This)->lpVtbl -> put_IsSecure(This,isSecure) ) + +#define ICoreWebView2Cookie_get_IsSession(This,isSession) \ + ( (This)->lpVtbl -> get_IsSession(This,isSession) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2Cookie_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2CookieList_INTERFACE_DEFINED__ +#define __ICoreWebView2CookieList_INTERFACE_DEFINED__ + +/* interface ICoreWebView2CookieList */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2CookieList = {0xF7F6F714,0x5D2A,0x43C6,{0x95,0x03,0x34,0x6E,0xCE,0x02,0xD1,0x86}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("F7F6F714-5D2A-43C6-9503-346ECE02D186") + ICoreWebView2CookieList : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Count( + /* [retval][out] */ UINT *count) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetValueAtIndex( + /* [in] */ UINT index, + /* [retval][out] */ ICoreWebView2Cookie **cookie) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2CookieListVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2CookieList * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2CookieList * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2CookieList * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Count )( + ICoreWebView2CookieList * This, + /* [retval][out] */ UINT *count); + + HRESULT ( STDMETHODCALLTYPE *GetValueAtIndex )( + ICoreWebView2CookieList * This, + /* [in] */ UINT index, + /* [retval][out] */ ICoreWebView2Cookie **cookie); + + END_INTERFACE + } ICoreWebView2CookieListVtbl; + + interface ICoreWebView2CookieList + { + CONST_VTBL struct ICoreWebView2CookieListVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2CookieList_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2CookieList_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2CookieList_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2CookieList_get_Count(This,count) \ + ( (This)->lpVtbl -> get_Count(This,count) ) + +#define ICoreWebView2CookieList_GetValueAtIndex(This,index,cookie) \ + ( (This)->lpVtbl -> GetValueAtIndex(This,index,cookie) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2CookieList_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2CookieManager_INTERFACE_DEFINED__ +#define __ICoreWebView2CookieManager_INTERFACE_DEFINED__ + +/* interface ICoreWebView2CookieManager */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2CookieManager = {0x177CD9E7,0xB6F5,0x451A,{0x94,0xA0,0x5D,0x7A,0x3A,0x4C,0x41,0x41}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("177CD9E7-B6F5-451A-94A0-5D7A3A4C4141") + ICoreWebView2CookieManager : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE CreateCookie( + /* [in] */ LPCWSTR name, + /* [in] */ LPCWSTR value, + /* [in] */ LPCWSTR domain, + /* [in] */ LPCWSTR path, + /* [retval][out] */ ICoreWebView2Cookie **cookie) = 0; + + virtual HRESULT STDMETHODCALLTYPE CopyCookie( + /* [in] */ ICoreWebView2Cookie *cookieParam, + /* [retval][out] */ ICoreWebView2Cookie **cookie) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetCookies( + /* [in] */ LPCWSTR uri, + /* [in] */ ICoreWebView2GetCookiesCompletedHandler *handler) = 0; + + virtual HRESULT STDMETHODCALLTYPE AddOrUpdateCookie( + /* [in] */ ICoreWebView2Cookie *cookie) = 0; + + virtual HRESULT STDMETHODCALLTYPE DeleteCookie( + /* [in] */ ICoreWebView2Cookie *cookie) = 0; + + virtual HRESULT STDMETHODCALLTYPE DeleteCookies( + /* [in] */ LPCWSTR name, + /* [in] */ LPCWSTR uri) = 0; + + virtual HRESULT STDMETHODCALLTYPE DeleteCookiesWithDomainAndPath( + /* [in] */ LPCWSTR name, + /* [in] */ LPCWSTR domain, + /* [in] */ LPCWSTR path) = 0; + + virtual HRESULT STDMETHODCALLTYPE DeleteAllCookies( void) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2CookieManagerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2CookieManager * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2CookieManager * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2CookieManager * This); + + HRESULT ( STDMETHODCALLTYPE *CreateCookie )( + ICoreWebView2CookieManager * This, + /* [in] */ LPCWSTR name, + /* [in] */ LPCWSTR value, + /* [in] */ LPCWSTR domain, + /* [in] */ LPCWSTR path, + /* [retval][out] */ ICoreWebView2Cookie **cookie); + + HRESULT ( STDMETHODCALLTYPE *CopyCookie )( + ICoreWebView2CookieManager * This, + /* [in] */ ICoreWebView2Cookie *cookieParam, + /* [retval][out] */ ICoreWebView2Cookie **cookie); + + HRESULT ( STDMETHODCALLTYPE *GetCookies )( + ICoreWebView2CookieManager * This, + /* [in] */ LPCWSTR uri, + /* [in] */ ICoreWebView2GetCookiesCompletedHandler *handler); + + HRESULT ( STDMETHODCALLTYPE *AddOrUpdateCookie )( + ICoreWebView2CookieManager * This, + /* [in] */ ICoreWebView2Cookie *cookie); + + HRESULT ( STDMETHODCALLTYPE *DeleteCookie )( + ICoreWebView2CookieManager * This, + /* [in] */ ICoreWebView2Cookie *cookie); + + HRESULT ( STDMETHODCALLTYPE *DeleteCookies )( + ICoreWebView2CookieManager * This, + /* [in] */ LPCWSTR name, + /* [in] */ LPCWSTR uri); + + HRESULT ( STDMETHODCALLTYPE *DeleteCookiesWithDomainAndPath )( + ICoreWebView2CookieManager * This, + /* [in] */ LPCWSTR name, + /* [in] */ LPCWSTR domain, + /* [in] */ LPCWSTR path); + + HRESULT ( STDMETHODCALLTYPE *DeleteAllCookies )( + ICoreWebView2CookieManager * This); + + END_INTERFACE + } ICoreWebView2CookieManagerVtbl; + + interface ICoreWebView2CookieManager + { + CONST_VTBL struct ICoreWebView2CookieManagerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2CookieManager_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2CookieManager_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2CookieManager_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2CookieManager_CreateCookie(This,name,value,domain,path,cookie) \ + ( (This)->lpVtbl -> CreateCookie(This,name,value,domain,path,cookie) ) + +#define ICoreWebView2CookieManager_CopyCookie(This,cookieParam,cookie) \ + ( (This)->lpVtbl -> CopyCookie(This,cookieParam,cookie) ) + +#define ICoreWebView2CookieManager_GetCookies(This,uri,handler) \ + ( (This)->lpVtbl -> GetCookies(This,uri,handler) ) + +#define ICoreWebView2CookieManager_AddOrUpdateCookie(This,cookie) \ + ( (This)->lpVtbl -> AddOrUpdateCookie(This,cookie) ) + +#define ICoreWebView2CookieManager_DeleteCookie(This,cookie) \ + ( (This)->lpVtbl -> DeleteCookie(This,cookie) ) + +#define ICoreWebView2CookieManager_DeleteCookies(This,name,uri) \ + ( (This)->lpVtbl -> DeleteCookies(This,name,uri) ) + +#define ICoreWebView2CookieManager_DeleteCookiesWithDomainAndPath(This,name,domain,path) \ + ( (This)->lpVtbl -> DeleteCookiesWithDomainAndPath(This,name,domain,path) ) + +#define ICoreWebView2CookieManager_DeleteAllCookies(This) \ + ( (This)->lpVtbl -> DeleteAllCookies(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2CookieManager_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2CreateCoreWebView2CompositionControllerCompletedHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2CreateCoreWebView2CompositionControllerCompletedHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2CreateCoreWebView2CompositionControllerCompletedHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2CreateCoreWebView2CompositionControllerCompletedHandler = {0x02fab84b,0x1428,0x4fb7,{0xad,0x45,0x1b,0x2e,0x64,0x73,0x61,0x84}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("02fab84b-1428-4fb7-ad45-1b2e64736184") + ICoreWebView2CreateCoreWebView2CompositionControllerCompletedHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + HRESULT errorCode, + ICoreWebView2CompositionController *webView) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2CreateCoreWebView2CompositionControllerCompletedHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2CreateCoreWebView2CompositionControllerCompletedHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2CreateCoreWebView2CompositionControllerCompletedHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2CreateCoreWebView2CompositionControllerCompletedHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2CreateCoreWebView2CompositionControllerCompletedHandler * This, + HRESULT errorCode, + ICoreWebView2CompositionController *webView); + + END_INTERFACE + } ICoreWebView2CreateCoreWebView2CompositionControllerCompletedHandlerVtbl; + + interface ICoreWebView2CreateCoreWebView2CompositionControllerCompletedHandler + { + CONST_VTBL struct ICoreWebView2CreateCoreWebView2CompositionControllerCompletedHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2CreateCoreWebView2CompositionControllerCompletedHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2CreateCoreWebView2CompositionControllerCompletedHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2CreateCoreWebView2CompositionControllerCompletedHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2CreateCoreWebView2CompositionControllerCompletedHandler_Invoke(This,errorCode,webView) \ + ( (This)->lpVtbl -> Invoke(This,errorCode,webView) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2CreateCoreWebView2CompositionControllerCompletedHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2CreateCoreWebView2ControllerCompletedHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2CreateCoreWebView2ControllerCompletedHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2CreateCoreWebView2ControllerCompletedHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2CreateCoreWebView2ControllerCompletedHandler = {0x6c4819f3,0xc9b7,0x4260,{0x81,0x27,0xc9,0xf5,0xbd,0xe7,0xf6,0x8c}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("6c4819f3-c9b7-4260-8127-c9f5bde7f68c") + ICoreWebView2CreateCoreWebView2ControllerCompletedHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + HRESULT errorCode, + ICoreWebView2Controller *createdController) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2CreateCoreWebView2ControllerCompletedHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2CreateCoreWebView2ControllerCompletedHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2CreateCoreWebView2ControllerCompletedHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2CreateCoreWebView2ControllerCompletedHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2CreateCoreWebView2ControllerCompletedHandler * This, + HRESULT errorCode, + ICoreWebView2Controller *createdController); + + END_INTERFACE + } ICoreWebView2CreateCoreWebView2ControllerCompletedHandlerVtbl; + + interface ICoreWebView2CreateCoreWebView2ControllerCompletedHandler + { + CONST_VTBL struct ICoreWebView2CreateCoreWebView2ControllerCompletedHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2CreateCoreWebView2ControllerCompletedHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2CreateCoreWebView2ControllerCompletedHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2CreateCoreWebView2ControllerCompletedHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2CreateCoreWebView2ControllerCompletedHandler_Invoke(This,errorCode,createdController) \ + ( (This)->lpVtbl -> Invoke(This,errorCode,createdController) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2CreateCoreWebView2ControllerCompletedHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler = {0x4e8a3389,0xc9d8,0x4bd2,{0xb6,0xb5,0x12,0x4f,0xee,0x6c,0xc1,0x4d}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("4e8a3389-c9d8-4bd2-b6b5-124fee6cc14d") + ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + HRESULT errorCode, + ICoreWebView2Environment *createdEnvironment) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler * This, + HRESULT errorCode, + ICoreWebView2Environment *createdEnvironment); + + END_INTERFACE + } ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandlerVtbl; + + interface ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler + { + CONST_VTBL struct ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler_Invoke(This,errorCode,createdEnvironment) \ + ( (This)->lpVtbl -> Invoke(This,errorCode,createdEnvironment) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2ContainsFullScreenElementChangedEventHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2ContainsFullScreenElementChangedEventHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2ContainsFullScreenElementChangedEventHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2ContainsFullScreenElementChangedEventHandler = {0xe45d98b1,0xafef,0x45be,{0x8b,0xaf,0x6c,0x77,0x28,0x86,0x7f,0x73}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("e45d98b1-afef-45be-8baf-6c7728867f73") + ICoreWebView2ContainsFullScreenElementChangedEventHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + /* [in] */ ICoreWebView2 *sender, + /* [in] */ IUnknown *args) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2ContainsFullScreenElementChangedEventHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2ContainsFullScreenElementChangedEventHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2ContainsFullScreenElementChangedEventHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2ContainsFullScreenElementChangedEventHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2ContainsFullScreenElementChangedEventHandler * This, + /* [in] */ ICoreWebView2 *sender, + /* [in] */ IUnknown *args); + + END_INTERFACE + } ICoreWebView2ContainsFullScreenElementChangedEventHandlerVtbl; + + interface ICoreWebView2ContainsFullScreenElementChangedEventHandler + { + CONST_VTBL struct ICoreWebView2ContainsFullScreenElementChangedEventHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2ContainsFullScreenElementChangedEventHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2ContainsFullScreenElementChangedEventHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2ContainsFullScreenElementChangedEventHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2ContainsFullScreenElementChangedEventHandler_Invoke(This,sender,args) \ + ( (This)->lpVtbl -> Invoke(This,sender,args) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2ContainsFullScreenElementChangedEventHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2CursorChangedEventHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2CursorChangedEventHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2CursorChangedEventHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2CursorChangedEventHandler = {0x9da43ccc,0x26e1,0x4dad,{0xb5,0x6c,0xd8,0x96,0x1c,0x94,0xc5,0x71}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("9da43ccc-26e1-4dad-b56c-d8961c94c571") + ICoreWebView2CursorChangedEventHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + /* [in] */ ICoreWebView2CompositionController *sender, + /* [in] */ IUnknown *args) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2CursorChangedEventHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2CursorChangedEventHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2CursorChangedEventHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2CursorChangedEventHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2CursorChangedEventHandler * This, + /* [in] */ ICoreWebView2CompositionController *sender, + /* [in] */ IUnknown *args); + + END_INTERFACE + } ICoreWebView2CursorChangedEventHandlerVtbl; + + interface ICoreWebView2CursorChangedEventHandler + { + CONST_VTBL struct ICoreWebView2CursorChangedEventHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2CursorChangedEventHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2CursorChangedEventHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2CursorChangedEventHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2CursorChangedEventHandler_Invoke(This,sender,args) \ + ( (This)->lpVtbl -> Invoke(This,sender,args) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2CursorChangedEventHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2DocumentTitleChangedEventHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2DocumentTitleChangedEventHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2DocumentTitleChangedEventHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2DocumentTitleChangedEventHandler = {0xf5f2b923,0x953e,0x4042,{0x9f,0x95,0xf3,0xa1,0x18,0xe1,0xaf,0xd4}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("f5f2b923-953e-4042-9f95-f3a118e1afd4") + ICoreWebView2DocumentTitleChangedEventHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + /* [in] */ ICoreWebView2 *sender, + /* [in] */ IUnknown *args) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2DocumentTitleChangedEventHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2DocumentTitleChangedEventHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2DocumentTitleChangedEventHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2DocumentTitleChangedEventHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2DocumentTitleChangedEventHandler * This, + /* [in] */ ICoreWebView2 *sender, + /* [in] */ IUnknown *args); + + END_INTERFACE + } ICoreWebView2DocumentTitleChangedEventHandlerVtbl; + + interface ICoreWebView2DocumentTitleChangedEventHandler + { + CONST_VTBL struct ICoreWebView2DocumentTitleChangedEventHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2DocumentTitleChangedEventHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2DocumentTitleChangedEventHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2DocumentTitleChangedEventHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2DocumentTitleChangedEventHandler_Invoke(This,sender,args) \ + ( (This)->lpVtbl -> Invoke(This,sender,args) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2DocumentTitleChangedEventHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2DOMContentLoadedEventArgs_INTERFACE_DEFINED__ +#define __ICoreWebView2DOMContentLoadedEventArgs_INTERFACE_DEFINED__ + +/* interface ICoreWebView2DOMContentLoadedEventArgs */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2DOMContentLoadedEventArgs = {0x16B1E21A,0xC503,0x44F2,{0x84,0xC9,0x70,0xAB,0xA5,0x03,0x12,0x83}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("16B1E21A-C503-44F2-84C9-70ABA5031283") + ICoreWebView2DOMContentLoadedEventArgs : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_NavigationId( + /* [retval][out] */ UINT64 *navigationId) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2DOMContentLoadedEventArgsVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2DOMContentLoadedEventArgs * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2DOMContentLoadedEventArgs * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2DOMContentLoadedEventArgs * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_NavigationId )( + ICoreWebView2DOMContentLoadedEventArgs * This, + /* [retval][out] */ UINT64 *navigationId); + + END_INTERFACE + } ICoreWebView2DOMContentLoadedEventArgsVtbl; + + interface ICoreWebView2DOMContentLoadedEventArgs + { + CONST_VTBL struct ICoreWebView2DOMContentLoadedEventArgsVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2DOMContentLoadedEventArgs_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2DOMContentLoadedEventArgs_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2DOMContentLoadedEventArgs_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2DOMContentLoadedEventArgs_get_NavigationId(This,navigationId) \ + ( (This)->lpVtbl -> get_NavigationId(This,navigationId) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2DOMContentLoadedEventArgs_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2DOMContentLoadedEventHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2DOMContentLoadedEventHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2DOMContentLoadedEventHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2DOMContentLoadedEventHandler = {0x4BAC7E9C,0x199E,0x49ED,{0x87,0xED,0x24,0x93,0x03,0xAC,0xF0,0x19}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("4BAC7E9C-199E-49ED-87ED-249303ACF019") + ICoreWebView2DOMContentLoadedEventHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + /* [in] */ ICoreWebView2 *sender, + /* [in] */ ICoreWebView2DOMContentLoadedEventArgs *args) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2DOMContentLoadedEventHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2DOMContentLoadedEventHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2DOMContentLoadedEventHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2DOMContentLoadedEventHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2DOMContentLoadedEventHandler * This, + /* [in] */ ICoreWebView2 *sender, + /* [in] */ ICoreWebView2DOMContentLoadedEventArgs *args); + + END_INTERFACE + } ICoreWebView2DOMContentLoadedEventHandlerVtbl; + + interface ICoreWebView2DOMContentLoadedEventHandler + { + CONST_VTBL struct ICoreWebView2DOMContentLoadedEventHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2DOMContentLoadedEventHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2DOMContentLoadedEventHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2DOMContentLoadedEventHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2DOMContentLoadedEventHandler_Invoke(This,sender,args) \ + ( (This)->lpVtbl -> Invoke(This,sender,args) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2DOMContentLoadedEventHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2Deferral_INTERFACE_DEFINED__ +#define __ICoreWebView2Deferral_INTERFACE_DEFINED__ + +/* interface ICoreWebView2Deferral */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2Deferral = {0xc10e7f7b,0xb585,0x46f0,{0xa6,0x23,0x8b,0xef,0xbf,0x3e,0x4e,0xe0}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("c10e7f7b-b585-46f0-a623-8befbf3e4ee0") + ICoreWebView2Deferral : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Complete( void) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2DeferralVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2Deferral * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2Deferral * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2Deferral * This); + + HRESULT ( STDMETHODCALLTYPE *Complete )( + ICoreWebView2Deferral * This); + + END_INTERFACE + } ICoreWebView2DeferralVtbl; + + interface ICoreWebView2Deferral + { + CONST_VTBL struct ICoreWebView2DeferralVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2Deferral_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2Deferral_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2Deferral_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2Deferral_Complete(This) \ + ( (This)->lpVtbl -> Complete(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2Deferral_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2DevToolsProtocolEventReceivedEventArgs_INTERFACE_DEFINED__ +#define __ICoreWebView2DevToolsProtocolEventReceivedEventArgs_INTERFACE_DEFINED__ + +/* interface ICoreWebView2DevToolsProtocolEventReceivedEventArgs */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2DevToolsProtocolEventReceivedEventArgs = {0x653c2959,0xbb3a,0x4377,{0x86,0x32,0xb5,0x8a,0xda,0x4e,0x66,0xc4}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("653c2959-bb3a-4377-8632-b58ada4e66c4") + ICoreWebView2DevToolsProtocolEventReceivedEventArgs : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_ParameterObjectAsJson( + /* [retval][out] */ LPWSTR *parameterObjectAsJson) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2DevToolsProtocolEventReceivedEventArgsVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2DevToolsProtocolEventReceivedEventArgs * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2DevToolsProtocolEventReceivedEventArgs * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2DevToolsProtocolEventReceivedEventArgs * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_ParameterObjectAsJson )( + ICoreWebView2DevToolsProtocolEventReceivedEventArgs * This, + /* [retval][out] */ LPWSTR *parameterObjectAsJson); + + END_INTERFACE + } ICoreWebView2DevToolsProtocolEventReceivedEventArgsVtbl; + + interface ICoreWebView2DevToolsProtocolEventReceivedEventArgs + { + CONST_VTBL struct ICoreWebView2DevToolsProtocolEventReceivedEventArgsVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2DevToolsProtocolEventReceivedEventArgs_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2DevToolsProtocolEventReceivedEventArgs_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2DevToolsProtocolEventReceivedEventArgs_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2DevToolsProtocolEventReceivedEventArgs_get_ParameterObjectAsJson(This,parameterObjectAsJson) \ + ( (This)->lpVtbl -> get_ParameterObjectAsJson(This,parameterObjectAsJson) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2DevToolsProtocolEventReceivedEventArgs_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2DevToolsProtocolEventReceivedEventHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2DevToolsProtocolEventReceivedEventHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2DevToolsProtocolEventReceivedEventHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2DevToolsProtocolEventReceivedEventHandler = {0xe2fda4be,0x5456,0x406c,{0xa2,0x61,0x3d,0x45,0x21,0x38,0x36,0x2c}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("e2fda4be-5456-406c-a261-3d452138362c") + ICoreWebView2DevToolsProtocolEventReceivedEventHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + /* [in] */ ICoreWebView2 *sender, + /* [in] */ ICoreWebView2DevToolsProtocolEventReceivedEventArgs *args) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2DevToolsProtocolEventReceivedEventHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2DevToolsProtocolEventReceivedEventHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2DevToolsProtocolEventReceivedEventHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2DevToolsProtocolEventReceivedEventHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2DevToolsProtocolEventReceivedEventHandler * This, + /* [in] */ ICoreWebView2 *sender, + /* [in] */ ICoreWebView2DevToolsProtocolEventReceivedEventArgs *args); + + END_INTERFACE + } ICoreWebView2DevToolsProtocolEventReceivedEventHandlerVtbl; + + interface ICoreWebView2DevToolsProtocolEventReceivedEventHandler + { + CONST_VTBL struct ICoreWebView2DevToolsProtocolEventReceivedEventHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2DevToolsProtocolEventReceivedEventHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2DevToolsProtocolEventReceivedEventHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2DevToolsProtocolEventReceivedEventHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2DevToolsProtocolEventReceivedEventHandler_Invoke(This,sender,args) \ + ( (This)->lpVtbl -> Invoke(This,sender,args) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2DevToolsProtocolEventReceivedEventHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2DevToolsProtocolEventReceiver_INTERFACE_DEFINED__ +#define __ICoreWebView2DevToolsProtocolEventReceiver_INTERFACE_DEFINED__ + +/* interface ICoreWebView2DevToolsProtocolEventReceiver */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2DevToolsProtocolEventReceiver = {0xb32ca51a,0x8371,0x45e9,{0x93,0x17,0xaf,0x02,0x1d,0x08,0x03,0x67}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("b32ca51a-8371-45e9-9317-af021d080367") + ICoreWebView2DevToolsProtocolEventReceiver : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE add_DevToolsProtocolEventReceived( + /* [in] */ ICoreWebView2DevToolsProtocolEventReceivedEventHandler *handler, + /* [out] */ EventRegistrationToken *token) = 0; + + virtual HRESULT STDMETHODCALLTYPE remove_DevToolsProtocolEventReceived( + /* [in] */ EventRegistrationToken token) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2DevToolsProtocolEventReceiverVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2DevToolsProtocolEventReceiver * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2DevToolsProtocolEventReceiver * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2DevToolsProtocolEventReceiver * This); + + HRESULT ( STDMETHODCALLTYPE *add_DevToolsProtocolEventReceived )( + ICoreWebView2DevToolsProtocolEventReceiver * This, + /* [in] */ ICoreWebView2DevToolsProtocolEventReceivedEventHandler *handler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_DevToolsProtocolEventReceived )( + ICoreWebView2DevToolsProtocolEventReceiver * This, + /* [in] */ EventRegistrationToken token); + + END_INTERFACE + } ICoreWebView2DevToolsProtocolEventReceiverVtbl; + + interface ICoreWebView2DevToolsProtocolEventReceiver + { + CONST_VTBL struct ICoreWebView2DevToolsProtocolEventReceiverVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2DevToolsProtocolEventReceiver_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2DevToolsProtocolEventReceiver_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2DevToolsProtocolEventReceiver_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2DevToolsProtocolEventReceiver_add_DevToolsProtocolEventReceived(This,handler,token) \ + ( (This)->lpVtbl -> add_DevToolsProtocolEventReceived(This,handler,token) ) + +#define ICoreWebView2DevToolsProtocolEventReceiver_remove_DevToolsProtocolEventReceived(This,token) \ + ( (This)->lpVtbl -> remove_DevToolsProtocolEventReceived(This,token) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2DevToolsProtocolEventReceiver_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2Environment_INTERFACE_DEFINED__ +#define __ICoreWebView2Environment_INTERFACE_DEFINED__ + +/* interface ICoreWebView2Environment */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2Environment = {0xb96d755e,0x0319,0x4e92,{0xa2,0x96,0x23,0x43,0x6f,0x46,0xa1,0xfc}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("b96d755e-0319-4e92-a296-23436f46a1fc") + ICoreWebView2Environment : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE CreateCoreWebView2Controller( + HWND parentWindow, + ICoreWebView2CreateCoreWebView2ControllerCompletedHandler *handler) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateWebResourceResponse( + /* [in] */ IStream *content, + /* [in] */ int statusCode, + /* [in] */ LPCWSTR reasonPhrase, + /* [in] */ LPCWSTR headers, + /* [retval][out] */ ICoreWebView2WebResourceResponse **response) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_BrowserVersionString( + /* [retval][out] */ LPWSTR *versionInfo) = 0; + + virtual HRESULT STDMETHODCALLTYPE add_NewBrowserVersionAvailable( + /* [in] */ ICoreWebView2NewBrowserVersionAvailableEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token) = 0; + + virtual HRESULT STDMETHODCALLTYPE remove_NewBrowserVersionAvailable( + /* [in] */ EventRegistrationToken token) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2EnvironmentVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2Environment * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2Environment * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2Environment * This); + + HRESULT ( STDMETHODCALLTYPE *CreateCoreWebView2Controller )( + ICoreWebView2Environment * This, + HWND parentWindow, + ICoreWebView2CreateCoreWebView2ControllerCompletedHandler *handler); + + HRESULT ( STDMETHODCALLTYPE *CreateWebResourceResponse )( + ICoreWebView2Environment * This, + /* [in] */ IStream *content, + /* [in] */ int statusCode, + /* [in] */ LPCWSTR reasonPhrase, + /* [in] */ LPCWSTR headers, + /* [retval][out] */ ICoreWebView2WebResourceResponse **response); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_BrowserVersionString )( + ICoreWebView2Environment * This, + /* [retval][out] */ LPWSTR *versionInfo); + + HRESULT ( STDMETHODCALLTYPE *add_NewBrowserVersionAvailable )( + ICoreWebView2Environment * This, + /* [in] */ ICoreWebView2NewBrowserVersionAvailableEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_NewBrowserVersionAvailable )( + ICoreWebView2Environment * This, + /* [in] */ EventRegistrationToken token); + + END_INTERFACE + } ICoreWebView2EnvironmentVtbl; + + interface ICoreWebView2Environment + { + CONST_VTBL struct ICoreWebView2EnvironmentVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2Environment_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2Environment_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2Environment_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2Environment_CreateCoreWebView2Controller(This,parentWindow,handler) \ + ( (This)->lpVtbl -> CreateCoreWebView2Controller(This,parentWindow,handler) ) + +#define ICoreWebView2Environment_CreateWebResourceResponse(This,content,statusCode,reasonPhrase,headers,response) \ + ( (This)->lpVtbl -> CreateWebResourceResponse(This,content,statusCode,reasonPhrase,headers,response) ) + +#define ICoreWebView2Environment_get_BrowserVersionString(This,versionInfo) \ + ( (This)->lpVtbl -> get_BrowserVersionString(This,versionInfo) ) + +#define ICoreWebView2Environment_add_NewBrowserVersionAvailable(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_NewBrowserVersionAvailable(This,eventHandler,token) ) + +#define ICoreWebView2Environment_remove_NewBrowserVersionAvailable(This,token) \ + ( (This)->lpVtbl -> remove_NewBrowserVersionAvailable(This,token) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2Environment_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2Environment2_INTERFACE_DEFINED__ +#define __ICoreWebView2Environment2_INTERFACE_DEFINED__ + +/* interface ICoreWebView2Environment2 */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2Environment2 = {0x41F3632B,0x5EF4,0x404F,{0xAD,0x82,0x2D,0x60,0x6C,0x5A,0x9A,0x21}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("41F3632B-5EF4-404F-AD82-2D606C5A9A21") + ICoreWebView2Environment2 : public ICoreWebView2Environment + { + public: + virtual HRESULT STDMETHODCALLTYPE CreateWebResourceRequest( + /* [in] */ LPCWSTR uri, + /* [in] */ LPCWSTR method, + /* [in] */ IStream *postData, + /* [in] */ LPCWSTR headers, + /* [retval][out] */ ICoreWebView2WebResourceRequest **request) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2Environment2Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2Environment2 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2Environment2 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2Environment2 * This); + + HRESULT ( STDMETHODCALLTYPE *CreateCoreWebView2Controller )( + ICoreWebView2Environment2 * This, + HWND parentWindow, + ICoreWebView2CreateCoreWebView2ControllerCompletedHandler *handler); + + HRESULT ( STDMETHODCALLTYPE *CreateWebResourceResponse )( + ICoreWebView2Environment2 * This, + /* [in] */ IStream *content, + /* [in] */ int statusCode, + /* [in] */ LPCWSTR reasonPhrase, + /* [in] */ LPCWSTR headers, + /* [retval][out] */ ICoreWebView2WebResourceResponse **response); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_BrowserVersionString )( + ICoreWebView2Environment2 * This, + /* [retval][out] */ LPWSTR *versionInfo); + + HRESULT ( STDMETHODCALLTYPE *add_NewBrowserVersionAvailable )( + ICoreWebView2Environment2 * This, + /* [in] */ ICoreWebView2NewBrowserVersionAvailableEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_NewBrowserVersionAvailable )( + ICoreWebView2Environment2 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *CreateWebResourceRequest )( + ICoreWebView2Environment2 * This, + /* [in] */ LPCWSTR uri, + /* [in] */ LPCWSTR method, + /* [in] */ IStream *postData, + /* [in] */ LPCWSTR headers, + /* [retval][out] */ ICoreWebView2WebResourceRequest **request); + + END_INTERFACE + } ICoreWebView2Environment2Vtbl; + + interface ICoreWebView2Environment2 + { + CONST_VTBL struct ICoreWebView2Environment2Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2Environment2_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2Environment2_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2Environment2_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2Environment2_CreateCoreWebView2Controller(This,parentWindow,handler) \ + ( (This)->lpVtbl -> CreateCoreWebView2Controller(This,parentWindow,handler) ) + +#define ICoreWebView2Environment2_CreateWebResourceResponse(This,content,statusCode,reasonPhrase,headers,response) \ + ( (This)->lpVtbl -> CreateWebResourceResponse(This,content,statusCode,reasonPhrase,headers,response) ) + +#define ICoreWebView2Environment2_get_BrowserVersionString(This,versionInfo) \ + ( (This)->lpVtbl -> get_BrowserVersionString(This,versionInfo) ) + +#define ICoreWebView2Environment2_add_NewBrowserVersionAvailable(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_NewBrowserVersionAvailable(This,eventHandler,token) ) + +#define ICoreWebView2Environment2_remove_NewBrowserVersionAvailable(This,token) \ + ( (This)->lpVtbl -> remove_NewBrowserVersionAvailable(This,token) ) + + +#define ICoreWebView2Environment2_CreateWebResourceRequest(This,uri,method,postData,headers,request) \ + ( (This)->lpVtbl -> CreateWebResourceRequest(This,uri,method,postData,headers,request) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2Environment2_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2Environment3_INTERFACE_DEFINED__ +#define __ICoreWebView2Environment3_INTERFACE_DEFINED__ + +/* interface ICoreWebView2Environment3 */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2Environment3 = {0x80a22ae3,0xbe7c,0x4ce2,{0xaf,0xe1,0x5a,0x50,0x05,0x6c,0xde,0xeb}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("80a22ae3-be7c-4ce2-afe1-5a50056cdeeb") + ICoreWebView2Environment3 : public ICoreWebView2Environment2 + { + public: + virtual HRESULT STDMETHODCALLTYPE CreateCoreWebView2CompositionController( + HWND parentWindow, + ICoreWebView2CreateCoreWebView2CompositionControllerCompletedHandler *handler) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateCoreWebView2PointerInfo( + /* [retval][out] */ ICoreWebView2PointerInfo **pointerInfo) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2Environment3Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2Environment3 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2Environment3 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2Environment3 * This); + + HRESULT ( STDMETHODCALLTYPE *CreateCoreWebView2Controller )( + ICoreWebView2Environment3 * This, + HWND parentWindow, + ICoreWebView2CreateCoreWebView2ControllerCompletedHandler *handler); + + HRESULT ( STDMETHODCALLTYPE *CreateWebResourceResponse )( + ICoreWebView2Environment3 * This, + /* [in] */ IStream *content, + /* [in] */ int statusCode, + /* [in] */ LPCWSTR reasonPhrase, + /* [in] */ LPCWSTR headers, + /* [retval][out] */ ICoreWebView2WebResourceResponse **response); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_BrowserVersionString )( + ICoreWebView2Environment3 * This, + /* [retval][out] */ LPWSTR *versionInfo); + + HRESULT ( STDMETHODCALLTYPE *add_NewBrowserVersionAvailable )( + ICoreWebView2Environment3 * This, + /* [in] */ ICoreWebView2NewBrowserVersionAvailableEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_NewBrowserVersionAvailable )( + ICoreWebView2Environment3 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *CreateWebResourceRequest )( + ICoreWebView2Environment3 * This, + /* [in] */ LPCWSTR uri, + /* [in] */ LPCWSTR method, + /* [in] */ IStream *postData, + /* [in] */ LPCWSTR headers, + /* [retval][out] */ ICoreWebView2WebResourceRequest **request); + + HRESULT ( STDMETHODCALLTYPE *CreateCoreWebView2CompositionController )( + ICoreWebView2Environment3 * This, + HWND parentWindow, + ICoreWebView2CreateCoreWebView2CompositionControllerCompletedHandler *handler); + + HRESULT ( STDMETHODCALLTYPE *CreateCoreWebView2PointerInfo )( + ICoreWebView2Environment3 * This, + /* [retval][out] */ ICoreWebView2PointerInfo **pointerInfo); + + END_INTERFACE + } ICoreWebView2Environment3Vtbl; + + interface ICoreWebView2Environment3 + { + CONST_VTBL struct ICoreWebView2Environment3Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2Environment3_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2Environment3_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2Environment3_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2Environment3_CreateCoreWebView2Controller(This,parentWindow,handler) \ + ( (This)->lpVtbl -> CreateCoreWebView2Controller(This,parentWindow,handler) ) + +#define ICoreWebView2Environment3_CreateWebResourceResponse(This,content,statusCode,reasonPhrase,headers,response) \ + ( (This)->lpVtbl -> CreateWebResourceResponse(This,content,statusCode,reasonPhrase,headers,response) ) + +#define ICoreWebView2Environment3_get_BrowserVersionString(This,versionInfo) \ + ( (This)->lpVtbl -> get_BrowserVersionString(This,versionInfo) ) + +#define ICoreWebView2Environment3_add_NewBrowserVersionAvailable(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_NewBrowserVersionAvailable(This,eventHandler,token) ) + +#define ICoreWebView2Environment3_remove_NewBrowserVersionAvailable(This,token) \ + ( (This)->lpVtbl -> remove_NewBrowserVersionAvailable(This,token) ) + + +#define ICoreWebView2Environment3_CreateWebResourceRequest(This,uri,method,postData,headers,request) \ + ( (This)->lpVtbl -> CreateWebResourceRequest(This,uri,method,postData,headers,request) ) + + +#define ICoreWebView2Environment3_CreateCoreWebView2CompositionController(This,parentWindow,handler) \ + ( (This)->lpVtbl -> CreateCoreWebView2CompositionController(This,parentWindow,handler) ) + +#define ICoreWebView2Environment3_CreateCoreWebView2PointerInfo(This,pointerInfo) \ + ( (This)->lpVtbl -> CreateCoreWebView2PointerInfo(This,pointerInfo) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2Environment3_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2Environment4_INTERFACE_DEFINED__ +#define __ICoreWebView2Environment4_INTERFACE_DEFINED__ + +/* interface ICoreWebView2Environment4 */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2Environment4 = {0x20944379,0x6dcf,0x41d6,{0xa0,0xa0,0xab,0xc0,0xfc,0x50,0xde,0x0d}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("20944379-6dcf-41d6-a0a0-abc0fc50de0d") + ICoreWebView2Environment4 : public ICoreWebView2Environment3 + { + public: + virtual HRESULT STDMETHODCALLTYPE GetProviderForHwnd( + /* [in] */ HWND hwnd, + /* [retval][out] */ IUnknown **provider) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2Environment4Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2Environment4 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2Environment4 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2Environment4 * This); + + HRESULT ( STDMETHODCALLTYPE *CreateCoreWebView2Controller )( + ICoreWebView2Environment4 * This, + HWND parentWindow, + ICoreWebView2CreateCoreWebView2ControllerCompletedHandler *handler); + + HRESULT ( STDMETHODCALLTYPE *CreateWebResourceResponse )( + ICoreWebView2Environment4 * This, + /* [in] */ IStream *content, + /* [in] */ int statusCode, + /* [in] */ LPCWSTR reasonPhrase, + /* [in] */ LPCWSTR headers, + /* [retval][out] */ ICoreWebView2WebResourceResponse **response); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_BrowserVersionString )( + ICoreWebView2Environment4 * This, + /* [retval][out] */ LPWSTR *versionInfo); + + HRESULT ( STDMETHODCALLTYPE *add_NewBrowserVersionAvailable )( + ICoreWebView2Environment4 * This, + /* [in] */ ICoreWebView2NewBrowserVersionAvailableEventHandler *eventHandler, + /* [out] */ EventRegistrationToken *token); + + HRESULT ( STDMETHODCALLTYPE *remove_NewBrowserVersionAvailable )( + ICoreWebView2Environment4 * This, + /* [in] */ EventRegistrationToken token); + + HRESULT ( STDMETHODCALLTYPE *CreateWebResourceRequest )( + ICoreWebView2Environment4 * This, + /* [in] */ LPCWSTR uri, + /* [in] */ LPCWSTR method, + /* [in] */ IStream *postData, + /* [in] */ LPCWSTR headers, + /* [retval][out] */ ICoreWebView2WebResourceRequest **request); + + HRESULT ( STDMETHODCALLTYPE *CreateCoreWebView2CompositionController )( + ICoreWebView2Environment4 * This, + HWND parentWindow, + ICoreWebView2CreateCoreWebView2CompositionControllerCompletedHandler *handler); + + HRESULT ( STDMETHODCALLTYPE *CreateCoreWebView2PointerInfo )( + ICoreWebView2Environment4 * This, + /* [retval][out] */ ICoreWebView2PointerInfo **pointerInfo); + + HRESULT ( STDMETHODCALLTYPE *GetProviderForHwnd )( + ICoreWebView2Environment4 * This, + /* [in] */ HWND hwnd, + /* [retval][out] */ IUnknown **provider); + + END_INTERFACE + } ICoreWebView2Environment4Vtbl; + + interface ICoreWebView2Environment4 + { + CONST_VTBL struct ICoreWebView2Environment4Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2Environment4_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2Environment4_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2Environment4_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2Environment4_CreateCoreWebView2Controller(This,parentWindow,handler) \ + ( (This)->lpVtbl -> CreateCoreWebView2Controller(This,parentWindow,handler) ) + +#define ICoreWebView2Environment4_CreateWebResourceResponse(This,content,statusCode,reasonPhrase,headers,response) \ + ( (This)->lpVtbl -> CreateWebResourceResponse(This,content,statusCode,reasonPhrase,headers,response) ) + +#define ICoreWebView2Environment4_get_BrowserVersionString(This,versionInfo) \ + ( (This)->lpVtbl -> get_BrowserVersionString(This,versionInfo) ) + +#define ICoreWebView2Environment4_add_NewBrowserVersionAvailable(This,eventHandler,token) \ + ( (This)->lpVtbl -> add_NewBrowserVersionAvailable(This,eventHandler,token) ) + +#define ICoreWebView2Environment4_remove_NewBrowserVersionAvailable(This,token) \ + ( (This)->lpVtbl -> remove_NewBrowserVersionAvailable(This,token) ) + + +#define ICoreWebView2Environment4_CreateWebResourceRequest(This,uri,method,postData,headers,request) \ + ( (This)->lpVtbl -> CreateWebResourceRequest(This,uri,method,postData,headers,request) ) + + +#define ICoreWebView2Environment4_CreateCoreWebView2CompositionController(This,parentWindow,handler) \ + ( (This)->lpVtbl -> CreateCoreWebView2CompositionController(This,parentWindow,handler) ) + +#define ICoreWebView2Environment4_CreateCoreWebView2PointerInfo(This,pointerInfo) \ + ( (This)->lpVtbl -> CreateCoreWebView2PointerInfo(This,pointerInfo) ) + + +#define ICoreWebView2Environment4_GetProviderForHwnd(This,hwnd,provider) \ + ( (This)->lpVtbl -> GetProviderForHwnd(This,hwnd,provider) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2Environment4_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2EnvironmentOptions_INTERFACE_DEFINED__ +#define __ICoreWebView2EnvironmentOptions_INTERFACE_DEFINED__ + +/* interface ICoreWebView2EnvironmentOptions */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2EnvironmentOptions = {0x2fde08a8,0x1e9a,0x4766,{0x8c,0x05,0x95,0xa9,0xce,0xb9,0xd1,0xc5}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("2fde08a8-1e9a-4766-8c05-95a9ceb9d1c5") + ICoreWebView2EnvironmentOptions : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_AdditionalBrowserArguments( + /* [retval][out] */ LPWSTR *value) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_AdditionalBrowserArguments( + /* [in] */ LPCWSTR value) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Language( + /* [retval][out] */ LPWSTR *value) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_Language( + /* [in] */ LPCWSTR value) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_TargetCompatibleBrowserVersion( + /* [retval][out] */ LPWSTR *value) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_TargetCompatibleBrowserVersion( + /* [in] */ LPCWSTR value) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_AllowSingleSignOnUsingOSPrimaryAccount( + /* [retval][out] */ BOOL *allow) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_AllowSingleSignOnUsingOSPrimaryAccount( + /* [in] */ BOOL allow) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2EnvironmentOptionsVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2EnvironmentOptions * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2EnvironmentOptions * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2EnvironmentOptions * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_AdditionalBrowserArguments )( + ICoreWebView2EnvironmentOptions * This, + /* [retval][out] */ LPWSTR *value); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_AdditionalBrowserArguments )( + ICoreWebView2EnvironmentOptions * This, + /* [in] */ LPCWSTR value); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Language )( + ICoreWebView2EnvironmentOptions * This, + /* [retval][out] */ LPWSTR *value); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_Language )( + ICoreWebView2EnvironmentOptions * This, + /* [in] */ LPCWSTR value); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_TargetCompatibleBrowserVersion )( + ICoreWebView2EnvironmentOptions * This, + /* [retval][out] */ LPWSTR *value); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_TargetCompatibleBrowserVersion )( + ICoreWebView2EnvironmentOptions * This, + /* [in] */ LPCWSTR value); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_AllowSingleSignOnUsingOSPrimaryAccount )( + ICoreWebView2EnvironmentOptions * This, + /* [retval][out] */ BOOL *allow); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_AllowSingleSignOnUsingOSPrimaryAccount )( + ICoreWebView2EnvironmentOptions * This, + /* [in] */ BOOL allow); + + END_INTERFACE + } ICoreWebView2EnvironmentOptionsVtbl; + + interface ICoreWebView2EnvironmentOptions + { + CONST_VTBL struct ICoreWebView2EnvironmentOptionsVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2EnvironmentOptions_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2EnvironmentOptions_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2EnvironmentOptions_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2EnvironmentOptions_get_AdditionalBrowserArguments(This,value) \ + ( (This)->lpVtbl -> get_AdditionalBrowserArguments(This,value) ) + +#define ICoreWebView2EnvironmentOptions_put_AdditionalBrowserArguments(This,value) \ + ( (This)->lpVtbl -> put_AdditionalBrowserArguments(This,value) ) + +#define ICoreWebView2EnvironmentOptions_get_Language(This,value) \ + ( (This)->lpVtbl -> get_Language(This,value) ) + +#define ICoreWebView2EnvironmentOptions_put_Language(This,value) \ + ( (This)->lpVtbl -> put_Language(This,value) ) + +#define ICoreWebView2EnvironmentOptions_get_TargetCompatibleBrowserVersion(This,value) \ + ( (This)->lpVtbl -> get_TargetCompatibleBrowserVersion(This,value) ) + +#define ICoreWebView2EnvironmentOptions_put_TargetCompatibleBrowserVersion(This,value) \ + ( (This)->lpVtbl -> put_TargetCompatibleBrowserVersion(This,value) ) + +#define ICoreWebView2EnvironmentOptions_get_AllowSingleSignOnUsingOSPrimaryAccount(This,allow) \ + ( (This)->lpVtbl -> get_AllowSingleSignOnUsingOSPrimaryAccount(This,allow) ) + +#define ICoreWebView2EnvironmentOptions_put_AllowSingleSignOnUsingOSPrimaryAccount(This,allow) \ + ( (This)->lpVtbl -> put_AllowSingleSignOnUsingOSPrimaryAccount(This,allow) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2EnvironmentOptions_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2ExecuteScriptCompletedHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2ExecuteScriptCompletedHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2ExecuteScriptCompletedHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2ExecuteScriptCompletedHandler = {0x49511172,0xcc67,0x4bca,{0x99,0x23,0x13,0x71,0x12,0xf4,0xc4,0xcc}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("49511172-cc67-4bca-9923-137112f4c4cc") + ICoreWebView2ExecuteScriptCompletedHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + /* [in] */ HRESULT errorCode, + /* [in] */ LPCWSTR resultObjectAsJson) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2ExecuteScriptCompletedHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2ExecuteScriptCompletedHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2ExecuteScriptCompletedHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2ExecuteScriptCompletedHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2ExecuteScriptCompletedHandler * This, + /* [in] */ HRESULT errorCode, + /* [in] */ LPCWSTR resultObjectAsJson); + + END_INTERFACE + } ICoreWebView2ExecuteScriptCompletedHandlerVtbl; + + interface ICoreWebView2ExecuteScriptCompletedHandler + { + CONST_VTBL struct ICoreWebView2ExecuteScriptCompletedHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2ExecuteScriptCompletedHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2ExecuteScriptCompletedHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2ExecuteScriptCompletedHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2ExecuteScriptCompletedHandler_Invoke(This,errorCode,resultObjectAsJson) \ + ( (This)->lpVtbl -> Invoke(This,errorCode,resultObjectAsJson) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2ExecuteScriptCompletedHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2FrameInfo_INTERFACE_DEFINED__ +#define __ICoreWebView2FrameInfo_INTERFACE_DEFINED__ + +/* interface ICoreWebView2FrameInfo */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2FrameInfo = {0xda86b8a1,0xbdf3,0x4f11,{0x99,0x55,0x52,0x8c,0xef,0xa5,0x97,0x27}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("da86b8a1-bdf3-4f11-9955-528cefa59727") + ICoreWebView2FrameInfo : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Name( + /* [retval][out] */ LPWSTR *name) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Source( + /* [retval][out] */ LPWSTR *source) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2FrameInfoVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2FrameInfo * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2FrameInfo * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2FrameInfo * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Name )( + ICoreWebView2FrameInfo * This, + /* [retval][out] */ LPWSTR *name); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Source )( + ICoreWebView2FrameInfo * This, + /* [retval][out] */ LPWSTR *source); + + END_INTERFACE + } ICoreWebView2FrameInfoVtbl; + + interface ICoreWebView2FrameInfo + { + CONST_VTBL struct ICoreWebView2FrameInfoVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2FrameInfo_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2FrameInfo_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2FrameInfo_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2FrameInfo_get_Name(This,name) \ + ( (This)->lpVtbl -> get_Name(This,name) ) + +#define ICoreWebView2FrameInfo_get_Source(This,source) \ + ( (This)->lpVtbl -> get_Source(This,source) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2FrameInfo_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2FrameInfoCollection_INTERFACE_DEFINED__ +#define __ICoreWebView2FrameInfoCollection_INTERFACE_DEFINED__ + +/* interface ICoreWebView2FrameInfoCollection */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2FrameInfoCollection = {0x8f834154,0xd38e,0x4d90,{0xaf,0xfb,0x68,0x00,0xa7,0x27,0x28,0x39}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("8f834154-d38e-4d90-affb-6800a7272839") + ICoreWebView2FrameInfoCollection : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetIterator( + /* [retval][out] */ ICoreWebView2FrameInfoCollectionIterator **iterator) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2FrameInfoCollectionVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2FrameInfoCollection * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2FrameInfoCollection * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2FrameInfoCollection * This); + + HRESULT ( STDMETHODCALLTYPE *GetIterator )( + ICoreWebView2FrameInfoCollection * This, + /* [retval][out] */ ICoreWebView2FrameInfoCollectionIterator **iterator); + + END_INTERFACE + } ICoreWebView2FrameInfoCollectionVtbl; + + interface ICoreWebView2FrameInfoCollection + { + CONST_VTBL struct ICoreWebView2FrameInfoCollectionVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2FrameInfoCollection_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2FrameInfoCollection_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2FrameInfoCollection_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2FrameInfoCollection_GetIterator(This,iterator) \ + ( (This)->lpVtbl -> GetIterator(This,iterator) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2FrameInfoCollection_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2FrameInfoCollectionIterator_INTERFACE_DEFINED__ +#define __ICoreWebView2FrameInfoCollectionIterator_INTERFACE_DEFINED__ + +/* interface ICoreWebView2FrameInfoCollectionIterator */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2FrameInfoCollectionIterator = {0x1bf89e2d,0x1b2b,0x4629,{0xb2,0x8f,0x05,0x09,0x9b,0x41,0xbb,0x03}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("1bf89e2d-1b2b-4629-b28f-05099b41bb03") + ICoreWebView2FrameInfoCollectionIterator : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_HasCurrent( + /* [retval][out] */ BOOL *hasCurrent) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetCurrent( + /* [retval][out] */ ICoreWebView2FrameInfo **frameInfo) = 0; + + virtual HRESULT STDMETHODCALLTYPE MoveNext( + /* [retval][out] */ BOOL *hasNext) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2FrameInfoCollectionIteratorVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2FrameInfoCollectionIterator * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2FrameInfoCollectionIterator * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2FrameInfoCollectionIterator * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_HasCurrent )( + ICoreWebView2FrameInfoCollectionIterator * This, + /* [retval][out] */ BOOL *hasCurrent); + + HRESULT ( STDMETHODCALLTYPE *GetCurrent )( + ICoreWebView2FrameInfoCollectionIterator * This, + /* [retval][out] */ ICoreWebView2FrameInfo **frameInfo); + + HRESULT ( STDMETHODCALLTYPE *MoveNext )( + ICoreWebView2FrameInfoCollectionIterator * This, + /* [retval][out] */ BOOL *hasNext); + + END_INTERFACE + } ICoreWebView2FrameInfoCollectionIteratorVtbl; + + interface ICoreWebView2FrameInfoCollectionIterator + { + CONST_VTBL struct ICoreWebView2FrameInfoCollectionIteratorVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2FrameInfoCollectionIterator_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2FrameInfoCollectionIterator_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2FrameInfoCollectionIterator_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2FrameInfoCollectionIterator_get_HasCurrent(This,hasCurrent) \ + ( (This)->lpVtbl -> get_HasCurrent(This,hasCurrent) ) + +#define ICoreWebView2FrameInfoCollectionIterator_GetCurrent(This,frameInfo) \ + ( (This)->lpVtbl -> GetCurrent(This,frameInfo) ) + +#define ICoreWebView2FrameInfoCollectionIterator_MoveNext(This,hasNext) \ + ( (This)->lpVtbl -> MoveNext(This,hasNext) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2FrameInfoCollectionIterator_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2FocusChangedEventHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2FocusChangedEventHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2FocusChangedEventHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2FocusChangedEventHandler = {0x05ea24bd,0x6452,0x4926,{0x90,0x14,0x4b,0x82,0xb4,0x98,0x13,0x5d}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("05ea24bd-6452-4926-9014-4b82b498135d") + ICoreWebView2FocusChangedEventHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + /* [in] */ ICoreWebView2Controller *sender, + /* [in] */ IUnknown *args) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2FocusChangedEventHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2FocusChangedEventHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2FocusChangedEventHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2FocusChangedEventHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2FocusChangedEventHandler * This, + /* [in] */ ICoreWebView2Controller *sender, + /* [in] */ IUnknown *args); + + END_INTERFACE + } ICoreWebView2FocusChangedEventHandlerVtbl; + + interface ICoreWebView2FocusChangedEventHandler + { + CONST_VTBL struct ICoreWebView2FocusChangedEventHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2FocusChangedEventHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2FocusChangedEventHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2FocusChangedEventHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2FocusChangedEventHandler_Invoke(This,sender,args) \ + ( (This)->lpVtbl -> Invoke(This,sender,args) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2FocusChangedEventHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2GetCookiesCompletedHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2GetCookiesCompletedHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2GetCookiesCompletedHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2GetCookiesCompletedHandler = {0x5A4F5069,0x5C15,0x47C3,{0x86,0x46,0xF4,0xDE,0x1C,0x11,0x66,0x70}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("5A4F5069-5C15-47C3-8646-F4DE1C116670") + ICoreWebView2GetCookiesCompletedHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + HRESULT result, + ICoreWebView2CookieList *cookieList) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2GetCookiesCompletedHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2GetCookiesCompletedHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2GetCookiesCompletedHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2GetCookiesCompletedHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2GetCookiesCompletedHandler * This, + HRESULT result, + ICoreWebView2CookieList *cookieList); + + END_INTERFACE + } ICoreWebView2GetCookiesCompletedHandlerVtbl; + + interface ICoreWebView2GetCookiesCompletedHandler + { + CONST_VTBL struct ICoreWebView2GetCookiesCompletedHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2GetCookiesCompletedHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2GetCookiesCompletedHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2GetCookiesCompletedHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2GetCookiesCompletedHandler_Invoke(This,result,cookieList) \ + ( (This)->lpVtbl -> Invoke(This,result,cookieList) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2GetCookiesCompletedHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2HistoryChangedEventHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2HistoryChangedEventHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2HistoryChangedEventHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2HistoryChangedEventHandler = {0xc79a420c,0xefd9,0x4058,{0x92,0x95,0x3e,0x8b,0x4b,0xca,0xb6,0x45}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("c79a420c-efd9-4058-9295-3e8b4bcab645") + ICoreWebView2HistoryChangedEventHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + /* [in] */ ICoreWebView2 *sender, + /* [in] */ IUnknown *args) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2HistoryChangedEventHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2HistoryChangedEventHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2HistoryChangedEventHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2HistoryChangedEventHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2HistoryChangedEventHandler * This, + /* [in] */ ICoreWebView2 *sender, + /* [in] */ IUnknown *args); + + END_INTERFACE + } ICoreWebView2HistoryChangedEventHandlerVtbl; + + interface ICoreWebView2HistoryChangedEventHandler + { + CONST_VTBL struct ICoreWebView2HistoryChangedEventHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2HistoryChangedEventHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2HistoryChangedEventHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2HistoryChangedEventHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2HistoryChangedEventHandler_Invoke(This,sender,args) \ + ( (This)->lpVtbl -> Invoke(This,sender,args) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2HistoryChangedEventHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2HttpHeadersCollectionIterator_INTERFACE_DEFINED__ +#define __ICoreWebView2HttpHeadersCollectionIterator_INTERFACE_DEFINED__ + +/* interface ICoreWebView2HttpHeadersCollectionIterator */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2HttpHeadersCollectionIterator = {0x0702fc30,0xf43b,0x47bb,{0xab,0x52,0xa4,0x2c,0xb5,0x52,0xad,0x9f}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("0702fc30-f43b-47bb-ab52-a42cb552ad9f") + ICoreWebView2HttpHeadersCollectionIterator : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetCurrentHeader( + /* [out] */ LPWSTR *name, + /* [out] */ LPWSTR *value) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_HasCurrentHeader( + /* [retval][out] */ BOOL *hasCurrent) = 0; + + virtual HRESULT STDMETHODCALLTYPE MoveNext( + /* [retval][out] */ BOOL *hasNext) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2HttpHeadersCollectionIteratorVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2HttpHeadersCollectionIterator * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2HttpHeadersCollectionIterator * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2HttpHeadersCollectionIterator * This); + + HRESULT ( STDMETHODCALLTYPE *GetCurrentHeader )( + ICoreWebView2HttpHeadersCollectionIterator * This, + /* [out] */ LPWSTR *name, + /* [out] */ LPWSTR *value); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_HasCurrentHeader )( + ICoreWebView2HttpHeadersCollectionIterator * This, + /* [retval][out] */ BOOL *hasCurrent); + + HRESULT ( STDMETHODCALLTYPE *MoveNext )( + ICoreWebView2HttpHeadersCollectionIterator * This, + /* [retval][out] */ BOOL *hasNext); + + END_INTERFACE + } ICoreWebView2HttpHeadersCollectionIteratorVtbl; + + interface ICoreWebView2HttpHeadersCollectionIterator + { + CONST_VTBL struct ICoreWebView2HttpHeadersCollectionIteratorVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2HttpHeadersCollectionIterator_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2HttpHeadersCollectionIterator_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2HttpHeadersCollectionIterator_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2HttpHeadersCollectionIterator_GetCurrentHeader(This,name,value) \ + ( (This)->lpVtbl -> GetCurrentHeader(This,name,value) ) + +#define ICoreWebView2HttpHeadersCollectionIterator_get_HasCurrentHeader(This,hasCurrent) \ + ( (This)->lpVtbl -> get_HasCurrentHeader(This,hasCurrent) ) + +#define ICoreWebView2HttpHeadersCollectionIterator_MoveNext(This,hasNext) \ + ( (This)->lpVtbl -> MoveNext(This,hasNext) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2HttpHeadersCollectionIterator_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2HttpRequestHeaders_INTERFACE_DEFINED__ +#define __ICoreWebView2HttpRequestHeaders_INTERFACE_DEFINED__ + +/* interface ICoreWebView2HttpRequestHeaders */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2HttpRequestHeaders = {0xe86cac0e,0x5523,0x465c,{0xb5,0x36,0x8f,0xb9,0xfc,0x8c,0x8c,0x60}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("e86cac0e-5523-465c-b536-8fb9fc8c8c60") + ICoreWebView2HttpRequestHeaders : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetHeader( + /* [in] */ LPCWSTR name, + /* [retval][out] */ LPWSTR *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetHeaders( + /* [in] */ LPCWSTR name, + /* [retval][out] */ ICoreWebView2HttpHeadersCollectionIterator **iterator) = 0; + + virtual HRESULT STDMETHODCALLTYPE Contains( + /* [in] */ LPCWSTR name, + /* [retval][out] */ BOOL *contains) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetHeader( + /* [in] */ LPCWSTR name, + /* [in] */ LPCWSTR value) = 0; + + virtual HRESULT STDMETHODCALLTYPE RemoveHeader( + /* [in] */ LPCWSTR name) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetIterator( + /* [retval][out] */ ICoreWebView2HttpHeadersCollectionIterator **iterator) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2HttpRequestHeadersVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2HttpRequestHeaders * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2HttpRequestHeaders * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2HttpRequestHeaders * This); + + HRESULT ( STDMETHODCALLTYPE *GetHeader )( + ICoreWebView2HttpRequestHeaders * This, + /* [in] */ LPCWSTR name, + /* [retval][out] */ LPWSTR *value); + + HRESULT ( STDMETHODCALLTYPE *GetHeaders )( + ICoreWebView2HttpRequestHeaders * This, + /* [in] */ LPCWSTR name, + /* [retval][out] */ ICoreWebView2HttpHeadersCollectionIterator **iterator); + + HRESULT ( STDMETHODCALLTYPE *Contains )( + ICoreWebView2HttpRequestHeaders * This, + /* [in] */ LPCWSTR name, + /* [retval][out] */ BOOL *contains); + + HRESULT ( STDMETHODCALLTYPE *SetHeader )( + ICoreWebView2HttpRequestHeaders * This, + /* [in] */ LPCWSTR name, + /* [in] */ LPCWSTR value); + + HRESULT ( STDMETHODCALLTYPE *RemoveHeader )( + ICoreWebView2HttpRequestHeaders * This, + /* [in] */ LPCWSTR name); + + HRESULT ( STDMETHODCALLTYPE *GetIterator )( + ICoreWebView2HttpRequestHeaders * This, + /* [retval][out] */ ICoreWebView2HttpHeadersCollectionIterator **iterator); + + END_INTERFACE + } ICoreWebView2HttpRequestHeadersVtbl; + + interface ICoreWebView2HttpRequestHeaders + { + CONST_VTBL struct ICoreWebView2HttpRequestHeadersVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2HttpRequestHeaders_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2HttpRequestHeaders_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2HttpRequestHeaders_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2HttpRequestHeaders_GetHeader(This,name,value) \ + ( (This)->lpVtbl -> GetHeader(This,name,value) ) + +#define ICoreWebView2HttpRequestHeaders_GetHeaders(This,name,iterator) \ + ( (This)->lpVtbl -> GetHeaders(This,name,iterator) ) + +#define ICoreWebView2HttpRequestHeaders_Contains(This,name,contains) \ + ( (This)->lpVtbl -> Contains(This,name,contains) ) + +#define ICoreWebView2HttpRequestHeaders_SetHeader(This,name,value) \ + ( (This)->lpVtbl -> SetHeader(This,name,value) ) + +#define ICoreWebView2HttpRequestHeaders_RemoveHeader(This,name) \ + ( (This)->lpVtbl -> RemoveHeader(This,name) ) + +#define ICoreWebView2HttpRequestHeaders_GetIterator(This,iterator) \ + ( (This)->lpVtbl -> GetIterator(This,iterator) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2HttpRequestHeaders_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2HttpResponseHeaders_INTERFACE_DEFINED__ +#define __ICoreWebView2HttpResponseHeaders_INTERFACE_DEFINED__ + +/* interface ICoreWebView2HttpResponseHeaders */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2HttpResponseHeaders = {0x03c5ff5a,0x9b45,0x4a88,{0x88,0x1c,0x89,0xa9,0xf3,0x28,0x61,0x9c}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("03c5ff5a-9b45-4a88-881c-89a9f328619c") + ICoreWebView2HttpResponseHeaders : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE AppendHeader( + /* [in] */ LPCWSTR name, + /* [in] */ LPCWSTR value) = 0; + + virtual HRESULT STDMETHODCALLTYPE Contains( + /* [in] */ LPCWSTR name, + /* [retval][out] */ BOOL *contains) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetHeader( + /* [in] */ LPCWSTR name, + /* [retval][out] */ LPWSTR *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetHeaders( + /* [in] */ LPCWSTR name, + /* [retval][out] */ ICoreWebView2HttpHeadersCollectionIterator **iterator) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetIterator( + /* [retval][out] */ ICoreWebView2HttpHeadersCollectionIterator **iterator) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2HttpResponseHeadersVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2HttpResponseHeaders * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2HttpResponseHeaders * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2HttpResponseHeaders * This); + + HRESULT ( STDMETHODCALLTYPE *AppendHeader )( + ICoreWebView2HttpResponseHeaders * This, + /* [in] */ LPCWSTR name, + /* [in] */ LPCWSTR value); + + HRESULT ( STDMETHODCALLTYPE *Contains )( + ICoreWebView2HttpResponseHeaders * This, + /* [in] */ LPCWSTR name, + /* [retval][out] */ BOOL *contains); + + HRESULT ( STDMETHODCALLTYPE *GetHeader )( + ICoreWebView2HttpResponseHeaders * This, + /* [in] */ LPCWSTR name, + /* [retval][out] */ LPWSTR *value); + + HRESULT ( STDMETHODCALLTYPE *GetHeaders )( + ICoreWebView2HttpResponseHeaders * This, + /* [in] */ LPCWSTR name, + /* [retval][out] */ ICoreWebView2HttpHeadersCollectionIterator **iterator); + + HRESULT ( STDMETHODCALLTYPE *GetIterator )( + ICoreWebView2HttpResponseHeaders * This, + /* [retval][out] */ ICoreWebView2HttpHeadersCollectionIterator **iterator); + + END_INTERFACE + } ICoreWebView2HttpResponseHeadersVtbl; + + interface ICoreWebView2HttpResponseHeaders + { + CONST_VTBL struct ICoreWebView2HttpResponseHeadersVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2HttpResponseHeaders_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2HttpResponseHeaders_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2HttpResponseHeaders_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2HttpResponseHeaders_AppendHeader(This,name,value) \ + ( (This)->lpVtbl -> AppendHeader(This,name,value) ) + +#define ICoreWebView2HttpResponseHeaders_Contains(This,name,contains) \ + ( (This)->lpVtbl -> Contains(This,name,contains) ) + +#define ICoreWebView2HttpResponseHeaders_GetHeader(This,name,value) \ + ( (This)->lpVtbl -> GetHeader(This,name,value) ) + +#define ICoreWebView2HttpResponseHeaders_GetHeaders(This,name,iterator) \ + ( (This)->lpVtbl -> GetHeaders(This,name,iterator) ) + +#define ICoreWebView2HttpResponseHeaders_GetIterator(This,iterator) \ + ( (This)->lpVtbl -> GetIterator(This,iterator) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2HttpResponseHeaders_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2Interop_INTERFACE_DEFINED__ +#define __ICoreWebView2Interop_INTERFACE_DEFINED__ + +/* interface ICoreWebView2Interop */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2Interop = {0x912b34a7,0xd10b,0x49c4,{0xaf,0x18,0x7c,0xb7,0xe6,0x04,0xe0,0x1a}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("912b34a7-d10b-49c4-af18-7cb7e604e01a") + ICoreWebView2Interop : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE AddHostObjectToScript( + /* [in] */ LPCWSTR name, + /* [in] */ VARIANT *object) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2InteropVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2Interop * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2Interop * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2Interop * This); + + HRESULT ( STDMETHODCALLTYPE *AddHostObjectToScript )( + ICoreWebView2Interop * This, + /* [in] */ LPCWSTR name, + /* [in] */ VARIANT *object); + + END_INTERFACE + } ICoreWebView2InteropVtbl; + + interface ICoreWebView2Interop + { + CONST_VTBL struct ICoreWebView2InteropVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2Interop_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2Interop_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2Interop_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2Interop_AddHostObjectToScript(This,name,object) \ + ( (This)->lpVtbl -> AddHostObjectToScript(This,name,object) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2Interop_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2MoveFocusRequestedEventArgs_INTERFACE_DEFINED__ +#define __ICoreWebView2MoveFocusRequestedEventArgs_INTERFACE_DEFINED__ + +/* interface ICoreWebView2MoveFocusRequestedEventArgs */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2MoveFocusRequestedEventArgs = {0x2d6aa13b,0x3839,0x4a15,{0x92,0xfc,0xd8,0x8b,0x3c,0x0d,0x9c,0x9d}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("2d6aa13b-3839-4a15-92fc-d88b3c0d9c9d") + ICoreWebView2MoveFocusRequestedEventArgs : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Reason( + /* [retval][out] */ COREWEBVIEW2_MOVE_FOCUS_REASON *reason) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Handled( + /* [retval][out] */ BOOL *value) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_Handled( + /* [in] */ BOOL value) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2MoveFocusRequestedEventArgsVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2MoveFocusRequestedEventArgs * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2MoveFocusRequestedEventArgs * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2MoveFocusRequestedEventArgs * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Reason )( + ICoreWebView2MoveFocusRequestedEventArgs * This, + /* [retval][out] */ COREWEBVIEW2_MOVE_FOCUS_REASON *reason); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Handled )( + ICoreWebView2MoveFocusRequestedEventArgs * This, + /* [retval][out] */ BOOL *value); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_Handled )( + ICoreWebView2MoveFocusRequestedEventArgs * This, + /* [in] */ BOOL value); + + END_INTERFACE + } ICoreWebView2MoveFocusRequestedEventArgsVtbl; + + interface ICoreWebView2MoveFocusRequestedEventArgs + { + CONST_VTBL struct ICoreWebView2MoveFocusRequestedEventArgsVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2MoveFocusRequestedEventArgs_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2MoveFocusRequestedEventArgs_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2MoveFocusRequestedEventArgs_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2MoveFocusRequestedEventArgs_get_Reason(This,reason) \ + ( (This)->lpVtbl -> get_Reason(This,reason) ) + +#define ICoreWebView2MoveFocusRequestedEventArgs_get_Handled(This,value) \ + ( (This)->lpVtbl -> get_Handled(This,value) ) + +#define ICoreWebView2MoveFocusRequestedEventArgs_put_Handled(This,value) \ + ( (This)->lpVtbl -> put_Handled(This,value) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2MoveFocusRequestedEventArgs_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2MoveFocusRequestedEventHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2MoveFocusRequestedEventHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2MoveFocusRequestedEventHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2MoveFocusRequestedEventHandler = {0x69035451,0x6dc7,0x4cb8,{0x9b,0xce,0xb2,0xbd,0x70,0xad,0x28,0x9f}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("69035451-6dc7-4cb8-9bce-b2bd70ad289f") + ICoreWebView2MoveFocusRequestedEventHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + /* [in] */ ICoreWebView2Controller *sender, + /* [in] */ ICoreWebView2MoveFocusRequestedEventArgs *args) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2MoveFocusRequestedEventHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2MoveFocusRequestedEventHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2MoveFocusRequestedEventHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2MoveFocusRequestedEventHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2MoveFocusRequestedEventHandler * This, + /* [in] */ ICoreWebView2Controller *sender, + /* [in] */ ICoreWebView2MoveFocusRequestedEventArgs *args); + + END_INTERFACE + } ICoreWebView2MoveFocusRequestedEventHandlerVtbl; + + interface ICoreWebView2MoveFocusRequestedEventHandler + { + CONST_VTBL struct ICoreWebView2MoveFocusRequestedEventHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2MoveFocusRequestedEventHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2MoveFocusRequestedEventHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2MoveFocusRequestedEventHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2MoveFocusRequestedEventHandler_Invoke(This,sender,args) \ + ( (This)->lpVtbl -> Invoke(This,sender,args) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2MoveFocusRequestedEventHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2NavigationCompletedEventArgs_INTERFACE_DEFINED__ +#define __ICoreWebView2NavigationCompletedEventArgs_INTERFACE_DEFINED__ + +/* interface ICoreWebView2NavigationCompletedEventArgs */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2NavigationCompletedEventArgs = {0x30d68b7d,0x20d9,0x4752,{0xa9,0xca,0xec,0x84,0x48,0xfb,0xb5,0xc1}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("30d68b7d-20d9-4752-a9ca-ec8448fbb5c1") + ICoreWebView2NavigationCompletedEventArgs : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_IsSuccess( + /* [retval][out] */ BOOL *isSuccess) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_WebErrorStatus( + /* [retval][out] */ COREWEBVIEW2_WEB_ERROR_STATUS *webErrorStatus) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_NavigationId( + /* [retval][out] */ UINT64 *navigationId) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2NavigationCompletedEventArgsVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2NavigationCompletedEventArgs * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2NavigationCompletedEventArgs * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2NavigationCompletedEventArgs * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_IsSuccess )( + ICoreWebView2NavigationCompletedEventArgs * This, + /* [retval][out] */ BOOL *isSuccess); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_WebErrorStatus )( + ICoreWebView2NavigationCompletedEventArgs * This, + /* [retval][out] */ COREWEBVIEW2_WEB_ERROR_STATUS *webErrorStatus); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_NavigationId )( + ICoreWebView2NavigationCompletedEventArgs * This, + /* [retval][out] */ UINT64 *navigationId); + + END_INTERFACE + } ICoreWebView2NavigationCompletedEventArgsVtbl; + + interface ICoreWebView2NavigationCompletedEventArgs + { + CONST_VTBL struct ICoreWebView2NavigationCompletedEventArgsVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2NavigationCompletedEventArgs_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2NavigationCompletedEventArgs_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2NavigationCompletedEventArgs_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2NavigationCompletedEventArgs_get_IsSuccess(This,isSuccess) \ + ( (This)->lpVtbl -> get_IsSuccess(This,isSuccess) ) + +#define ICoreWebView2NavigationCompletedEventArgs_get_WebErrorStatus(This,webErrorStatus) \ + ( (This)->lpVtbl -> get_WebErrorStatus(This,webErrorStatus) ) + +#define ICoreWebView2NavigationCompletedEventArgs_get_NavigationId(This,navigationId) \ + ( (This)->lpVtbl -> get_NavigationId(This,navigationId) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2NavigationCompletedEventArgs_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2NavigationCompletedEventHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2NavigationCompletedEventHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2NavigationCompletedEventHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2NavigationCompletedEventHandler = {0xd33a35bf,0x1c49,0x4f98,{0x93,0xab,0x00,0x6e,0x05,0x33,0xfe,0x1c}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("d33a35bf-1c49-4f98-93ab-006e0533fe1c") + ICoreWebView2NavigationCompletedEventHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + /* [in] */ ICoreWebView2 *sender, + /* [in] */ ICoreWebView2NavigationCompletedEventArgs *args) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2NavigationCompletedEventHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2NavigationCompletedEventHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2NavigationCompletedEventHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2NavigationCompletedEventHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2NavigationCompletedEventHandler * This, + /* [in] */ ICoreWebView2 *sender, + /* [in] */ ICoreWebView2NavigationCompletedEventArgs *args); + + END_INTERFACE + } ICoreWebView2NavigationCompletedEventHandlerVtbl; + + interface ICoreWebView2NavigationCompletedEventHandler + { + CONST_VTBL struct ICoreWebView2NavigationCompletedEventHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2NavigationCompletedEventHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2NavigationCompletedEventHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2NavigationCompletedEventHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2NavigationCompletedEventHandler_Invoke(This,sender,args) \ + ( (This)->lpVtbl -> Invoke(This,sender,args) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2NavigationCompletedEventHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2NavigationStartingEventArgs_INTERFACE_DEFINED__ +#define __ICoreWebView2NavigationStartingEventArgs_INTERFACE_DEFINED__ + +/* interface ICoreWebView2NavigationStartingEventArgs */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2NavigationStartingEventArgs = {0x5b495469,0xe119,0x438a,{0x9b,0x18,0x76,0x04,0xf2,0x5f,0x2e,0x49}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("5b495469-e119-438a-9b18-7604f25f2e49") + ICoreWebView2NavigationStartingEventArgs : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Uri( + /* [retval][out] */ LPWSTR *uri) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_IsUserInitiated( + /* [retval][out] */ BOOL *isUserInitiated) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_IsRedirected( + /* [retval][out] */ BOOL *isRedirected) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_RequestHeaders( + /* [retval][out] */ ICoreWebView2HttpRequestHeaders **requestHeaders) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Cancel( + /* [retval][out] */ BOOL *cancel) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_Cancel( + /* [in] */ BOOL cancel) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_NavigationId( + /* [retval][out] */ UINT64 *navigationId) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2NavigationStartingEventArgsVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2NavigationStartingEventArgs * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2NavigationStartingEventArgs * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2NavigationStartingEventArgs * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Uri )( + ICoreWebView2NavigationStartingEventArgs * This, + /* [retval][out] */ LPWSTR *uri); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_IsUserInitiated )( + ICoreWebView2NavigationStartingEventArgs * This, + /* [retval][out] */ BOOL *isUserInitiated); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_IsRedirected )( + ICoreWebView2NavigationStartingEventArgs * This, + /* [retval][out] */ BOOL *isRedirected); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_RequestHeaders )( + ICoreWebView2NavigationStartingEventArgs * This, + /* [retval][out] */ ICoreWebView2HttpRequestHeaders **requestHeaders); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Cancel )( + ICoreWebView2NavigationStartingEventArgs * This, + /* [retval][out] */ BOOL *cancel); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_Cancel )( + ICoreWebView2NavigationStartingEventArgs * This, + /* [in] */ BOOL cancel); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_NavigationId )( + ICoreWebView2NavigationStartingEventArgs * This, + /* [retval][out] */ UINT64 *navigationId); + + END_INTERFACE + } ICoreWebView2NavigationStartingEventArgsVtbl; + + interface ICoreWebView2NavigationStartingEventArgs + { + CONST_VTBL struct ICoreWebView2NavigationStartingEventArgsVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2NavigationStartingEventArgs_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2NavigationStartingEventArgs_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2NavigationStartingEventArgs_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2NavigationStartingEventArgs_get_Uri(This,uri) \ + ( (This)->lpVtbl -> get_Uri(This,uri) ) + +#define ICoreWebView2NavigationStartingEventArgs_get_IsUserInitiated(This,isUserInitiated) \ + ( (This)->lpVtbl -> get_IsUserInitiated(This,isUserInitiated) ) + +#define ICoreWebView2NavigationStartingEventArgs_get_IsRedirected(This,isRedirected) \ + ( (This)->lpVtbl -> get_IsRedirected(This,isRedirected) ) + +#define ICoreWebView2NavigationStartingEventArgs_get_RequestHeaders(This,requestHeaders) \ + ( (This)->lpVtbl -> get_RequestHeaders(This,requestHeaders) ) + +#define ICoreWebView2NavigationStartingEventArgs_get_Cancel(This,cancel) \ + ( (This)->lpVtbl -> get_Cancel(This,cancel) ) + +#define ICoreWebView2NavigationStartingEventArgs_put_Cancel(This,cancel) \ + ( (This)->lpVtbl -> put_Cancel(This,cancel) ) + +#define ICoreWebView2NavigationStartingEventArgs_get_NavigationId(This,navigationId) \ + ( (This)->lpVtbl -> get_NavigationId(This,navigationId) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2NavigationStartingEventArgs_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2NavigationStartingEventHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2NavigationStartingEventHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2NavigationStartingEventHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2NavigationStartingEventHandler = {0x9adbe429,0xf36d,0x432b,{0x9d,0xdc,0xf8,0x88,0x1f,0xbd,0x76,0xe3}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("9adbe429-f36d-432b-9ddc-f8881fbd76e3") + ICoreWebView2NavigationStartingEventHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + /* [in] */ ICoreWebView2 *sender, + /* [in] */ ICoreWebView2NavigationStartingEventArgs *args) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2NavigationStartingEventHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2NavigationStartingEventHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2NavigationStartingEventHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2NavigationStartingEventHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2NavigationStartingEventHandler * This, + /* [in] */ ICoreWebView2 *sender, + /* [in] */ ICoreWebView2NavigationStartingEventArgs *args); + + END_INTERFACE + } ICoreWebView2NavigationStartingEventHandlerVtbl; + + interface ICoreWebView2NavigationStartingEventHandler + { + CONST_VTBL struct ICoreWebView2NavigationStartingEventHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2NavigationStartingEventHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2NavigationStartingEventHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2NavigationStartingEventHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2NavigationStartingEventHandler_Invoke(This,sender,args) \ + ( (This)->lpVtbl -> Invoke(This,sender,args) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2NavigationStartingEventHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2NewBrowserVersionAvailableEventHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2NewBrowserVersionAvailableEventHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2NewBrowserVersionAvailableEventHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2NewBrowserVersionAvailableEventHandler = {0xf9a2976e,0xd34e,0x44fc,{0xad,0xee,0x81,0xb6,0xb5,0x7c,0xa9,0x14}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("f9a2976e-d34e-44fc-adee-81b6b57ca914") + ICoreWebView2NewBrowserVersionAvailableEventHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + /* [in] */ ICoreWebView2Environment *sender, + /* [in] */ IUnknown *args) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2NewBrowserVersionAvailableEventHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2NewBrowserVersionAvailableEventHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2NewBrowserVersionAvailableEventHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2NewBrowserVersionAvailableEventHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2NewBrowserVersionAvailableEventHandler * This, + /* [in] */ ICoreWebView2Environment *sender, + /* [in] */ IUnknown *args); + + END_INTERFACE + } ICoreWebView2NewBrowserVersionAvailableEventHandlerVtbl; + + interface ICoreWebView2NewBrowserVersionAvailableEventHandler + { + CONST_VTBL struct ICoreWebView2NewBrowserVersionAvailableEventHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2NewBrowserVersionAvailableEventHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2NewBrowserVersionAvailableEventHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2NewBrowserVersionAvailableEventHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2NewBrowserVersionAvailableEventHandler_Invoke(This,sender,args) \ + ( (This)->lpVtbl -> Invoke(This,sender,args) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2NewBrowserVersionAvailableEventHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2NewWindowRequestedEventArgs_INTERFACE_DEFINED__ +#define __ICoreWebView2NewWindowRequestedEventArgs_INTERFACE_DEFINED__ + +/* interface ICoreWebView2NewWindowRequestedEventArgs */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2NewWindowRequestedEventArgs = {0x34acb11c,0xfc37,0x4418,{0x91,0x32,0xf9,0xc2,0x1d,0x1e,0xaf,0xb9}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("34acb11c-fc37-4418-9132-f9c21d1eafb9") + ICoreWebView2NewWindowRequestedEventArgs : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Uri( + /* [retval][out] */ LPWSTR *uri) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_NewWindow( + /* [in] */ ICoreWebView2 *newWindow) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_NewWindow( + /* [retval][out] */ ICoreWebView2 **newWindow) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_Handled( + /* [in] */ BOOL handled) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Handled( + /* [retval][out] */ BOOL *handled) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_IsUserInitiated( + /* [retval][out] */ BOOL *isUserInitiated) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDeferral( + /* [retval][out] */ ICoreWebView2Deferral **deferral) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_WindowFeatures( + /* [retval][out] */ ICoreWebView2WindowFeatures **value) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2NewWindowRequestedEventArgsVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2NewWindowRequestedEventArgs * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2NewWindowRequestedEventArgs * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2NewWindowRequestedEventArgs * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Uri )( + ICoreWebView2NewWindowRequestedEventArgs * This, + /* [retval][out] */ LPWSTR *uri); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_NewWindow )( + ICoreWebView2NewWindowRequestedEventArgs * This, + /* [in] */ ICoreWebView2 *newWindow); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_NewWindow )( + ICoreWebView2NewWindowRequestedEventArgs * This, + /* [retval][out] */ ICoreWebView2 **newWindow); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_Handled )( + ICoreWebView2NewWindowRequestedEventArgs * This, + /* [in] */ BOOL handled); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Handled )( + ICoreWebView2NewWindowRequestedEventArgs * This, + /* [retval][out] */ BOOL *handled); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_IsUserInitiated )( + ICoreWebView2NewWindowRequestedEventArgs * This, + /* [retval][out] */ BOOL *isUserInitiated); + + HRESULT ( STDMETHODCALLTYPE *GetDeferral )( + ICoreWebView2NewWindowRequestedEventArgs * This, + /* [retval][out] */ ICoreWebView2Deferral **deferral); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_WindowFeatures )( + ICoreWebView2NewWindowRequestedEventArgs * This, + /* [retval][out] */ ICoreWebView2WindowFeatures **value); + + END_INTERFACE + } ICoreWebView2NewWindowRequestedEventArgsVtbl; + + interface ICoreWebView2NewWindowRequestedEventArgs + { + CONST_VTBL struct ICoreWebView2NewWindowRequestedEventArgsVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2NewWindowRequestedEventArgs_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2NewWindowRequestedEventArgs_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2NewWindowRequestedEventArgs_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2NewWindowRequestedEventArgs_get_Uri(This,uri) \ + ( (This)->lpVtbl -> get_Uri(This,uri) ) + +#define ICoreWebView2NewWindowRequestedEventArgs_put_NewWindow(This,newWindow) \ + ( (This)->lpVtbl -> put_NewWindow(This,newWindow) ) + +#define ICoreWebView2NewWindowRequestedEventArgs_get_NewWindow(This,newWindow) \ + ( (This)->lpVtbl -> get_NewWindow(This,newWindow) ) + +#define ICoreWebView2NewWindowRequestedEventArgs_put_Handled(This,handled) \ + ( (This)->lpVtbl -> put_Handled(This,handled) ) + +#define ICoreWebView2NewWindowRequestedEventArgs_get_Handled(This,handled) \ + ( (This)->lpVtbl -> get_Handled(This,handled) ) + +#define ICoreWebView2NewWindowRequestedEventArgs_get_IsUserInitiated(This,isUserInitiated) \ + ( (This)->lpVtbl -> get_IsUserInitiated(This,isUserInitiated) ) + +#define ICoreWebView2NewWindowRequestedEventArgs_GetDeferral(This,deferral) \ + ( (This)->lpVtbl -> GetDeferral(This,deferral) ) + +#define ICoreWebView2NewWindowRequestedEventArgs_get_WindowFeatures(This,value) \ + ( (This)->lpVtbl -> get_WindowFeatures(This,value) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2NewWindowRequestedEventArgs_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2NewWindowRequestedEventHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2NewWindowRequestedEventHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2NewWindowRequestedEventHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2NewWindowRequestedEventHandler = {0xd4c185fe,0xc81c,0x4989,{0x97,0xaf,0x2d,0x3f,0xa7,0xab,0x56,0x51}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("d4c185fe-c81c-4989-97af-2d3fa7ab5651") + ICoreWebView2NewWindowRequestedEventHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + /* [in] */ ICoreWebView2 *sender, + /* [in] */ ICoreWebView2NewWindowRequestedEventArgs *args) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2NewWindowRequestedEventHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2NewWindowRequestedEventHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2NewWindowRequestedEventHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2NewWindowRequestedEventHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2NewWindowRequestedEventHandler * This, + /* [in] */ ICoreWebView2 *sender, + /* [in] */ ICoreWebView2NewWindowRequestedEventArgs *args); + + END_INTERFACE + } ICoreWebView2NewWindowRequestedEventHandlerVtbl; + + interface ICoreWebView2NewWindowRequestedEventHandler + { + CONST_VTBL struct ICoreWebView2NewWindowRequestedEventHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2NewWindowRequestedEventHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2NewWindowRequestedEventHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2NewWindowRequestedEventHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2NewWindowRequestedEventHandler_Invoke(This,sender,args) \ + ( (This)->lpVtbl -> Invoke(This,sender,args) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2NewWindowRequestedEventHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2PermissionRequestedEventArgs_INTERFACE_DEFINED__ +#define __ICoreWebView2PermissionRequestedEventArgs_INTERFACE_DEFINED__ + +/* interface ICoreWebView2PermissionRequestedEventArgs */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2PermissionRequestedEventArgs = {0x973ae2ef,0xff18,0x4894,{0x8f,0xb2,0x3c,0x75,0x8f,0x04,0x68,0x10}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("973ae2ef-ff18-4894-8fb2-3c758f046810") + ICoreWebView2PermissionRequestedEventArgs : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Uri( + /* [retval][out] */ LPWSTR *uri) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_PermissionKind( + /* [retval][out] */ COREWEBVIEW2_PERMISSION_KIND *permissionKind) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_IsUserInitiated( + /* [retval][out] */ BOOL *isUserInitiated) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_State( + /* [retval][out] */ COREWEBVIEW2_PERMISSION_STATE *state) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_State( + /* [in] */ COREWEBVIEW2_PERMISSION_STATE state) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDeferral( + /* [retval][out] */ ICoreWebView2Deferral **deferral) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2PermissionRequestedEventArgsVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2PermissionRequestedEventArgs * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2PermissionRequestedEventArgs * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2PermissionRequestedEventArgs * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Uri )( + ICoreWebView2PermissionRequestedEventArgs * This, + /* [retval][out] */ LPWSTR *uri); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_PermissionKind )( + ICoreWebView2PermissionRequestedEventArgs * This, + /* [retval][out] */ COREWEBVIEW2_PERMISSION_KIND *permissionKind); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_IsUserInitiated )( + ICoreWebView2PermissionRequestedEventArgs * This, + /* [retval][out] */ BOOL *isUserInitiated); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_State )( + ICoreWebView2PermissionRequestedEventArgs * This, + /* [retval][out] */ COREWEBVIEW2_PERMISSION_STATE *state); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_State )( + ICoreWebView2PermissionRequestedEventArgs * This, + /* [in] */ COREWEBVIEW2_PERMISSION_STATE state); + + HRESULT ( STDMETHODCALLTYPE *GetDeferral )( + ICoreWebView2PermissionRequestedEventArgs * This, + /* [retval][out] */ ICoreWebView2Deferral **deferral); + + END_INTERFACE + } ICoreWebView2PermissionRequestedEventArgsVtbl; + + interface ICoreWebView2PermissionRequestedEventArgs + { + CONST_VTBL struct ICoreWebView2PermissionRequestedEventArgsVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2PermissionRequestedEventArgs_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2PermissionRequestedEventArgs_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2PermissionRequestedEventArgs_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2PermissionRequestedEventArgs_get_Uri(This,uri) \ + ( (This)->lpVtbl -> get_Uri(This,uri) ) + +#define ICoreWebView2PermissionRequestedEventArgs_get_PermissionKind(This,permissionKind) \ + ( (This)->lpVtbl -> get_PermissionKind(This,permissionKind) ) + +#define ICoreWebView2PermissionRequestedEventArgs_get_IsUserInitiated(This,isUserInitiated) \ + ( (This)->lpVtbl -> get_IsUserInitiated(This,isUserInitiated) ) + +#define ICoreWebView2PermissionRequestedEventArgs_get_State(This,state) \ + ( (This)->lpVtbl -> get_State(This,state) ) + +#define ICoreWebView2PermissionRequestedEventArgs_put_State(This,state) \ + ( (This)->lpVtbl -> put_State(This,state) ) + +#define ICoreWebView2PermissionRequestedEventArgs_GetDeferral(This,deferral) \ + ( (This)->lpVtbl -> GetDeferral(This,deferral) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2PermissionRequestedEventArgs_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2PermissionRequestedEventHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2PermissionRequestedEventHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2PermissionRequestedEventHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2PermissionRequestedEventHandler = {0x15e1c6a3,0xc72a,0x4df3,{0x91,0xd7,0xd0,0x97,0xfb,0xec,0x6b,0xfd}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("15e1c6a3-c72a-4df3-91d7-d097fbec6bfd") + ICoreWebView2PermissionRequestedEventHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + /* [in] */ ICoreWebView2 *sender, + /* [in] */ ICoreWebView2PermissionRequestedEventArgs *args) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2PermissionRequestedEventHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2PermissionRequestedEventHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2PermissionRequestedEventHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2PermissionRequestedEventHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2PermissionRequestedEventHandler * This, + /* [in] */ ICoreWebView2 *sender, + /* [in] */ ICoreWebView2PermissionRequestedEventArgs *args); + + END_INTERFACE + } ICoreWebView2PermissionRequestedEventHandlerVtbl; + + interface ICoreWebView2PermissionRequestedEventHandler + { + CONST_VTBL struct ICoreWebView2PermissionRequestedEventHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2PermissionRequestedEventHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2PermissionRequestedEventHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2PermissionRequestedEventHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2PermissionRequestedEventHandler_Invoke(This,sender,args) \ + ( (This)->lpVtbl -> Invoke(This,sender,args) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2PermissionRequestedEventHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2PointerInfo_INTERFACE_DEFINED__ +#define __ICoreWebView2PointerInfo_INTERFACE_DEFINED__ + +/* interface ICoreWebView2PointerInfo */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2PointerInfo = {0xe6995887,0xd10d,0x4f5d,{0x93,0x59,0x4c,0xe4,0x6e,0x4f,0x96,0xb9}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("e6995887-d10d-4f5d-9359-4ce46e4f96b9") + ICoreWebView2PointerInfo : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_PointerKind( + /* [retval][out] */ DWORD *pointerKind) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_PointerKind( + /* [in] */ DWORD pointerKind) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_PointerId( + /* [retval][out] */ UINT32 *pointerId) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_PointerId( + /* [in] */ UINT32 pointerId) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_FrameId( + /* [retval][out] */ UINT32 *frameId) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_FrameId( + /* [in] */ UINT32 frameId) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_PointerFlags( + /* [retval][out] */ UINT32 *pointerFlags) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_PointerFlags( + /* [in] */ UINT32 pointerFlags) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_PointerDeviceRect( + /* [retval][out] */ RECT *pointerDeviceRect) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_PointerDeviceRect( + /* [in] */ RECT pointerDeviceRect) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_DisplayRect( + /* [retval][out] */ RECT *displayRect) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_DisplayRect( + /* [in] */ RECT displayRect) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_PixelLocation( + /* [retval][out] */ POINT *pixelLocation) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_PixelLocation( + /* [in] */ POINT pixelLocation) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_HimetricLocation( + /* [retval][out] */ POINT *himetricLocation) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_HimetricLocation( + /* [in] */ POINT himetricLocation) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_PixelLocationRaw( + /* [retval][out] */ POINT *pixelLocationRaw) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_PixelLocationRaw( + /* [in] */ POINT pixelLocationRaw) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_HimetricLocationRaw( + /* [retval][out] */ POINT *himetricLocationRaw) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_HimetricLocationRaw( + /* [in] */ POINT himetricLocationRaw) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Time( + /* [retval][out] */ DWORD *time) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_Time( + /* [in] */ DWORD time) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_HistoryCount( + /* [retval][out] */ UINT32 *historyCount) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_HistoryCount( + /* [in] */ UINT32 historyCount) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_InputData( + /* [retval][out] */ INT32 *inputData) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_InputData( + /* [in] */ INT32 inputData) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_KeyStates( + /* [retval][out] */ DWORD *keyStates) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_KeyStates( + /* [in] */ DWORD keyStates) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_PerformanceCount( + /* [retval][out] */ UINT64 *performanceCount) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_PerformanceCount( + /* [in] */ UINT64 performanceCount) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_ButtonChangeKind( + /* [retval][out] */ INT32 *buttonChangeKind) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_ButtonChangeKind( + /* [in] */ INT32 buttonChangeKind) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_PenFlags( + /* [retval][out] */ UINT32 *penFLags) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_PenFlags( + /* [in] */ UINT32 penFLags) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_PenMask( + /* [retval][out] */ UINT32 *penMask) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_PenMask( + /* [in] */ UINT32 penMask) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_PenPressure( + /* [retval][out] */ UINT32 *penPressure) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_PenPressure( + /* [in] */ UINT32 penPressure) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_PenRotation( + /* [retval][out] */ UINT32 *penRotation) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_PenRotation( + /* [in] */ UINT32 penRotation) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_PenTiltX( + /* [retval][out] */ INT32 *penTiltX) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_PenTiltX( + /* [in] */ INT32 penTiltX) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_PenTiltY( + /* [retval][out] */ INT32 *penTiltY) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_PenTiltY( + /* [in] */ INT32 penTiltY) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_TouchFlags( + /* [retval][out] */ UINT32 *touchFlags) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_TouchFlags( + /* [in] */ UINT32 touchFlags) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_TouchMask( + /* [retval][out] */ UINT32 *touchMask) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_TouchMask( + /* [in] */ UINT32 touchMask) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_TouchContact( + /* [retval][out] */ RECT *touchContact) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_TouchContact( + /* [in] */ RECT touchContact) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_TouchContactRaw( + /* [retval][out] */ RECT *touchContactRaw) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_TouchContactRaw( + /* [in] */ RECT touchContactRaw) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_TouchOrientation( + /* [retval][out] */ UINT32 *touchOrientation) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_TouchOrientation( + /* [in] */ UINT32 touchOrientation) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_TouchPressure( + /* [retval][out] */ UINT32 *touchPressure) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_TouchPressure( + /* [in] */ UINT32 touchPressure) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2PointerInfoVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2PointerInfo * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2PointerInfo * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2PointerInfo * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_PointerKind )( + ICoreWebView2PointerInfo * This, + /* [retval][out] */ DWORD *pointerKind); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_PointerKind )( + ICoreWebView2PointerInfo * This, + /* [in] */ DWORD pointerKind); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_PointerId )( + ICoreWebView2PointerInfo * This, + /* [retval][out] */ UINT32 *pointerId); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_PointerId )( + ICoreWebView2PointerInfo * This, + /* [in] */ UINT32 pointerId); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_FrameId )( + ICoreWebView2PointerInfo * This, + /* [retval][out] */ UINT32 *frameId); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_FrameId )( + ICoreWebView2PointerInfo * This, + /* [in] */ UINT32 frameId); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_PointerFlags )( + ICoreWebView2PointerInfo * This, + /* [retval][out] */ UINT32 *pointerFlags); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_PointerFlags )( + ICoreWebView2PointerInfo * This, + /* [in] */ UINT32 pointerFlags); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_PointerDeviceRect )( + ICoreWebView2PointerInfo * This, + /* [retval][out] */ RECT *pointerDeviceRect); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_PointerDeviceRect )( + ICoreWebView2PointerInfo * This, + /* [in] */ RECT pointerDeviceRect); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_DisplayRect )( + ICoreWebView2PointerInfo * This, + /* [retval][out] */ RECT *displayRect); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_DisplayRect )( + ICoreWebView2PointerInfo * This, + /* [in] */ RECT displayRect); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_PixelLocation )( + ICoreWebView2PointerInfo * This, + /* [retval][out] */ POINT *pixelLocation); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_PixelLocation )( + ICoreWebView2PointerInfo * This, + /* [in] */ POINT pixelLocation); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_HimetricLocation )( + ICoreWebView2PointerInfo * This, + /* [retval][out] */ POINT *himetricLocation); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_HimetricLocation )( + ICoreWebView2PointerInfo * This, + /* [in] */ POINT himetricLocation); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_PixelLocationRaw )( + ICoreWebView2PointerInfo * This, + /* [retval][out] */ POINT *pixelLocationRaw); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_PixelLocationRaw )( + ICoreWebView2PointerInfo * This, + /* [in] */ POINT pixelLocationRaw); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_HimetricLocationRaw )( + ICoreWebView2PointerInfo * This, + /* [retval][out] */ POINT *himetricLocationRaw); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_HimetricLocationRaw )( + ICoreWebView2PointerInfo * This, + /* [in] */ POINT himetricLocationRaw); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Time )( + ICoreWebView2PointerInfo * This, + /* [retval][out] */ DWORD *time); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_Time )( + ICoreWebView2PointerInfo * This, + /* [in] */ DWORD time); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_HistoryCount )( + ICoreWebView2PointerInfo * This, + /* [retval][out] */ UINT32 *historyCount); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_HistoryCount )( + ICoreWebView2PointerInfo * This, + /* [in] */ UINT32 historyCount); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_InputData )( + ICoreWebView2PointerInfo * This, + /* [retval][out] */ INT32 *inputData); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_InputData )( + ICoreWebView2PointerInfo * This, + /* [in] */ INT32 inputData); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_KeyStates )( + ICoreWebView2PointerInfo * This, + /* [retval][out] */ DWORD *keyStates); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_KeyStates )( + ICoreWebView2PointerInfo * This, + /* [in] */ DWORD keyStates); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_PerformanceCount )( + ICoreWebView2PointerInfo * This, + /* [retval][out] */ UINT64 *performanceCount); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_PerformanceCount )( + ICoreWebView2PointerInfo * This, + /* [in] */ UINT64 performanceCount); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_ButtonChangeKind )( + ICoreWebView2PointerInfo * This, + /* [retval][out] */ INT32 *buttonChangeKind); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_ButtonChangeKind )( + ICoreWebView2PointerInfo * This, + /* [in] */ INT32 buttonChangeKind); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_PenFlags )( + ICoreWebView2PointerInfo * This, + /* [retval][out] */ UINT32 *penFLags); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_PenFlags )( + ICoreWebView2PointerInfo * This, + /* [in] */ UINT32 penFLags); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_PenMask )( + ICoreWebView2PointerInfo * This, + /* [retval][out] */ UINT32 *penMask); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_PenMask )( + ICoreWebView2PointerInfo * This, + /* [in] */ UINT32 penMask); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_PenPressure )( + ICoreWebView2PointerInfo * This, + /* [retval][out] */ UINT32 *penPressure); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_PenPressure )( + ICoreWebView2PointerInfo * This, + /* [in] */ UINT32 penPressure); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_PenRotation )( + ICoreWebView2PointerInfo * This, + /* [retval][out] */ UINT32 *penRotation); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_PenRotation )( + ICoreWebView2PointerInfo * This, + /* [in] */ UINT32 penRotation); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_PenTiltX )( + ICoreWebView2PointerInfo * This, + /* [retval][out] */ INT32 *penTiltX); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_PenTiltX )( + ICoreWebView2PointerInfo * This, + /* [in] */ INT32 penTiltX); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_PenTiltY )( + ICoreWebView2PointerInfo * This, + /* [retval][out] */ INT32 *penTiltY); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_PenTiltY )( + ICoreWebView2PointerInfo * This, + /* [in] */ INT32 penTiltY); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_TouchFlags )( + ICoreWebView2PointerInfo * This, + /* [retval][out] */ UINT32 *touchFlags); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_TouchFlags )( + ICoreWebView2PointerInfo * This, + /* [in] */ UINT32 touchFlags); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_TouchMask )( + ICoreWebView2PointerInfo * This, + /* [retval][out] */ UINT32 *touchMask); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_TouchMask )( + ICoreWebView2PointerInfo * This, + /* [in] */ UINT32 touchMask); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_TouchContact )( + ICoreWebView2PointerInfo * This, + /* [retval][out] */ RECT *touchContact); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_TouchContact )( + ICoreWebView2PointerInfo * This, + /* [in] */ RECT touchContact); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_TouchContactRaw )( + ICoreWebView2PointerInfo * This, + /* [retval][out] */ RECT *touchContactRaw); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_TouchContactRaw )( + ICoreWebView2PointerInfo * This, + /* [in] */ RECT touchContactRaw); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_TouchOrientation )( + ICoreWebView2PointerInfo * This, + /* [retval][out] */ UINT32 *touchOrientation); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_TouchOrientation )( + ICoreWebView2PointerInfo * This, + /* [in] */ UINT32 touchOrientation); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_TouchPressure )( + ICoreWebView2PointerInfo * This, + /* [retval][out] */ UINT32 *touchPressure); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_TouchPressure )( + ICoreWebView2PointerInfo * This, + /* [in] */ UINT32 touchPressure); + + END_INTERFACE + } ICoreWebView2PointerInfoVtbl; + + interface ICoreWebView2PointerInfo + { + CONST_VTBL struct ICoreWebView2PointerInfoVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2PointerInfo_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2PointerInfo_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2PointerInfo_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2PointerInfo_get_PointerKind(This,pointerKind) \ + ( (This)->lpVtbl -> get_PointerKind(This,pointerKind) ) + +#define ICoreWebView2PointerInfo_put_PointerKind(This,pointerKind) \ + ( (This)->lpVtbl -> put_PointerKind(This,pointerKind) ) + +#define ICoreWebView2PointerInfo_get_PointerId(This,pointerId) \ + ( (This)->lpVtbl -> get_PointerId(This,pointerId) ) + +#define ICoreWebView2PointerInfo_put_PointerId(This,pointerId) \ + ( (This)->lpVtbl -> put_PointerId(This,pointerId) ) + +#define ICoreWebView2PointerInfo_get_FrameId(This,frameId) \ + ( (This)->lpVtbl -> get_FrameId(This,frameId) ) + +#define ICoreWebView2PointerInfo_put_FrameId(This,frameId) \ + ( (This)->lpVtbl -> put_FrameId(This,frameId) ) + +#define ICoreWebView2PointerInfo_get_PointerFlags(This,pointerFlags) \ + ( (This)->lpVtbl -> get_PointerFlags(This,pointerFlags) ) + +#define ICoreWebView2PointerInfo_put_PointerFlags(This,pointerFlags) \ + ( (This)->lpVtbl -> put_PointerFlags(This,pointerFlags) ) + +#define ICoreWebView2PointerInfo_get_PointerDeviceRect(This,pointerDeviceRect) \ + ( (This)->lpVtbl -> get_PointerDeviceRect(This,pointerDeviceRect) ) + +#define ICoreWebView2PointerInfo_put_PointerDeviceRect(This,pointerDeviceRect) \ + ( (This)->lpVtbl -> put_PointerDeviceRect(This,pointerDeviceRect) ) + +#define ICoreWebView2PointerInfo_get_DisplayRect(This,displayRect) \ + ( (This)->lpVtbl -> get_DisplayRect(This,displayRect) ) + +#define ICoreWebView2PointerInfo_put_DisplayRect(This,displayRect) \ + ( (This)->lpVtbl -> put_DisplayRect(This,displayRect) ) + +#define ICoreWebView2PointerInfo_get_PixelLocation(This,pixelLocation) \ + ( (This)->lpVtbl -> get_PixelLocation(This,pixelLocation) ) + +#define ICoreWebView2PointerInfo_put_PixelLocation(This,pixelLocation) \ + ( (This)->lpVtbl -> put_PixelLocation(This,pixelLocation) ) + +#define ICoreWebView2PointerInfo_get_HimetricLocation(This,himetricLocation) \ + ( (This)->lpVtbl -> get_HimetricLocation(This,himetricLocation) ) + +#define ICoreWebView2PointerInfo_put_HimetricLocation(This,himetricLocation) \ + ( (This)->lpVtbl -> put_HimetricLocation(This,himetricLocation) ) + +#define ICoreWebView2PointerInfo_get_PixelLocationRaw(This,pixelLocationRaw) \ + ( (This)->lpVtbl -> get_PixelLocationRaw(This,pixelLocationRaw) ) + +#define ICoreWebView2PointerInfo_put_PixelLocationRaw(This,pixelLocationRaw) \ + ( (This)->lpVtbl -> put_PixelLocationRaw(This,pixelLocationRaw) ) + +#define ICoreWebView2PointerInfo_get_HimetricLocationRaw(This,himetricLocationRaw) \ + ( (This)->lpVtbl -> get_HimetricLocationRaw(This,himetricLocationRaw) ) + +#define ICoreWebView2PointerInfo_put_HimetricLocationRaw(This,himetricLocationRaw) \ + ( (This)->lpVtbl -> put_HimetricLocationRaw(This,himetricLocationRaw) ) + +#define ICoreWebView2PointerInfo_get_Time(This,time) \ + ( (This)->lpVtbl -> get_Time(This,time) ) + +#define ICoreWebView2PointerInfo_put_Time(This,time) \ + ( (This)->lpVtbl -> put_Time(This,time) ) + +#define ICoreWebView2PointerInfo_get_HistoryCount(This,historyCount) \ + ( (This)->lpVtbl -> get_HistoryCount(This,historyCount) ) + +#define ICoreWebView2PointerInfo_put_HistoryCount(This,historyCount) \ + ( (This)->lpVtbl -> put_HistoryCount(This,historyCount) ) + +#define ICoreWebView2PointerInfo_get_InputData(This,inputData) \ + ( (This)->lpVtbl -> get_InputData(This,inputData) ) + +#define ICoreWebView2PointerInfo_put_InputData(This,inputData) \ + ( (This)->lpVtbl -> put_InputData(This,inputData) ) + +#define ICoreWebView2PointerInfo_get_KeyStates(This,keyStates) \ + ( (This)->lpVtbl -> get_KeyStates(This,keyStates) ) + +#define ICoreWebView2PointerInfo_put_KeyStates(This,keyStates) \ + ( (This)->lpVtbl -> put_KeyStates(This,keyStates) ) + +#define ICoreWebView2PointerInfo_get_PerformanceCount(This,performanceCount) \ + ( (This)->lpVtbl -> get_PerformanceCount(This,performanceCount) ) + +#define ICoreWebView2PointerInfo_put_PerformanceCount(This,performanceCount) \ + ( (This)->lpVtbl -> put_PerformanceCount(This,performanceCount) ) + +#define ICoreWebView2PointerInfo_get_ButtonChangeKind(This,buttonChangeKind) \ + ( (This)->lpVtbl -> get_ButtonChangeKind(This,buttonChangeKind) ) + +#define ICoreWebView2PointerInfo_put_ButtonChangeKind(This,buttonChangeKind) \ + ( (This)->lpVtbl -> put_ButtonChangeKind(This,buttonChangeKind) ) + +#define ICoreWebView2PointerInfo_get_PenFlags(This,penFLags) \ + ( (This)->lpVtbl -> get_PenFlags(This,penFLags) ) + +#define ICoreWebView2PointerInfo_put_PenFlags(This,penFLags) \ + ( (This)->lpVtbl -> put_PenFlags(This,penFLags) ) + +#define ICoreWebView2PointerInfo_get_PenMask(This,penMask) \ + ( (This)->lpVtbl -> get_PenMask(This,penMask) ) + +#define ICoreWebView2PointerInfo_put_PenMask(This,penMask) \ + ( (This)->lpVtbl -> put_PenMask(This,penMask) ) + +#define ICoreWebView2PointerInfo_get_PenPressure(This,penPressure) \ + ( (This)->lpVtbl -> get_PenPressure(This,penPressure) ) + +#define ICoreWebView2PointerInfo_put_PenPressure(This,penPressure) \ + ( (This)->lpVtbl -> put_PenPressure(This,penPressure) ) + +#define ICoreWebView2PointerInfo_get_PenRotation(This,penRotation) \ + ( (This)->lpVtbl -> get_PenRotation(This,penRotation) ) + +#define ICoreWebView2PointerInfo_put_PenRotation(This,penRotation) \ + ( (This)->lpVtbl -> put_PenRotation(This,penRotation) ) + +#define ICoreWebView2PointerInfo_get_PenTiltX(This,penTiltX) \ + ( (This)->lpVtbl -> get_PenTiltX(This,penTiltX) ) + +#define ICoreWebView2PointerInfo_put_PenTiltX(This,penTiltX) \ + ( (This)->lpVtbl -> put_PenTiltX(This,penTiltX) ) + +#define ICoreWebView2PointerInfo_get_PenTiltY(This,penTiltY) \ + ( (This)->lpVtbl -> get_PenTiltY(This,penTiltY) ) + +#define ICoreWebView2PointerInfo_put_PenTiltY(This,penTiltY) \ + ( (This)->lpVtbl -> put_PenTiltY(This,penTiltY) ) + +#define ICoreWebView2PointerInfo_get_TouchFlags(This,touchFlags) \ + ( (This)->lpVtbl -> get_TouchFlags(This,touchFlags) ) + +#define ICoreWebView2PointerInfo_put_TouchFlags(This,touchFlags) \ + ( (This)->lpVtbl -> put_TouchFlags(This,touchFlags) ) + +#define ICoreWebView2PointerInfo_get_TouchMask(This,touchMask) \ + ( (This)->lpVtbl -> get_TouchMask(This,touchMask) ) + +#define ICoreWebView2PointerInfo_put_TouchMask(This,touchMask) \ + ( (This)->lpVtbl -> put_TouchMask(This,touchMask) ) + +#define ICoreWebView2PointerInfo_get_TouchContact(This,touchContact) \ + ( (This)->lpVtbl -> get_TouchContact(This,touchContact) ) + +#define ICoreWebView2PointerInfo_put_TouchContact(This,touchContact) \ + ( (This)->lpVtbl -> put_TouchContact(This,touchContact) ) + +#define ICoreWebView2PointerInfo_get_TouchContactRaw(This,touchContactRaw) \ + ( (This)->lpVtbl -> get_TouchContactRaw(This,touchContactRaw) ) + +#define ICoreWebView2PointerInfo_put_TouchContactRaw(This,touchContactRaw) \ + ( (This)->lpVtbl -> put_TouchContactRaw(This,touchContactRaw) ) + +#define ICoreWebView2PointerInfo_get_TouchOrientation(This,touchOrientation) \ + ( (This)->lpVtbl -> get_TouchOrientation(This,touchOrientation) ) + +#define ICoreWebView2PointerInfo_put_TouchOrientation(This,touchOrientation) \ + ( (This)->lpVtbl -> put_TouchOrientation(This,touchOrientation) ) + +#define ICoreWebView2PointerInfo_get_TouchPressure(This,touchPressure) \ + ( (This)->lpVtbl -> get_TouchPressure(This,touchPressure) ) + +#define ICoreWebView2PointerInfo_put_TouchPressure(This,touchPressure) \ + ( (This)->lpVtbl -> put_TouchPressure(This,touchPressure) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2PointerInfo_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2ProcessFailedEventArgs_INTERFACE_DEFINED__ +#define __ICoreWebView2ProcessFailedEventArgs_INTERFACE_DEFINED__ + +/* interface ICoreWebView2ProcessFailedEventArgs */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2ProcessFailedEventArgs = {0x8155a9a4,0x1474,0x4a86,{0x8c,0xae,0x15,0x1b,0x0f,0xa6,0xb8,0xca}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("8155a9a4-1474-4a86-8cae-151b0fa6b8ca") + ICoreWebView2ProcessFailedEventArgs : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_ProcessFailedKind( + /* [retval][out] */ COREWEBVIEW2_PROCESS_FAILED_KIND *processFailedKind) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2ProcessFailedEventArgsVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2ProcessFailedEventArgs * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2ProcessFailedEventArgs * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2ProcessFailedEventArgs * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_ProcessFailedKind )( + ICoreWebView2ProcessFailedEventArgs * This, + /* [retval][out] */ COREWEBVIEW2_PROCESS_FAILED_KIND *processFailedKind); + + END_INTERFACE + } ICoreWebView2ProcessFailedEventArgsVtbl; + + interface ICoreWebView2ProcessFailedEventArgs + { + CONST_VTBL struct ICoreWebView2ProcessFailedEventArgsVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2ProcessFailedEventArgs_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2ProcessFailedEventArgs_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2ProcessFailedEventArgs_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2ProcessFailedEventArgs_get_ProcessFailedKind(This,processFailedKind) \ + ( (This)->lpVtbl -> get_ProcessFailedKind(This,processFailedKind) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2ProcessFailedEventArgs_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2ProcessFailedEventArgs2_INTERFACE_DEFINED__ +#define __ICoreWebView2ProcessFailedEventArgs2_INTERFACE_DEFINED__ + +/* interface ICoreWebView2ProcessFailedEventArgs2 */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2ProcessFailedEventArgs2 = {0x4dab9422,0x46fa,0x4c3e,{0xa5,0xd2,0x41,0xd2,0x07,0x1d,0x36,0x80}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("4dab9422-46fa-4c3e-a5d2-41d2071d3680") + ICoreWebView2ProcessFailedEventArgs2 : public ICoreWebView2ProcessFailedEventArgs + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Reason( + /* [retval][out] */ COREWEBVIEW2_PROCESS_FAILED_REASON *reason) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_ExitCode( + /* [retval][out] */ int *exitCode) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_ProcessDescription( + /* [retval][out] */ LPWSTR *processDescription) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_FrameInfosForFailedProcess( + /* [retval][out] */ ICoreWebView2FrameInfoCollection **frames) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2ProcessFailedEventArgs2Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2ProcessFailedEventArgs2 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2ProcessFailedEventArgs2 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2ProcessFailedEventArgs2 * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_ProcessFailedKind )( + ICoreWebView2ProcessFailedEventArgs2 * This, + /* [retval][out] */ COREWEBVIEW2_PROCESS_FAILED_KIND *processFailedKind); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Reason )( + ICoreWebView2ProcessFailedEventArgs2 * This, + /* [retval][out] */ COREWEBVIEW2_PROCESS_FAILED_REASON *reason); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_ExitCode )( + ICoreWebView2ProcessFailedEventArgs2 * This, + /* [retval][out] */ int *exitCode); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_ProcessDescription )( + ICoreWebView2ProcessFailedEventArgs2 * This, + /* [retval][out] */ LPWSTR *processDescription); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_FrameInfosForFailedProcess )( + ICoreWebView2ProcessFailedEventArgs2 * This, + /* [retval][out] */ ICoreWebView2FrameInfoCollection **frames); + + END_INTERFACE + } ICoreWebView2ProcessFailedEventArgs2Vtbl; + + interface ICoreWebView2ProcessFailedEventArgs2 + { + CONST_VTBL struct ICoreWebView2ProcessFailedEventArgs2Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2ProcessFailedEventArgs2_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2ProcessFailedEventArgs2_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2ProcessFailedEventArgs2_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2ProcessFailedEventArgs2_get_ProcessFailedKind(This,processFailedKind) \ + ( (This)->lpVtbl -> get_ProcessFailedKind(This,processFailedKind) ) + + +#define ICoreWebView2ProcessFailedEventArgs2_get_Reason(This,reason) \ + ( (This)->lpVtbl -> get_Reason(This,reason) ) + +#define ICoreWebView2ProcessFailedEventArgs2_get_ExitCode(This,exitCode) \ + ( (This)->lpVtbl -> get_ExitCode(This,exitCode) ) + +#define ICoreWebView2ProcessFailedEventArgs2_get_ProcessDescription(This,processDescription) \ + ( (This)->lpVtbl -> get_ProcessDescription(This,processDescription) ) + +#define ICoreWebView2ProcessFailedEventArgs2_get_FrameInfosForFailedProcess(This,frames) \ + ( (This)->lpVtbl -> get_FrameInfosForFailedProcess(This,frames) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2ProcessFailedEventArgs2_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2ProcessFailedEventHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2ProcessFailedEventHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2ProcessFailedEventHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2ProcessFailedEventHandler = {0x79e0aea4,0x990b,0x42d9,{0xaa,0x1d,0x0f,0xcc,0x2e,0x5b,0xc7,0xf1}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("79e0aea4-990b-42d9-aa1d-0fcc2e5bc7f1") + ICoreWebView2ProcessFailedEventHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + /* [in] */ ICoreWebView2 *sender, + /* [in] */ ICoreWebView2ProcessFailedEventArgs *args) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2ProcessFailedEventHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2ProcessFailedEventHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2ProcessFailedEventHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2ProcessFailedEventHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2ProcessFailedEventHandler * This, + /* [in] */ ICoreWebView2 *sender, + /* [in] */ ICoreWebView2ProcessFailedEventArgs *args); + + END_INTERFACE + } ICoreWebView2ProcessFailedEventHandlerVtbl; + + interface ICoreWebView2ProcessFailedEventHandler + { + CONST_VTBL struct ICoreWebView2ProcessFailedEventHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2ProcessFailedEventHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2ProcessFailedEventHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2ProcessFailedEventHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2ProcessFailedEventHandler_Invoke(This,sender,args) \ + ( (This)->lpVtbl -> Invoke(This,sender,args) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2ProcessFailedEventHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2RasterizationScaleChangedEventHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2RasterizationScaleChangedEventHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2RasterizationScaleChangedEventHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2RasterizationScaleChangedEventHandler = {0x9c98c8b1,0xac53,0x427e,{0xa3,0x45,0x30,0x49,0xb5,0x52,0x4b,0xbe}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("9c98c8b1-ac53-427e-a345-3049b5524bbe") + ICoreWebView2RasterizationScaleChangedEventHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + /* [in] */ ICoreWebView2Controller *sender, + /* [in] */ IUnknown *args) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2RasterizationScaleChangedEventHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2RasterizationScaleChangedEventHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2RasterizationScaleChangedEventHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2RasterizationScaleChangedEventHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2RasterizationScaleChangedEventHandler * This, + /* [in] */ ICoreWebView2Controller *sender, + /* [in] */ IUnknown *args); + + END_INTERFACE + } ICoreWebView2RasterizationScaleChangedEventHandlerVtbl; + + interface ICoreWebView2RasterizationScaleChangedEventHandler + { + CONST_VTBL struct ICoreWebView2RasterizationScaleChangedEventHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2RasterizationScaleChangedEventHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2RasterizationScaleChangedEventHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2RasterizationScaleChangedEventHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2RasterizationScaleChangedEventHandler_Invoke(This,sender,args) \ + ( (This)->lpVtbl -> Invoke(This,sender,args) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2RasterizationScaleChangedEventHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2ScriptDialogOpeningEventArgs_INTERFACE_DEFINED__ +#define __ICoreWebView2ScriptDialogOpeningEventArgs_INTERFACE_DEFINED__ + +/* interface ICoreWebView2ScriptDialogOpeningEventArgs */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2ScriptDialogOpeningEventArgs = {0x7390bb70,0xabe0,0x4843,{0x95,0x29,0xf1,0x43,0xb3,0x1b,0x03,0xd6}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("7390bb70-abe0-4843-9529-f143b31b03d6") + ICoreWebView2ScriptDialogOpeningEventArgs : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Uri( + /* [retval][out] */ LPWSTR *uri) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Kind( + /* [retval][out] */ COREWEBVIEW2_SCRIPT_DIALOG_KIND *kind) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Message( + /* [retval][out] */ LPWSTR *message) = 0; + + virtual HRESULT STDMETHODCALLTYPE Accept( void) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_DefaultText( + /* [retval][out] */ LPWSTR *defaultText) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_ResultText( + /* [retval][out] */ LPWSTR *resultText) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_ResultText( + /* [in] */ LPCWSTR resultText) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDeferral( + /* [retval][out] */ ICoreWebView2Deferral **deferral) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2ScriptDialogOpeningEventArgsVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2ScriptDialogOpeningEventArgs * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2ScriptDialogOpeningEventArgs * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2ScriptDialogOpeningEventArgs * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Uri )( + ICoreWebView2ScriptDialogOpeningEventArgs * This, + /* [retval][out] */ LPWSTR *uri); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Kind )( + ICoreWebView2ScriptDialogOpeningEventArgs * This, + /* [retval][out] */ COREWEBVIEW2_SCRIPT_DIALOG_KIND *kind); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Message )( + ICoreWebView2ScriptDialogOpeningEventArgs * This, + /* [retval][out] */ LPWSTR *message); + + HRESULT ( STDMETHODCALLTYPE *Accept )( + ICoreWebView2ScriptDialogOpeningEventArgs * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_DefaultText )( + ICoreWebView2ScriptDialogOpeningEventArgs * This, + /* [retval][out] */ LPWSTR *defaultText); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_ResultText )( + ICoreWebView2ScriptDialogOpeningEventArgs * This, + /* [retval][out] */ LPWSTR *resultText); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_ResultText )( + ICoreWebView2ScriptDialogOpeningEventArgs * This, + /* [in] */ LPCWSTR resultText); + + HRESULT ( STDMETHODCALLTYPE *GetDeferral )( + ICoreWebView2ScriptDialogOpeningEventArgs * This, + /* [retval][out] */ ICoreWebView2Deferral **deferral); + + END_INTERFACE + } ICoreWebView2ScriptDialogOpeningEventArgsVtbl; + + interface ICoreWebView2ScriptDialogOpeningEventArgs + { + CONST_VTBL struct ICoreWebView2ScriptDialogOpeningEventArgsVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2ScriptDialogOpeningEventArgs_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2ScriptDialogOpeningEventArgs_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2ScriptDialogOpeningEventArgs_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2ScriptDialogOpeningEventArgs_get_Uri(This,uri) \ + ( (This)->lpVtbl -> get_Uri(This,uri) ) + +#define ICoreWebView2ScriptDialogOpeningEventArgs_get_Kind(This,kind) \ + ( (This)->lpVtbl -> get_Kind(This,kind) ) + +#define ICoreWebView2ScriptDialogOpeningEventArgs_get_Message(This,message) \ + ( (This)->lpVtbl -> get_Message(This,message) ) + +#define ICoreWebView2ScriptDialogOpeningEventArgs_Accept(This) \ + ( (This)->lpVtbl -> Accept(This) ) + +#define ICoreWebView2ScriptDialogOpeningEventArgs_get_DefaultText(This,defaultText) \ + ( (This)->lpVtbl -> get_DefaultText(This,defaultText) ) + +#define ICoreWebView2ScriptDialogOpeningEventArgs_get_ResultText(This,resultText) \ + ( (This)->lpVtbl -> get_ResultText(This,resultText) ) + +#define ICoreWebView2ScriptDialogOpeningEventArgs_put_ResultText(This,resultText) \ + ( (This)->lpVtbl -> put_ResultText(This,resultText) ) + +#define ICoreWebView2ScriptDialogOpeningEventArgs_GetDeferral(This,deferral) \ + ( (This)->lpVtbl -> GetDeferral(This,deferral) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2ScriptDialogOpeningEventArgs_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2ScriptDialogOpeningEventHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2ScriptDialogOpeningEventHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2ScriptDialogOpeningEventHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2ScriptDialogOpeningEventHandler = {0xef381bf9,0xafa8,0x4e37,{0x91,0xc4,0x8a,0xc4,0x85,0x24,0xbd,0xfb}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("ef381bf9-afa8-4e37-91c4-8ac48524bdfb") + ICoreWebView2ScriptDialogOpeningEventHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + /* [in] */ ICoreWebView2 *sender, + /* [in] */ ICoreWebView2ScriptDialogOpeningEventArgs *args) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2ScriptDialogOpeningEventHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2ScriptDialogOpeningEventHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2ScriptDialogOpeningEventHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2ScriptDialogOpeningEventHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2ScriptDialogOpeningEventHandler * This, + /* [in] */ ICoreWebView2 *sender, + /* [in] */ ICoreWebView2ScriptDialogOpeningEventArgs *args); + + END_INTERFACE + } ICoreWebView2ScriptDialogOpeningEventHandlerVtbl; + + interface ICoreWebView2ScriptDialogOpeningEventHandler + { + CONST_VTBL struct ICoreWebView2ScriptDialogOpeningEventHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2ScriptDialogOpeningEventHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2ScriptDialogOpeningEventHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2ScriptDialogOpeningEventHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2ScriptDialogOpeningEventHandler_Invoke(This,sender,args) \ + ( (This)->lpVtbl -> Invoke(This,sender,args) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2ScriptDialogOpeningEventHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2Settings_INTERFACE_DEFINED__ +#define __ICoreWebView2Settings_INTERFACE_DEFINED__ + +/* interface ICoreWebView2Settings */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2Settings = {0xe562e4f0,0xd7fa,0x43ac,{0x8d,0x71,0xc0,0x51,0x50,0x49,0x9f,0x00}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("e562e4f0-d7fa-43ac-8d71-c05150499f00") + ICoreWebView2Settings : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_IsScriptEnabled( + /* [retval][out] */ BOOL *isScriptEnabled) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_IsScriptEnabled( + /* [in] */ BOOL isScriptEnabled) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_IsWebMessageEnabled( + /* [retval][out] */ BOOL *isWebMessageEnabled) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_IsWebMessageEnabled( + /* [in] */ BOOL isWebMessageEnabled) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_AreDefaultScriptDialogsEnabled( + /* [retval][out] */ BOOL *areDefaultScriptDialogsEnabled) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_AreDefaultScriptDialogsEnabled( + /* [in] */ BOOL areDefaultScriptDialogsEnabled) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_IsStatusBarEnabled( + /* [retval][out] */ BOOL *isStatusBarEnabled) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_IsStatusBarEnabled( + /* [in] */ BOOL isStatusBarEnabled) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_AreDevToolsEnabled( + /* [retval][out] */ BOOL *areDevToolsEnabled) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_AreDevToolsEnabled( + /* [in] */ BOOL areDevToolsEnabled) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_AreDefaultContextMenusEnabled( + /* [retval][out] */ BOOL *enabled) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_AreDefaultContextMenusEnabled( + /* [in] */ BOOL enabled) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_AreHostObjectsAllowed( + /* [retval][out] */ BOOL *allowed) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_AreHostObjectsAllowed( + /* [in] */ BOOL allowed) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_IsZoomControlEnabled( + /* [retval][out] */ BOOL *enabled) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_IsZoomControlEnabled( + /* [in] */ BOOL enabled) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_IsBuiltInErrorPageEnabled( + /* [retval][out] */ BOOL *enabled) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_IsBuiltInErrorPageEnabled( + /* [in] */ BOOL enabled) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2SettingsVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2Settings * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2Settings * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2Settings * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_IsScriptEnabled )( + ICoreWebView2Settings * This, + /* [retval][out] */ BOOL *isScriptEnabled); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_IsScriptEnabled )( + ICoreWebView2Settings * This, + /* [in] */ BOOL isScriptEnabled); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_IsWebMessageEnabled )( + ICoreWebView2Settings * This, + /* [retval][out] */ BOOL *isWebMessageEnabled); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_IsWebMessageEnabled )( + ICoreWebView2Settings * This, + /* [in] */ BOOL isWebMessageEnabled); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_AreDefaultScriptDialogsEnabled )( + ICoreWebView2Settings * This, + /* [retval][out] */ BOOL *areDefaultScriptDialogsEnabled); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_AreDefaultScriptDialogsEnabled )( + ICoreWebView2Settings * This, + /* [in] */ BOOL areDefaultScriptDialogsEnabled); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_IsStatusBarEnabled )( + ICoreWebView2Settings * This, + /* [retval][out] */ BOOL *isStatusBarEnabled); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_IsStatusBarEnabled )( + ICoreWebView2Settings * This, + /* [in] */ BOOL isStatusBarEnabled); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_AreDevToolsEnabled )( + ICoreWebView2Settings * This, + /* [retval][out] */ BOOL *areDevToolsEnabled); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_AreDevToolsEnabled )( + ICoreWebView2Settings * This, + /* [in] */ BOOL areDevToolsEnabled); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_AreDefaultContextMenusEnabled )( + ICoreWebView2Settings * This, + /* [retval][out] */ BOOL *enabled); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_AreDefaultContextMenusEnabled )( + ICoreWebView2Settings * This, + /* [in] */ BOOL enabled); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_AreHostObjectsAllowed )( + ICoreWebView2Settings * This, + /* [retval][out] */ BOOL *allowed); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_AreHostObjectsAllowed )( + ICoreWebView2Settings * This, + /* [in] */ BOOL allowed); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_IsZoomControlEnabled )( + ICoreWebView2Settings * This, + /* [retval][out] */ BOOL *enabled); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_IsZoomControlEnabled )( + ICoreWebView2Settings * This, + /* [in] */ BOOL enabled); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_IsBuiltInErrorPageEnabled )( + ICoreWebView2Settings * This, + /* [retval][out] */ BOOL *enabled); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_IsBuiltInErrorPageEnabled )( + ICoreWebView2Settings * This, + /* [in] */ BOOL enabled); + + END_INTERFACE + } ICoreWebView2SettingsVtbl; + + interface ICoreWebView2Settings + { + CONST_VTBL struct ICoreWebView2SettingsVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2Settings_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2Settings_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2Settings_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2Settings_get_IsScriptEnabled(This,isScriptEnabled) \ + ( (This)->lpVtbl -> get_IsScriptEnabled(This,isScriptEnabled) ) + +#define ICoreWebView2Settings_put_IsScriptEnabled(This,isScriptEnabled) \ + ( (This)->lpVtbl -> put_IsScriptEnabled(This,isScriptEnabled) ) + +#define ICoreWebView2Settings_get_IsWebMessageEnabled(This,isWebMessageEnabled) \ + ( (This)->lpVtbl -> get_IsWebMessageEnabled(This,isWebMessageEnabled) ) + +#define ICoreWebView2Settings_put_IsWebMessageEnabled(This,isWebMessageEnabled) \ + ( (This)->lpVtbl -> put_IsWebMessageEnabled(This,isWebMessageEnabled) ) + +#define ICoreWebView2Settings_get_AreDefaultScriptDialogsEnabled(This,areDefaultScriptDialogsEnabled) \ + ( (This)->lpVtbl -> get_AreDefaultScriptDialogsEnabled(This,areDefaultScriptDialogsEnabled) ) + +#define ICoreWebView2Settings_put_AreDefaultScriptDialogsEnabled(This,areDefaultScriptDialogsEnabled) \ + ( (This)->lpVtbl -> put_AreDefaultScriptDialogsEnabled(This,areDefaultScriptDialogsEnabled) ) + +#define ICoreWebView2Settings_get_IsStatusBarEnabled(This,isStatusBarEnabled) \ + ( (This)->lpVtbl -> get_IsStatusBarEnabled(This,isStatusBarEnabled) ) + +#define ICoreWebView2Settings_put_IsStatusBarEnabled(This,isStatusBarEnabled) \ + ( (This)->lpVtbl -> put_IsStatusBarEnabled(This,isStatusBarEnabled) ) + +#define ICoreWebView2Settings_get_AreDevToolsEnabled(This,areDevToolsEnabled) \ + ( (This)->lpVtbl -> get_AreDevToolsEnabled(This,areDevToolsEnabled) ) + +#define ICoreWebView2Settings_put_AreDevToolsEnabled(This,areDevToolsEnabled) \ + ( (This)->lpVtbl -> put_AreDevToolsEnabled(This,areDevToolsEnabled) ) + +#define ICoreWebView2Settings_get_AreDefaultContextMenusEnabled(This,enabled) \ + ( (This)->lpVtbl -> get_AreDefaultContextMenusEnabled(This,enabled) ) + +#define ICoreWebView2Settings_put_AreDefaultContextMenusEnabled(This,enabled) \ + ( (This)->lpVtbl -> put_AreDefaultContextMenusEnabled(This,enabled) ) + +#define ICoreWebView2Settings_get_AreHostObjectsAllowed(This,allowed) \ + ( (This)->lpVtbl -> get_AreHostObjectsAllowed(This,allowed) ) + +#define ICoreWebView2Settings_put_AreHostObjectsAllowed(This,allowed) \ + ( (This)->lpVtbl -> put_AreHostObjectsAllowed(This,allowed) ) + +#define ICoreWebView2Settings_get_IsZoomControlEnabled(This,enabled) \ + ( (This)->lpVtbl -> get_IsZoomControlEnabled(This,enabled) ) + +#define ICoreWebView2Settings_put_IsZoomControlEnabled(This,enabled) \ + ( (This)->lpVtbl -> put_IsZoomControlEnabled(This,enabled) ) + +#define ICoreWebView2Settings_get_IsBuiltInErrorPageEnabled(This,enabled) \ + ( (This)->lpVtbl -> get_IsBuiltInErrorPageEnabled(This,enabled) ) + +#define ICoreWebView2Settings_put_IsBuiltInErrorPageEnabled(This,enabled) \ + ( (This)->lpVtbl -> put_IsBuiltInErrorPageEnabled(This,enabled) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2Settings_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2Settings2_INTERFACE_DEFINED__ +#define __ICoreWebView2Settings2_INTERFACE_DEFINED__ + +/* interface ICoreWebView2Settings2 */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2Settings2 = {0xee9a0f68,0xf46c,0x4e32,{0xac,0x23,0xef,0x8c,0xac,0x22,0x4d,0x2a}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("ee9a0f68-f46c-4e32-ac23-ef8cac224d2a") + ICoreWebView2Settings2 : public ICoreWebView2Settings + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_UserAgent( + /* [retval][out] */ LPWSTR *userAgent) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_UserAgent( + /* [in] */ LPCWSTR userAgent) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2Settings2Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2Settings2 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2Settings2 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2Settings2 * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_IsScriptEnabled )( + ICoreWebView2Settings2 * This, + /* [retval][out] */ BOOL *isScriptEnabled); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_IsScriptEnabled )( + ICoreWebView2Settings2 * This, + /* [in] */ BOOL isScriptEnabled); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_IsWebMessageEnabled )( + ICoreWebView2Settings2 * This, + /* [retval][out] */ BOOL *isWebMessageEnabled); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_IsWebMessageEnabled )( + ICoreWebView2Settings2 * This, + /* [in] */ BOOL isWebMessageEnabled); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_AreDefaultScriptDialogsEnabled )( + ICoreWebView2Settings2 * This, + /* [retval][out] */ BOOL *areDefaultScriptDialogsEnabled); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_AreDefaultScriptDialogsEnabled )( + ICoreWebView2Settings2 * This, + /* [in] */ BOOL areDefaultScriptDialogsEnabled); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_IsStatusBarEnabled )( + ICoreWebView2Settings2 * This, + /* [retval][out] */ BOOL *isStatusBarEnabled); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_IsStatusBarEnabled )( + ICoreWebView2Settings2 * This, + /* [in] */ BOOL isStatusBarEnabled); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_AreDevToolsEnabled )( + ICoreWebView2Settings2 * This, + /* [retval][out] */ BOOL *areDevToolsEnabled); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_AreDevToolsEnabled )( + ICoreWebView2Settings2 * This, + /* [in] */ BOOL areDevToolsEnabled); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_AreDefaultContextMenusEnabled )( + ICoreWebView2Settings2 * This, + /* [retval][out] */ BOOL *enabled); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_AreDefaultContextMenusEnabled )( + ICoreWebView2Settings2 * This, + /* [in] */ BOOL enabled); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_AreHostObjectsAllowed )( + ICoreWebView2Settings2 * This, + /* [retval][out] */ BOOL *allowed); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_AreHostObjectsAllowed )( + ICoreWebView2Settings2 * This, + /* [in] */ BOOL allowed); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_IsZoomControlEnabled )( + ICoreWebView2Settings2 * This, + /* [retval][out] */ BOOL *enabled); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_IsZoomControlEnabled )( + ICoreWebView2Settings2 * This, + /* [in] */ BOOL enabled); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_IsBuiltInErrorPageEnabled )( + ICoreWebView2Settings2 * This, + /* [retval][out] */ BOOL *enabled); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_IsBuiltInErrorPageEnabled )( + ICoreWebView2Settings2 * This, + /* [in] */ BOOL enabled); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_UserAgent )( + ICoreWebView2Settings2 * This, + /* [retval][out] */ LPWSTR *userAgent); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_UserAgent )( + ICoreWebView2Settings2 * This, + /* [in] */ LPCWSTR userAgent); + + END_INTERFACE + } ICoreWebView2Settings2Vtbl; + + interface ICoreWebView2Settings2 + { + CONST_VTBL struct ICoreWebView2Settings2Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2Settings2_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2Settings2_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2Settings2_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2Settings2_get_IsScriptEnabled(This,isScriptEnabled) \ + ( (This)->lpVtbl -> get_IsScriptEnabled(This,isScriptEnabled) ) + +#define ICoreWebView2Settings2_put_IsScriptEnabled(This,isScriptEnabled) \ + ( (This)->lpVtbl -> put_IsScriptEnabled(This,isScriptEnabled) ) + +#define ICoreWebView2Settings2_get_IsWebMessageEnabled(This,isWebMessageEnabled) \ + ( (This)->lpVtbl -> get_IsWebMessageEnabled(This,isWebMessageEnabled) ) + +#define ICoreWebView2Settings2_put_IsWebMessageEnabled(This,isWebMessageEnabled) \ + ( (This)->lpVtbl -> put_IsWebMessageEnabled(This,isWebMessageEnabled) ) + +#define ICoreWebView2Settings2_get_AreDefaultScriptDialogsEnabled(This,areDefaultScriptDialogsEnabled) \ + ( (This)->lpVtbl -> get_AreDefaultScriptDialogsEnabled(This,areDefaultScriptDialogsEnabled) ) + +#define ICoreWebView2Settings2_put_AreDefaultScriptDialogsEnabled(This,areDefaultScriptDialogsEnabled) \ + ( (This)->lpVtbl -> put_AreDefaultScriptDialogsEnabled(This,areDefaultScriptDialogsEnabled) ) + +#define ICoreWebView2Settings2_get_IsStatusBarEnabled(This,isStatusBarEnabled) \ + ( (This)->lpVtbl -> get_IsStatusBarEnabled(This,isStatusBarEnabled) ) + +#define ICoreWebView2Settings2_put_IsStatusBarEnabled(This,isStatusBarEnabled) \ + ( (This)->lpVtbl -> put_IsStatusBarEnabled(This,isStatusBarEnabled) ) + +#define ICoreWebView2Settings2_get_AreDevToolsEnabled(This,areDevToolsEnabled) \ + ( (This)->lpVtbl -> get_AreDevToolsEnabled(This,areDevToolsEnabled) ) + +#define ICoreWebView2Settings2_put_AreDevToolsEnabled(This,areDevToolsEnabled) \ + ( (This)->lpVtbl -> put_AreDevToolsEnabled(This,areDevToolsEnabled) ) + +#define ICoreWebView2Settings2_get_AreDefaultContextMenusEnabled(This,enabled) \ + ( (This)->lpVtbl -> get_AreDefaultContextMenusEnabled(This,enabled) ) + +#define ICoreWebView2Settings2_put_AreDefaultContextMenusEnabled(This,enabled) \ + ( (This)->lpVtbl -> put_AreDefaultContextMenusEnabled(This,enabled) ) + +#define ICoreWebView2Settings2_get_AreHostObjectsAllowed(This,allowed) \ + ( (This)->lpVtbl -> get_AreHostObjectsAllowed(This,allowed) ) + +#define ICoreWebView2Settings2_put_AreHostObjectsAllowed(This,allowed) \ + ( (This)->lpVtbl -> put_AreHostObjectsAllowed(This,allowed) ) + +#define ICoreWebView2Settings2_get_IsZoomControlEnabled(This,enabled) \ + ( (This)->lpVtbl -> get_IsZoomControlEnabled(This,enabled) ) + +#define ICoreWebView2Settings2_put_IsZoomControlEnabled(This,enabled) \ + ( (This)->lpVtbl -> put_IsZoomControlEnabled(This,enabled) ) + +#define ICoreWebView2Settings2_get_IsBuiltInErrorPageEnabled(This,enabled) \ + ( (This)->lpVtbl -> get_IsBuiltInErrorPageEnabled(This,enabled) ) + +#define ICoreWebView2Settings2_put_IsBuiltInErrorPageEnabled(This,enabled) \ + ( (This)->lpVtbl -> put_IsBuiltInErrorPageEnabled(This,enabled) ) + + +#define ICoreWebView2Settings2_get_UserAgent(This,userAgent) \ + ( (This)->lpVtbl -> get_UserAgent(This,userAgent) ) + +#define ICoreWebView2Settings2_put_UserAgent(This,userAgent) \ + ( (This)->lpVtbl -> put_UserAgent(This,userAgent) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2Settings2_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2Settings3_INTERFACE_DEFINED__ +#define __ICoreWebView2Settings3_INTERFACE_DEFINED__ + +/* interface ICoreWebView2Settings3 */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2Settings3 = {0xfdb5ab74,0xaf33,0x4854,{0x84,0xf0,0x0a,0x63,0x1d,0xeb,0x5e,0xba}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("fdb5ab74-af33-4854-84f0-0a631deb5eba") + ICoreWebView2Settings3 : public ICoreWebView2Settings2 + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_AreBrowserAcceleratorKeysEnabled( + /* [retval][out] */ BOOL *areBrowserAcceleratorKeysEnabled) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_AreBrowserAcceleratorKeysEnabled( + /* [in] */ BOOL areBrowserAcceleratorKeysEnabled) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2Settings3Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2Settings3 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2Settings3 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2Settings3 * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_IsScriptEnabled )( + ICoreWebView2Settings3 * This, + /* [retval][out] */ BOOL *isScriptEnabled); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_IsScriptEnabled )( + ICoreWebView2Settings3 * This, + /* [in] */ BOOL isScriptEnabled); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_IsWebMessageEnabled )( + ICoreWebView2Settings3 * This, + /* [retval][out] */ BOOL *isWebMessageEnabled); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_IsWebMessageEnabled )( + ICoreWebView2Settings3 * This, + /* [in] */ BOOL isWebMessageEnabled); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_AreDefaultScriptDialogsEnabled )( + ICoreWebView2Settings3 * This, + /* [retval][out] */ BOOL *areDefaultScriptDialogsEnabled); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_AreDefaultScriptDialogsEnabled )( + ICoreWebView2Settings3 * This, + /* [in] */ BOOL areDefaultScriptDialogsEnabled); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_IsStatusBarEnabled )( + ICoreWebView2Settings3 * This, + /* [retval][out] */ BOOL *isStatusBarEnabled); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_IsStatusBarEnabled )( + ICoreWebView2Settings3 * This, + /* [in] */ BOOL isStatusBarEnabled); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_AreDevToolsEnabled )( + ICoreWebView2Settings3 * This, + /* [retval][out] */ BOOL *areDevToolsEnabled); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_AreDevToolsEnabled )( + ICoreWebView2Settings3 * This, + /* [in] */ BOOL areDevToolsEnabled); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_AreDefaultContextMenusEnabled )( + ICoreWebView2Settings3 * This, + /* [retval][out] */ BOOL *enabled); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_AreDefaultContextMenusEnabled )( + ICoreWebView2Settings3 * This, + /* [in] */ BOOL enabled); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_AreHostObjectsAllowed )( + ICoreWebView2Settings3 * This, + /* [retval][out] */ BOOL *allowed); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_AreHostObjectsAllowed )( + ICoreWebView2Settings3 * This, + /* [in] */ BOOL allowed); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_IsZoomControlEnabled )( + ICoreWebView2Settings3 * This, + /* [retval][out] */ BOOL *enabled); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_IsZoomControlEnabled )( + ICoreWebView2Settings3 * This, + /* [in] */ BOOL enabled); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_IsBuiltInErrorPageEnabled )( + ICoreWebView2Settings3 * This, + /* [retval][out] */ BOOL *enabled); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_IsBuiltInErrorPageEnabled )( + ICoreWebView2Settings3 * This, + /* [in] */ BOOL enabled); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_UserAgent )( + ICoreWebView2Settings3 * This, + /* [retval][out] */ LPWSTR *userAgent); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_UserAgent )( + ICoreWebView2Settings3 * This, + /* [in] */ LPCWSTR userAgent); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_AreBrowserAcceleratorKeysEnabled )( + ICoreWebView2Settings3 * This, + /* [retval][out] */ BOOL *areBrowserAcceleratorKeysEnabled); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_AreBrowserAcceleratorKeysEnabled )( + ICoreWebView2Settings3 * This, + /* [in] */ BOOL areBrowserAcceleratorKeysEnabled); + + END_INTERFACE + } ICoreWebView2Settings3Vtbl; + + interface ICoreWebView2Settings3 + { + CONST_VTBL struct ICoreWebView2Settings3Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2Settings3_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2Settings3_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2Settings3_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2Settings3_get_IsScriptEnabled(This,isScriptEnabled) \ + ( (This)->lpVtbl -> get_IsScriptEnabled(This,isScriptEnabled) ) + +#define ICoreWebView2Settings3_put_IsScriptEnabled(This,isScriptEnabled) \ + ( (This)->lpVtbl -> put_IsScriptEnabled(This,isScriptEnabled) ) + +#define ICoreWebView2Settings3_get_IsWebMessageEnabled(This,isWebMessageEnabled) \ + ( (This)->lpVtbl -> get_IsWebMessageEnabled(This,isWebMessageEnabled) ) + +#define ICoreWebView2Settings3_put_IsWebMessageEnabled(This,isWebMessageEnabled) \ + ( (This)->lpVtbl -> put_IsWebMessageEnabled(This,isWebMessageEnabled) ) + +#define ICoreWebView2Settings3_get_AreDefaultScriptDialogsEnabled(This,areDefaultScriptDialogsEnabled) \ + ( (This)->lpVtbl -> get_AreDefaultScriptDialogsEnabled(This,areDefaultScriptDialogsEnabled) ) + +#define ICoreWebView2Settings3_put_AreDefaultScriptDialogsEnabled(This,areDefaultScriptDialogsEnabled) \ + ( (This)->lpVtbl -> put_AreDefaultScriptDialogsEnabled(This,areDefaultScriptDialogsEnabled) ) + +#define ICoreWebView2Settings3_get_IsStatusBarEnabled(This,isStatusBarEnabled) \ + ( (This)->lpVtbl -> get_IsStatusBarEnabled(This,isStatusBarEnabled) ) + +#define ICoreWebView2Settings3_put_IsStatusBarEnabled(This,isStatusBarEnabled) \ + ( (This)->lpVtbl -> put_IsStatusBarEnabled(This,isStatusBarEnabled) ) + +#define ICoreWebView2Settings3_get_AreDevToolsEnabled(This,areDevToolsEnabled) \ + ( (This)->lpVtbl -> get_AreDevToolsEnabled(This,areDevToolsEnabled) ) + +#define ICoreWebView2Settings3_put_AreDevToolsEnabled(This,areDevToolsEnabled) \ + ( (This)->lpVtbl -> put_AreDevToolsEnabled(This,areDevToolsEnabled) ) + +#define ICoreWebView2Settings3_get_AreDefaultContextMenusEnabled(This,enabled) \ + ( (This)->lpVtbl -> get_AreDefaultContextMenusEnabled(This,enabled) ) + +#define ICoreWebView2Settings3_put_AreDefaultContextMenusEnabled(This,enabled) \ + ( (This)->lpVtbl -> put_AreDefaultContextMenusEnabled(This,enabled) ) + +#define ICoreWebView2Settings3_get_AreHostObjectsAllowed(This,allowed) \ + ( (This)->lpVtbl -> get_AreHostObjectsAllowed(This,allowed) ) + +#define ICoreWebView2Settings3_put_AreHostObjectsAllowed(This,allowed) \ + ( (This)->lpVtbl -> put_AreHostObjectsAllowed(This,allowed) ) + +#define ICoreWebView2Settings3_get_IsZoomControlEnabled(This,enabled) \ + ( (This)->lpVtbl -> get_IsZoomControlEnabled(This,enabled) ) + +#define ICoreWebView2Settings3_put_IsZoomControlEnabled(This,enabled) \ + ( (This)->lpVtbl -> put_IsZoomControlEnabled(This,enabled) ) + +#define ICoreWebView2Settings3_get_IsBuiltInErrorPageEnabled(This,enabled) \ + ( (This)->lpVtbl -> get_IsBuiltInErrorPageEnabled(This,enabled) ) + +#define ICoreWebView2Settings3_put_IsBuiltInErrorPageEnabled(This,enabled) \ + ( (This)->lpVtbl -> put_IsBuiltInErrorPageEnabled(This,enabled) ) + + +#define ICoreWebView2Settings3_get_UserAgent(This,userAgent) \ + ( (This)->lpVtbl -> get_UserAgent(This,userAgent) ) + +#define ICoreWebView2Settings3_put_UserAgent(This,userAgent) \ + ( (This)->lpVtbl -> put_UserAgent(This,userAgent) ) + + +#define ICoreWebView2Settings3_get_AreBrowserAcceleratorKeysEnabled(This,areBrowserAcceleratorKeysEnabled) \ + ( (This)->lpVtbl -> get_AreBrowserAcceleratorKeysEnabled(This,areBrowserAcceleratorKeysEnabled) ) + +#define ICoreWebView2Settings3_put_AreBrowserAcceleratorKeysEnabled(This,areBrowserAcceleratorKeysEnabled) \ + ( (This)->lpVtbl -> put_AreBrowserAcceleratorKeysEnabled(This,areBrowserAcceleratorKeysEnabled) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2Settings3_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2SourceChangedEventArgs_INTERFACE_DEFINED__ +#define __ICoreWebView2SourceChangedEventArgs_INTERFACE_DEFINED__ + +/* interface ICoreWebView2SourceChangedEventArgs */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2SourceChangedEventArgs = {0x31e0e545,0x1dba,0x4266,{0x89,0x14,0xf6,0x38,0x48,0xa1,0xf7,0xd7}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("31e0e545-1dba-4266-8914-f63848a1f7d7") + ICoreWebView2SourceChangedEventArgs : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_IsNewDocument( + /* [retval][out] */ BOOL *isNewDocument) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2SourceChangedEventArgsVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2SourceChangedEventArgs * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2SourceChangedEventArgs * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2SourceChangedEventArgs * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_IsNewDocument )( + ICoreWebView2SourceChangedEventArgs * This, + /* [retval][out] */ BOOL *isNewDocument); + + END_INTERFACE + } ICoreWebView2SourceChangedEventArgsVtbl; + + interface ICoreWebView2SourceChangedEventArgs + { + CONST_VTBL struct ICoreWebView2SourceChangedEventArgsVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2SourceChangedEventArgs_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2SourceChangedEventArgs_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2SourceChangedEventArgs_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2SourceChangedEventArgs_get_IsNewDocument(This,isNewDocument) \ + ( (This)->lpVtbl -> get_IsNewDocument(This,isNewDocument) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2SourceChangedEventArgs_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2SourceChangedEventHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2SourceChangedEventHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2SourceChangedEventHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2SourceChangedEventHandler = {0x3c067f9f,0x5388,0x4772,{0x8b,0x48,0x79,0xf7,0xef,0x1a,0xb3,0x7c}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("3c067f9f-5388-4772-8b48-79f7ef1ab37c") + ICoreWebView2SourceChangedEventHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + /* [in] */ ICoreWebView2 *sender, + /* [in] */ ICoreWebView2SourceChangedEventArgs *args) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2SourceChangedEventHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2SourceChangedEventHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2SourceChangedEventHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2SourceChangedEventHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2SourceChangedEventHandler * This, + /* [in] */ ICoreWebView2 *sender, + /* [in] */ ICoreWebView2SourceChangedEventArgs *args); + + END_INTERFACE + } ICoreWebView2SourceChangedEventHandlerVtbl; + + interface ICoreWebView2SourceChangedEventHandler + { + CONST_VTBL struct ICoreWebView2SourceChangedEventHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2SourceChangedEventHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2SourceChangedEventHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2SourceChangedEventHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2SourceChangedEventHandler_Invoke(This,sender,args) \ + ( (This)->lpVtbl -> Invoke(This,sender,args) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2SourceChangedEventHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2TrySuspendCompletedHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2TrySuspendCompletedHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2TrySuspendCompletedHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2TrySuspendCompletedHandler = {0x00F206A7,0x9D17,0x4605,{0x91,0xF6,0x4E,0x8E,0x4D,0xE1,0x92,0xE3}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("00F206A7-9D17-4605-91F6-4E8E4DE192E3") + ICoreWebView2TrySuspendCompletedHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + /* [in] */ HRESULT errorCode, + /* [in] */ BOOL isSuccessful) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2TrySuspendCompletedHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2TrySuspendCompletedHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2TrySuspendCompletedHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2TrySuspendCompletedHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2TrySuspendCompletedHandler * This, + /* [in] */ HRESULT errorCode, + /* [in] */ BOOL isSuccessful); + + END_INTERFACE + } ICoreWebView2TrySuspendCompletedHandlerVtbl; + + interface ICoreWebView2TrySuspendCompletedHandler + { + CONST_VTBL struct ICoreWebView2TrySuspendCompletedHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2TrySuspendCompletedHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2TrySuspendCompletedHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2TrySuspendCompletedHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2TrySuspendCompletedHandler_Invoke(This,errorCode,isSuccessful) \ + ( (This)->lpVtbl -> Invoke(This,errorCode,isSuccessful) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2TrySuspendCompletedHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2WebMessageReceivedEventArgs_INTERFACE_DEFINED__ +#define __ICoreWebView2WebMessageReceivedEventArgs_INTERFACE_DEFINED__ + +/* interface ICoreWebView2WebMessageReceivedEventArgs */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2WebMessageReceivedEventArgs = {0x0f99a40c,0xe962,0x4207,{0x9e,0x92,0xe3,0xd5,0x42,0xef,0xf8,0x49}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("0f99a40c-e962-4207-9e92-e3d542eff849") + ICoreWebView2WebMessageReceivedEventArgs : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Source( + /* [retval][out] */ LPWSTR *source) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_WebMessageAsJson( + /* [retval][out] */ LPWSTR *webMessageAsJson) = 0; + + virtual HRESULT STDMETHODCALLTYPE TryGetWebMessageAsString( + /* [retval][out] */ LPWSTR *webMessageAsString) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2WebMessageReceivedEventArgsVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2WebMessageReceivedEventArgs * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2WebMessageReceivedEventArgs * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2WebMessageReceivedEventArgs * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Source )( + ICoreWebView2WebMessageReceivedEventArgs * This, + /* [retval][out] */ LPWSTR *source); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_WebMessageAsJson )( + ICoreWebView2WebMessageReceivedEventArgs * This, + /* [retval][out] */ LPWSTR *webMessageAsJson); + + HRESULT ( STDMETHODCALLTYPE *TryGetWebMessageAsString )( + ICoreWebView2WebMessageReceivedEventArgs * This, + /* [retval][out] */ LPWSTR *webMessageAsString); + + END_INTERFACE + } ICoreWebView2WebMessageReceivedEventArgsVtbl; + + interface ICoreWebView2WebMessageReceivedEventArgs + { + CONST_VTBL struct ICoreWebView2WebMessageReceivedEventArgsVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2WebMessageReceivedEventArgs_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2WebMessageReceivedEventArgs_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2WebMessageReceivedEventArgs_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2WebMessageReceivedEventArgs_get_Source(This,source) \ + ( (This)->lpVtbl -> get_Source(This,source) ) + +#define ICoreWebView2WebMessageReceivedEventArgs_get_WebMessageAsJson(This,webMessageAsJson) \ + ( (This)->lpVtbl -> get_WebMessageAsJson(This,webMessageAsJson) ) + +#define ICoreWebView2WebMessageReceivedEventArgs_TryGetWebMessageAsString(This,webMessageAsString) \ + ( (This)->lpVtbl -> TryGetWebMessageAsString(This,webMessageAsString) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2WebMessageReceivedEventArgs_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2WebMessageReceivedEventHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2WebMessageReceivedEventHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2WebMessageReceivedEventHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2WebMessageReceivedEventHandler = {0x57213f19,0x00e6,0x49fa,{0x8e,0x07,0x89,0x8e,0xa0,0x1e,0xcb,0xd2}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("57213f19-00e6-49fa-8e07-898ea01ecbd2") + ICoreWebView2WebMessageReceivedEventHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + /* [in] */ ICoreWebView2 *sender, + /* [in] */ ICoreWebView2WebMessageReceivedEventArgs *args) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2WebMessageReceivedEventHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2WebMessageReceivedEventHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2WebMessageReceivedEventHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2WebMessageReceivedEventHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2WebMessageReceivedEventHandler * This, + /* [in] */ ICoreWebView2 *sender, + /* [in] */ ICoreWebView2WebMessageReceivedEventArgs *args); + + END_INTERFACE + } ICoreWebView2WebMessageReceivedEventHandlerVtbl; + + interface ICoreWebView2WebMessageReceivedEventHandler + { + CONST_VTBL struct ICoreWebView2WebMessageReceivedEventHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2WebMessageReceivedEventHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2WebMessageReceivedEventHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2WebMessageReceivedEventHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2WebMessageReceivedEventHandler_Invoke(This,sender,args) \ + ( (This)->lpVtbl -> Invoke(This,sender,args) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2WebMessageReceivedEventHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2WebResourceRequest_INTERFACE_DEFINED__ +#define __ICoreWebView2WebResourceRequest_INTERFACE_DEFINED__ + +/* interface ICoreWebView2WebResourceRequest */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2WebResourceRequest = {0x97055cd4,0x512c,0x4264,{0x8b,0x5f,0xe3,0xf4,0x46,0xce,0xa6,0xa5}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("97055cd4-512c-4264-8b5f-e3f446cea6a5") + ICoreWebView2WebResourceRequest : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Uri( + /* [retval][out] */ LPWSTR *uri) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_Uri( + /* [in] */ LPCWSTR uri) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Method( + /* [retval][out] */ LPWSTR *method) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_Method( + /* [in] */ LPCWSTR method) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Content( + /* [retval][out] */ IStream **content) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_Content( + /* [in] */ IStream *content) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Headers( + /* [retval][out] */ ICoreWebView2HttpRequestHeaders **headers) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2WebResourceRequestVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2WebResourceRequest * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2WebResourceRequest * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2WebResourceRequest * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Uri )( + ICoreWebView2WebResourceRequest * This, + /* [retval][out] */ LPWSTR *uri); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_Uri )( + ICoreWebView2WebResourceRequest * This, + /* [in] */ LPCWSTR uri); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Method )( + ICoreWebView2WebResourceRequest * This, + /* [retval][out] */ LPWSTR *method); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_Method )( + ICoreWebView2WebResourceRequest * This, + /* [in] */ LPCWSTR method); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Content )( + ICoreWebView2WebResourceRequest * This, + /* [retval][out] */ IStream **content); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_Content )( + ICoreWebView2WebResourceRequest * This, + /* [in] */ IStream *content); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Headers )( + ICoreWebView2WebResourceRequest * This, + /* [retval][out] */ ICoreWebView2HttpRequestHeaders **headers); + + END_INTERFACE + } ICoreWebView2WebResourceRequestVtbl; + + interface ICoreWebView2WebResourceRequest + { + CONST_VTBL struct ICoreWebView2WebResourceRequestVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2WebResourceRequest_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2WebResourceRequest_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2WebResourceRequest_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2WebResourceRequest_get_Uri(This,uri) \ + ( (This)->lpVtbl -> get_Uri(This,uri) ) + +#define ICoreWebView2WebResourceRequest_put_Uri(This,uri) \ + ( (This)->lpVtbl -> put_Uri(This,uri) ) + +#define ICoreWebView2WebResourceRequest_get_Method(This,method) \ + ( (This)->lpVtbl -> get_Method(This,method) ) + +#define ICoreWebView2WebResourceRequest_put_Method(This,method) \ + ( (This)->lpVtbl -> put_Method(This,method) ) + +#define ICoreWebView2WebResourceRequest_get_Content(This,content) \ + ( (This)->lpVtbl -> get_Content(This,content) ) + +#define ICoreWebView2WebResourceRequest_put_Content(This,content) \ + ( (This)->lpVtbl -> put_Content(This,content) ) + +#define ICoreWebView2WebResourceRequest_get_Headers(This,headers) \ + ( (This)->lpVtbl -> get_Headers(This,headers) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2WebResourceRequest_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2WebResourceRequestedEventArgs_INTERFACE_DEFINED__ +#define __ICoreWebView2WebResourceRequestedEventArgs_INTERFACE_DEFINED__ + +/* interface ICoreWebView2WebResourceRequestedEventArgs */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2WebResourceRequestedEventArgs = {0x453e667f,0x12c7,0x49d4,{0xbe,0x6d,0xdd,0xbe,0x79,0x56,0xf5,0x7a}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("453e667f-12c7-49d4-be6d-ddbe7956f57a") + ICoreWebView2WebResourceRequestedEventArgs : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Request( + /* [retval][out] */ ICoreWebView2WebResourceRequest **request) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Response( + /* [retval][out] */ ICoreWebView2WebResourceResponse **response) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_Response( + /* [in] */ ICoreWebView2WebResourceResponse *response) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDeferral( + /* [retval][out] */ ICoreWebView2Deferral **deferral) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_ResourceContext( + /* [retval][out] */ COREWEBVIEW2_WEB_RESOURCE_CONTEXT *context) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2WebResourceRequestedEventArgsVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2WebResourceRequestedEventArgs * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2WebResourceRequestedEventArgs * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2WebResourceRequestedEventArgs * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Request )( + ICoreWebView2WebResourceRequestedEventArgs * This, + /* [retval][out] */ ICoreWebView2WebResourceRequest **request); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Response )( + ICoreWebView2WebResourceRequestedEventArgs * This, + /* [retval][out] */ ICoreWebView2WebResourceResponse **response); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_Response )( + ICoreWebView2WebResourceRequestedEventArgs * This, + /* [in] */ ICoreWebView2WebResourceResponse *response); + + HRESULT ( STDMETHODCALLTYPE *GetDeferral )( + ICoreWebView2WebResourceRequestedEventArgs * This, + /* [retval][out] */ ICoreWebView2Deferral **deferral); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_ResourceContext )( + ICoreWebView2WebResourceRequestedEventArgs * This, + /* [retval][out] */ COREWEBVIEW2_WEB_RESOURCE_CONTEXT *context); + + END_INTERFACE + } ICoreWebView2WebResourceRequestedEventArgsVtbl; + + interface ICoreWebView2WebResourceRequestedEventArgs + { + CONST_VTBL struct ICoreWebView2WebResourceRequestedEventArgsVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2WebResourceRequestedEventArgs_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2WebResourceRequestedEventArgs_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2WebResourceRequestedEventArgs_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2WebResourceRequestedEventArgs_get_Request(This,request) \ + ( (This)->lpVtbl -> get_Request(This,request) ) + +#define ICoreWebView2WebResourceRequestedEventArgs_get_Response(This,response) \ + ( (This)->lpVtbl -> get_Response(This,response) ) + +#define ICoreWebView2WebResourceRequestedEventArgs_put_Response(This,response) \ + ( (This)->lpVtbl -> put_Response(This,response) ) + +#define ICoreWebView2WebResourceRequestedEventArgs_GetDeferral(This,deferral) \ + ( (This)->lpVtbl -> GetDeferral(This,deferral) ) + +#define ICoreWebView2WebResourceRequestedEventArgs_get_ResourceContext(This,context) \ + ( (This)->lpVtbl -> get_ResourceContext(This,context) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2WebResourceRequestedEventArgs_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2WebResourceRequestedEventHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2WebResourceRequestedEventHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2WebResourceRequestedEventHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2WebResourceRequestedEventHandler = {0xab00b74c,0x15f1,0x4646,{0x80,0xe8,0xe7,0x63,0x41,0xd2,0x5d,0x71}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("ab00b74c-15f1-4646-80e8-e76341d25d71") + ICoreWebView2WebResourceRequestedEventHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + /* [in] */ ICoreWebView2 *sender, + /* [in] */ ICoreWebView2WebResourceRequestedEventArgs *args) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2WebResourceRequestedEventHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2WebResourceRequestedEventHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2WebResourceRequestedEventHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2WebResourceRequestedEventHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2WebResourceRequestedEventHandler * This, + /* [in] */ ICoreWebView2 *sender, + /* [in] */ ICoreWebView2WebResourceRequestedEventArgs *args); + + END_INTERFACE + } ICoreWebView2WebResourceRequestedEventHandlerVtbl; + + interface ICoreWebView2WebResourceRequestedEventHandler + { + CONST_VTBL struct ICoreWebView2WebResourceRequestedEventHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2WebResourceRequestedEventHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2WebResourceRequestedEventHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2WebResourceRequestedEventHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2WebResourceRequestedEventHandler_Invoke(This,sender,args) \ + ( (This)->lpVtbl -> Invoke(This,sender,args) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2WebResourceRequestedEventHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2WebResourceResponse_INTERFACE_DEFINED__ +#define __ICoreWebView2WebResourceResponse_INTERFACE_DEFINED__ + +/* interface ICoreWebView2WebResourceResponse */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2WebResourceResponse = {0xaafcc94f,0xfa27,0x48fd,{0x97,0xdf,0x83,0x0e,0xf7,0x5a,0xae,0xc9}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("aafcc94f-fa27-48fd-97df-830ef75aaec9") + ICoreWebView2WebResourceResponse : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Content( + /* [retval][out] */ IStream **content) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_Content( + /* [in] */ IStream *content) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Headers( + /* [retval][out] */ ICoreWebView2HttpResponseHeaders **headers) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_StatusCode( + /* [retval][out] */ int *statusCode) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_StatusCode( + /* [in] */ int statusCode) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_ReasonPhrase( + /* [retval][out] */ LPWSTR *reasonPhrase) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_ReasonPhrase( + /* [in] */ LPCWSTR reasonPhrase) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2WebResourceResponseVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2WebResourceResponse * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2WebResourceResponse * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2WebResourceResponse * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Content )( + ICoreWebView2WebResourceResponse * This, + /* [retval][out] */ IStream **content); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_Content )( + ICoreWebView2WebResourceResponse * This, + /* [in] */ IStream *content); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Headers )( + ICoreWebView2WebResourceResponse * This, + /* [retval][out] */ ICoreWebView2HttpResponseHeaders **headers); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_StatusCode )( + ICoreWebView2WebResourceResponse * This, + /* [retval][out] */ int *statusCode); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_StatusCode )( + ICoreWebView2WebResourceResponse * This, + /* [in] */ int statusCode); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_ReasonPhrase )( + ICoreWebView2WebResourceResponse * This, + /* [retval][out] */ LPWSTR *reasonPhrase); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_ReasonPhrase )( + ICoreWebView2WebResourceResponse * This, + /* [in] */ LPCWSTR reasonPhrase); + + END_INTERFACE + } ICoreWebView2WebResourceResponseVtbl; + + interface ICoreWebView2WebResourceResponse + { + CONST_VTBL struct ICoreWebView2WebResourceResponseVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2WebResourceResponse_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2WebResourceResponse_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2WebResourceResponse_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2WebResourceResponse_get_Content(This,content) \ + ( (This)->lpVtbl -> get_Content(This,content) ) + +#define ICoreWebView2WebResourceResponse_put_Content(This,content) \ + ( (This)->lpVtbl -> put_Content(This,content) ) + +#define ICoreWebView2WebResourceResponse_get_Headers(This,headers) \ + ( (This)->lpVtbl -> get_Headers(This,headers) ) + +#define ICoreWebView2WebResourceResponse_get_StatusCode(This,statusCode) \ + ( (This)->lpVtbl -> get_StatusCode(This,statusCode) ) + +#define ICoreWebView2WebResourceResponse_put_StatusCode(This,statusCode) \ + ( (This)->lpVtbl -> put_StatusCode(This,statusCode) ) + +#define ICoreWebView2WebResourceResponse_get_ReasonPhrase(This,reasonPhrase) \ + ( (This)->lpVtbl -> get_ReasonPhrase(This,reasonPhrase) ) + +#define ICoreWebView2WebResourceResponse_put_ReasonPhrase(This,reasonPhrase) \ + ( (This)->lpVtbl -> put_ReasonPhrase(This,reasonPhrase) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2WebResourceResponse_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2WebResourceResponseReceivedEventHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2WebResourceResponseReceivedEventHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2WebResourceResponseReceivedEventHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2WebResourceResponseReceivedEventHandler = {0x7DE9898A,0x24F5,0x40C3,{0xA2,0xDE,0xD4,0xF4,0x58,0xE6,0x98,0x28}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("7DE9898A-24F5-40C3-A2DE-D4F458E69828") + ICoreWebView2WebResourceResponseReceivedEventHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + /* [in] */ ICoreWebView2 *sender, + /* [in] */ ICoreWebView2WebResourceResponseReceivedEventArgs *args) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2WebResourceResponseReceivedEventHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2WebResourceResponseReceivedEventHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2WebResourceResponseReceivedEventHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2WebResourceResponseReceivedEventHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2WebResourceResponseReceivedEventHandler * This, + /* [in] */ ICoreWebView2 *sender, + /* [in] */ ICoreWebView2WebResourceResponseReceivedEventArgs *args); + + END_INTERFACE + } ICoreWebView2WebResourceResponseReceivedEventHandlerVtbl; + + interface ICoreWebView2WebResourceResponseReceivedEventHandler + { + CONST_VTBL struct ICoreWebView2WebResourceResponseReceivedEventHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2WebResourceResponseReceivedEventHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2WebResourceResponseReceivedEventHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2WebResourceResponseReceivedEventHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2WebResourceResponseReceivedEventHandler_Invoke(This,sender,args) \ + ( (This)->lpVtbl -> Invoke(This,sender,args) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2WebResourceResponseReceivedEventHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2WebResourceResponseReceivedEventArgs_INTERFACE_DEFINED__ +#define __ICoreWebView2WebResourceResponseReceivedEventArgs_INTERFACE_DEFINED__ + +/* interface ICoreWebView2WebResourceResponseReceivedEventArgs */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2WebResourceResponseReceivedEventArgs = {0xD1DB483D,0x6796,0x4B8B,{0x80,0xFC,0x13,0x71,0x2B,0xB7,0x16,0xF4}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("D1DB483D-6796-4B8B-80FC-13712BB716F4") + ICoreWebView2WebResourceResponseReceivedEventArgs : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Request( + /* [retval][out] */ ICoreWebView2WebResourceRequest **request) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Response( + /* [retval][out] */ ICoreWebView2WebResourceResponseView **response) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2WebResourceResponseReceivedEventArgsVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2WebResourceResponseReceivedEventArgs * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2WebResourceResponseReceivedEventArgs * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2WebResourceResponseReceivedEventArgs * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Request )( + ICoreWebView2WebResourceResponseReceivedEventArgs * This, + /* [retval][out] */ ICoreWebView2WebResourceRequest **request); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Response )( + ICoreWebView2WebResourceResponseReceivedEventArgs * This, + /* [retval][out] */ ICoreWebView2WebResourceResponseView **response); + + END_INTERFACE + } ICoreWebView2WebResourceResponseReceivedEventArgsVtbl; + + interface ICoreWebView2WebResourceResponseReceivedEventArgs + { + CONST_VTBL struct ICoreWebView2WebResourceResponseReceivedEventArgsVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2WebResourceResponseReceivedEventArgs_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2WebResourceResponseReceivedEventArgs_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2WebResourceResponseReceivedEventArgs_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2WebResourceResponseReceivedEventArgs_get_Request(This,request) \ + ( (This)->lpVtbl -> get_Request(This,request) ) + +#define ICoreWebView2WebResourceResponseReceivedEventArgs_get_Response(This,response) \ + ( (This)->lpVtbl -> get_Response(This,response) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2WebResourceResponseReceivedEventArgs_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2WebResourceResponseView_INTERFACE_DEFINED__ +#define __ICoreWebView2WebResourceResponseView_INTERFACE_DEFINED__ + +/* interface ICoreWebView2WebResourceResponseView */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2WebResourceResponseView = {0x79701053,0x7759,0x4162,{0x8F,0x7D,0xF1,0xB3,0xF0,0x84,0x92,0x8D}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("79701053-7759-4162-8F7D-F1B3F084928D") + ICoreWebView2WebResourceResponseView : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Headers( + /* [retval][out] */ ICoreWebView2HttpResponseHeaders **headers) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_StatusCode( + /* [retval][out] */ int *statusCode) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_ReasonPhrase( + /* [retval][out] */ LPWSTR *reasonPhrase) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetContent( + /* [in] */ ICoreWebView2WebResourceResponseViewGetContentCompletedHandler *handler) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2WebResourceResponseViewVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2WebResourceResponseView * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2WebResourceResponseView * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2WebResourceResponseView * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Headers )( + ICoreWebView2WebResourceResponseView * This, + /* [retval][out] */ ICoreWebView2HttpResponseHeaders **headers); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_StatusCode )( + ICoreWebView2WebResourceResponseView * This, + /* [retval][out] */ int *statusCode); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_ReasonPhrase )( + ICoreWebView2WebResourceResponseView * This, + /* [retval][out] */ LPWSTR *reasonPhrase); + + HRESULT ( STDMETHODCALLTYPE *GetContent )( + ICoreWebView2WebResourceResponseView * This, + /* [in] */ ICoreWebView2WebResourceResponseViewGetContentCompletedHandler *handler); + + END_INTERFACE + } ICoreWebView2WebResourceResponseViewVtbl; + + interface ICoreWebView2WebResourceResponseView + { + CONST_VTBL struct ICoreWebView2WebResourceResponseViewVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2WebResourceResponseView_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2WebResourceResponseView_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2WebResourceResponseView_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2WebResourceResponseView_get_Headers(This,headers) \ + ( (This)->lpVtbl -> get_Headers(This,headers) ) + +#define ICoreWebView2WebResourceResponseView_get_StatusCode(This,statusCode) \ + ( (This)->lpVtbl -> get_StatusCode(This,statusCode) ) + +#define ICoreWebView2WebResourceResponseView_get_ReasonPhrase(This,reasonPhrase) \ + ( (This)->lpVtbl -> get_ReasonPhrase(This,reasonPhrase) ) + +#define ICoreWebView2WebResourceResponseView_GetContent(This,handler) \ + ( (This)->lpVtbl -> GetContent(This,handler) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2WebResourceResponseView_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2WebResourceResponseViewGetContentCompletedHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2WebResourceResponseViewGetContentCompletedHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2WebResourceResponseViewGetContentCompletedHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2WebResourceResponseViewGetContentCompletedHandler = {0x875738E1,0x9FA2,0x40E3,{0x8B,0x74,0x2E,0x89,0x72,0xDD,0x6F,0xE7}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("875738E1-9FA2-40E3-8B74-2E8972DD6FE7") + ICoreWebView2WebResourceResponseViewGetContentCompletedHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + /* [in] */ HRESULT errorCode, + /* [in] */ IStream *content) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2WebResourceResponseViewGetContentCompletedHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2WebResourceResponseViewGetContentCompletedHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2WebResourceResponseViewGetContentCompletedHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2WebResourceResponseViewGetContentCompletedHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2WebResourceResponseViewGetContentCompletedHandler * This, + /* [in] */ HRESULT errorCode, + /* [in] */ IStream *content); + + END_INTERFACE + } ICoreWebView2WebResourceResponseViewGetContentCompletedHandlerVtbl; + + interface ICoreWebView2WebResourceResponseViewGetContentCompletedHandler + { + CONST_VTBL struct ICoreWebView2WebResourceResponseViewGetContentCompletedHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2WebResourceResponseViewGetContentCompletedHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2WebResourceResponseViewGetContentCompletedHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2WebResourceResponseViewGetContentCompletedHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2WebResourceResponseViewGetContentCompletedHandler_Invoke(This,errorCode,content) \ + ( (This)->lpVtbl -> Invoke(This,errorCode,content) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2WebResourceResponseViewGetContentCompletedHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2WindowCloseRequestedEventHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2WindowCloseRequestedEventHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2WindowCloseRequestedEventHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2WindowCloseRequestedEventHandler = {0x5c19e9e0,0x092f,0x486b,{0xaf,0xfa,0xca,0x82,0x31,0x91,0x30,0x39}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("5c19e9e0-092f-486b-affa-ca8231913039") + ICoreWebView2WindowCloseRequestedEventHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + /* [in] */ ICoreWebView2 *sender, + /* [in] */ IUnknown *args) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2WindowCloseRequestedEventHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2WindowCloseRequestedEventHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2WindowCloseRequestedEventHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2WindowCloseRequestedEventHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2WindowCloseRequestedEventHandler * This, + /* [in] */ ICoreWebView2 *sender, + /* [in] */ IUnknown *args); + + END_INTERFACE + } ICoreWebView2WindowCloseRequestedEventHandlerVtbl; + + interface ICoreWebView2WindowCloseRequestedEventHandler + { + CONST_VTBL struct ICoreWebView2WindowCloseRequestedEventHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2WindowCloseRequestedEventHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2WindowCloseRequestedEventHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2WindowCloseRequestedEventHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2WindowCloseRequestedEventHandler_Invoke(This,sender,args) \ + ( (This)->lpVtbl -> Invoke(This,sender,args) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2WindowCloseRequestedEventHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2WindowFeatures_INTERFACE_DEFINED__ +#define __ICoreWebView2WindowFeatures_INTERFACE_DEFINED__ + +/* interface ICoreWebView2WindowFeatures */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2WindowFeatures = {0x5eaf559f,0xb46e,0x4397,{0x88,0x60,0xe4,0x22,0xf2,0x87,0xff,0x1e}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("5eaf559f-b46e-4397-8860-e422f287ff1e") + ICoreWebView2WindowFeatures : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_HasPosition( + /* [retval][out] */ BOOL *value) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_HasSize( + /* [retval][out] */ BOOL *value) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Left( + /* [retval][out] */ UINT32 *value) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Top( + /* [retval][out] */ UINT32 *value) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Height( + /* [retval][out] */ UINT32 *value) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Width( + /* [retval][out] */ UINT32 *value) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_ShouldDisplayMenuBar( + /* [retval][out] */ BOOL *value) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_ShouldDisplayStatus( + /* [retval][out] */ BOOL *value) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_ShouldDisplayToolbar( + /* [retval][out] */ BOOL *value) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_ShouldDisplayScrollBars( + /* [retval][out] */ BOOL *value) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2WindowFeaturesVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2WindowFeatures * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2WindowFeatures * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2WindowFeatures * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_HasPosition )( + ICoreWebView2WindowFeatures * This, + /* [retval][out] */ BOOL *value); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_HasSize )( + ICoreWebView2WindowFeatures * This, + /* [retval][out] */ BOOL *value); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Left )( + ICoreWebView2WindowFeatures * This, + /* [retval][out] */ UINT32 *value); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Top )( + ICoreWebView2WindowFeatures * This, + /* [retval][out] */ UINT32 *value); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Height )( + ICoreWebView2WindowFeatures * This, + /* [retval][out] */ UINT32 *value); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Width )( + ICoreWebView2WindowFeatures * This, + /* [retval][out] */ UINT32 *value); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_ShouldDisplayMenuBar )( + ICoreWebView2WindowFeatures * This, + /* [retval][out] */ BOOL *value); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_ShouldDisplayStatus )( + ICoreWebView2WindowFeatures * This, + /* [retval][out] */ BOOL *value); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_ShouldDisplayToolbar )( + ICoreWebView2WindowFeatures * This, + /* [retval][out] */ BOOL *value); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_ShouldDisplayScrollBars )( + ICoreWebView2WindowFeatures * This, + /* [retval][out] */ BOOL *value); + + END_INTERFACE + } ICoreWebView2WindowFeaturesVtbl; + + interface ICoreWebView2WindowFeatures + { + CONST_VTBL struct ICoreWebView2WindowFeaturesVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2WindowFeatures_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2WindowFeatures_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2WindowFeatures_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2WindowFeatures_get_HasPosition(This,value) \ + ( (This)->lpVtbl -> get_HasPosition(This,value) ) + +#define ICoreWebView2WindowFeatures_get_HasSize(This,value) \ + ( (This)->lpVtbl -> get_HasSize(This,value) ) + +#define ICoreWebView2WindowFeatures_get_Left(This,value) \ + ( (This)->lpVtbl -> get_Left(This,value) ) + +#define ICoreWebView2WindowFeatures_get_Top(This,value) \ + ( (This)->lpVtbl -> get_Top(This,value) ) + +#define ICoreWebView2WindowFeatures_get_Height(This,value) \ + ( (This)->lpVtbl -> get_Height(This,value) ) + +#define ICoreWebView2WindowFeatures_get_Width(This,value) \ + ( (This)->lpVtbl -> get_Width(This,value) ) + +#define ICoreWebView2WindowFeatures_get_ShouldDisplayMenuBar(This,value) \ + ( (This)->lpVtbl -> get_ShouldDisplayMenuBar(This,value) ) + +#define ICoreWebView2WindowFeatures_get_ShouldDisplayStatus(This,value) \ + ( (This)->lpVtbl -> get_ShouldDisplayStatus(This,value) ) + +#define ICoreWebView2WindowFeatures_get_ShouldDisplayToolbar(This,value) \ + ( (This)->lpVtbl -> get_ShouldDisplayToolbar(This,value) ) + +#define ICoreWebView2WindowFeatures_get_ShouldDisplayScrollBars(This,value) \ + ( (This)->lpVtbl -> get_ShouldDisplayScrollBars(This,value) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2WindowFeatures_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2ZoomFactorChangedEventHandler_INTERFACE_DEFINED__ +#define __ICoreWebView2ZoomFactorChangedEventHandler_INTERFACE_DEFINED__ + +/* interface ICoreWebView2ZoomFactorChangedEventHandler */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2ZoomFactorChangedEventHandler = {0xb52d71d6,0xc4df,0x4543,{0xa9,0x0c,0x64,0xa3,0xe6,0x0f,0x38,0xcb}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("b52d71d6-c4df-4543-a90c-64a3e60f38cb") + ICoreWebView2ZoomFactorChangedEventHandler : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Invoke( + /* [in] */ ICoreWebView2Controller *sender, + /* [in] */ IUnknown *args) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2ZoomFactorChangedEventHandlerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2ZoomFactorChangedEventHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2ZoomFactorChangedEventHandler * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2ZoomFactorChangedEventHandler * This); + + HRESULT ( STDMETHODCALLTYPE *Invoke )( + ICoreWebView2ZoomFactorChangedEventHandler * This, + /* [in] */ ICoreWebView2Controller *sender, + /* [in] */ IUnknown *args); + + END_INTERFACE + } ICoreWebView2ZoomFactorChangedEventHandlerVtbl; + + interface ICoreWebView2ZoomFactorChangedEventHandler + { + CONST_VTBL struct ICoreWebView2ZoomFactorChangedEventHandlerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2ZoomFactorChangedEventHandler_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2ZoomFactorChangedEventHandler_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2ZoomFactorChangedEventHandler_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2ZoomFactorChangedEventHandler_Invoke(This,sender,args) \ + ( (This)->lpVtbl -> Invoke(This,sender,args) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2ZoomFactorChangedEventHandler_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2CompositionControllerInterop_INTERFACE_DEFINED__ +#define __ICoreWebView2CompositionControllerInterop_INTERFACE_DEFINED__ + +/* interface ICoreWebView2CompositionControllerInterop */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2CompositionControllerInterop = {0x8e9922ce,0x9c80,0x42e6,{0xba,0xd7,0xfc,0xeb,0xf2,0x91,0xa4,0x95}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("8e9922ce-9c80-42e6-bad7-fcebf291a495") + ICoreWebView2CompositionControllerInterop : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_UIAProvider( + /* [retval][out] */ IUnknown **provider) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_RootVisualTarget( + /* [retval][out] */ IUnknown **target) = 0; + + virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_RootVisualTarget( + /* [in] */ IUnknown *target) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2CompositionControllerInteropVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2CompositionControllerInterop * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2CompositionControllerInterop * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2CompositionControllerInterop * This); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_UIAProvider )( + ICoreWebView2CompositionControllerInterop * This, + /* [retval][out] */ IUnknown **provider); + + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_RootVisualTarget )( + ICoreWebView2CompositionControllerInterop * This, + /* [retval][out] */ IUnknown **target); + + /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_RootVisualTarget )( + ICoreWebView2CompositionControllerInterop * This, + /* [in] */ IUnknown *target); + + END_INTERFACE + } ICoreWebView2CompositionControllerInteropVtbl; + + interface ICoreWebView2CompositionControllerInterop + { + CONST_VTBL struct ICoreWebView2CompositionControllerInteropVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2CompositionControllerInterop_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2CompositionControllerInterop_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2CompositionControllerInterop_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2CompositionControllerInterop_get_UIAProvider(This,provider) \ + ( (This)->lpVtbl -> get_UIAProvider(This,provider) ) + +#define ICoreWebView2CompositionControllerInterop_get_RootVisualTarget(This,target) \ + ( (This)->lpVtbl -> get_RootVisualTarget(This,target) ) + +#define ICoreWebView2CompositionControllerInterop_put_RootVisualTarget(This,target) \ + ( (This)->lpVtbl -> put_RootVisualTarget(This,target) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2CompositionControllerInterop_INTERFACE_DEFINED__ */ + + +#ifndef __ICoreWebView2EnvironmentInterop_INTERFACE_DEFINED__ +#define __ICoreWebView2EnvironmentInterop_INTERFACE_DEFINED__ + +/* interface ICoreWebView2EnvironmentInterop */ +/* [unique][object][uuid] */ + + +EXTERN_C __declspec(selectany) const IID IID_ICoreWebView2EnvironmentInterop = {0xee503a63,0xc1e2,0x4fbf,{0x8a,0x4d,0x82,0x4e,0x95,0xf8,0xbb,0x13}}; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("ee503a63-c1e2-4fbf-8a4d-824e95f8bb13") + ICoreWebView2EnvironmentInterop : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetProviderForHwnd( + /* [in] */ HWND hwnd, + /* [retval][out] */ IUnknown **provider) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICoreWebView2EnvironmentInteropVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICoreWebView2EnvironmentInterop * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICoreWebView2EnvironmentInterop * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICoreWebView2EnvironmentInterop * This); + + HRESULT ( STDMETHODCALLTYPE *GetProviderForHwnd )( + ICoreWebView2EnvironmentInterop * This, + /* [in] */ HWND hwnd, + /* [retval][out] */ IUnknown **provider); + + END_INTERFACE + } ICoreWebView2EnvironmentInteropVtbl; + + interface ICoreWebView2EnvironmentInterop + { + CONST_VTBL struct ICoreWebView2EnvironmentInteropVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICoreWebView2EnvironmentInterop_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICoreWebView2EnvironmentInterop_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICoreWebView2EnvironmentInterop_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICoreWebView2EnvironmentInterop_GetProviderForHwnd(This,hwnd,provider) \ + ( (This)->lpVtbl -> GetProviderForHwnd(This,hwnd,provider) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICoreWebView2EnvironmentInterop_INTERFACE_DEFINED__ */ + +#endif /* __WebView2_LIBRARY_DEFINED__ */ + +/* Additional Prototypes for ALL interfaces */ + +/* end of Additional Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/v2/internal/ffenestri/windows/WebView2EnvironmentOptions.h b/v2/internal/ffenestri/windows/WebView2EnvironmentOptions.h new file mode 100644 index 000000000..6475ce58a --- /dev/null +++ b/v2/internal/ffenestri/windows/WebView2EnvironmentOptions.h @@ -0,0 +1,144 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef __core_webview2_environment_options_h__ +#define __core_webview2_environment_options_h__ + +#include +#include + +#include "webview2.h" +#define CORE_WEBVIEW_TARGET_PRODUCT_VERSION L"91.0.864.35" + +#define COREWEBVIEW2ENVIRONMENTOPTIONS_STRING_PROPERTY(p) \ + public: \ + HRESULT STDMETHODCALLTYPE get_##p(LPWSTR* value) override { \ + if (!value) \ + return E_POINTER; \ + *value = m_##p.Copy(); \ + if ((*value == nullptr) && (m_##p.Get() != nullptr)) \ + return HRESULT_FROM_WIN32(GetLastError()); \ + return S_OK; \ + } \ + HRESULT STDMETHODCALLTYPE put_##p(LPCWSTR value) override { \ + LPCWSTR result = m_##p.Set(value); \ + if ((result == nullptr) && (value != nullptr)) \ + return HRESULT_FROM_WIN32(GetLastError()); \ + return S_OK; \ + } \ + \ + protected: \ + AutoCoMemString m_##p; + +#define COREWEBVIEW2ENVIRONMENTOPTIONS_BOOL_PROPERTY(p) \ + public: \ + HRESULT STDMETHODCALLTYPE get_##p(BOOL* value) override { \ + if (!value) \ + return E_POINTER; \ + *value = m_##p; \ + return S_OK; \ + } \ + HRESULT STDMETHODCALLTYPE put_##p(BOOL value) override { \ + m_##p = value; \ + return S_OK; \ + } \ + \ + protected: \ + BOOL m_##p = FALSE; + +// This is a base COM class that implements ICoreWebView2EnvironmentOptions. +template +class CoreWebView2EnvironmentOptionsBase + : public Microsoft::WRL::Implements< + Microsoft::WRL::RuntimeClassFlags, + ICoreWebView2EnvironmentOptions> { + public: + CoreWebView2EnvironmentOptionsBase() { + // Initialize the target compatible browser version value to the version of + // the browser binaries corresponding to this version of the SDK. + m_TargetCompatibleBrowserVersion.Set(CORE_WEBVIEW_TARGET_PRODUCT_VERSION); + } + + protected: + ~CoreWebView2EnvironmentOptionsBase(){}; + + class AutoCoMemString { + public: + AutoCoMemString() {} + ~AutoCoMemString() { Release(); } + void Release() { + if (m_string) { + deallocate_fn(m_string); + m_string = nullptr; + } + } + + LPCWSTR Set(LPCWSTR str) { + Release(); + if (str) { + m_string = MakeCoMemString(str); + } + return m_string; + } + LPCWSTR Get() { return m_string; } + LPWSTR Copy() { + if (m_string) + return MakeCoMemString(m_string); + return nullptr; + } + + protected: + LPWSTR MakeCoMemString(LPCWSTR source) { + const size_t length = wcslen(source); + const size_t bytes = (length + 1) * sizeof(*source); + // Ensure we didn't overflow during our size calculation. + if (bytes <= length) { + return nullptr; + } + + wchar_t* result = reinterpret_cast(allocate_fn(bytes)); + if (result) + memcpy(result, source, bytes); + + return result; + } + + LPWSTR m_string = nullptr; + }; + + COREWEBVIEW2ENVIRONMENTOPTIONS_STRING_PROPERTY(AdditionalBrowserArguments) + COREWEBVIEW2ENVIRONMENTOPTIONS_STRING_PROPERTY(Language) + COREWEBVIEW2ENVIRONMENTOPTIONS_STRING_PROPERTY(TargetCompatibleBrowserVersion) + COREWEBVIEW2ENVIRONMENTOPTIONS_BOOL_PROPERTY( + AllowSingleSignOnUsingOSPrimaryAccount) +}; + +template +class CoreWebView2EnvironmentOptionsBaseClass + : public Microsoft::WRL::RuntimeClass< + Microsoft::WRL::RuntimeClassFlags, + CoreWebView2EnvironmentOptionsBase> { + public: + CoreWebView2EnvironmentOptionsBaseClass() {} + + protected: + ~CoreWebView2EnvironmentOptionsBaseClass() override{}; +}; + +typedef CoreWebView2EnvironmentOptionsBaseClass + CoreWebView2EnvironmentOptions; + +#endif // __core_webview2_environment_options_h__ diff --git a/v2/internal/ffenestri/windows/scripts/README.md b/v2/internal/ffenestri/windows/scripts/README.md new file mode 100644 index 000000000..634e3596b --- /dev/null +++ b/v2/internal/ffenestri/windows/scripts/README.md @@ -0,0 +1,11 @@ +# Build + +This script will download the given webview2 sdk version and copy out the files necessary for building Wails apps. + +## Prerequistes + + - nuget + +## Usage + +`updatesdk.bat ` diff --git a/v2/internal/ffenestri/windows/scripts/sdkversion.txt b/v2/internal/ffenestri/windows/scripts/sdkversion.txt new file mode 100644 index 000000000..e4c251ea5 --- /dev/null +++ b/v2/internal/ffenestri/windows/scripts/sdkversion.txt @@ -0,0 +1 @@ +The version of WebView2 SDK used: 1.0.992.28 diff --git a/v2/internal/ffenestri/windows/scripts/updatesdk.bat b/v2/internal/ffenestri/windows/scripts/updatesdk.bat new file mode 100644 index 000000000..780c09128 --- /dev/null +++ b/v2/internal/ffenestri/windows/scripts/updatesdk.bat @@ -0,0 +1,18 @@ +@echo off +IF %1.==. GOTO NoVersion +nuget install microsoft.web.webview2 -Version %1 -OutputDirectory . >NUL || goto :eof +echo Downloaded microsoft.web.webview2.%1 + +set sdk_version=%1 +set native_dir="%~dp0\microsoft.web.webview2.%sdk_version%\build\native" +copy "%native_dir%\include\*.h" .. >NUL +copy "%native_dir%\x64\WebView2Loader.dll" "..\x64" >NUL +@REM @rd /S /Q "microsoft.web.webview2.%sdk_version%" +del /s version.txt >nul 2>&1 +echo The version of WebView2 SDK used: %sdk_version% > sdkversion.txt +echo SDK updated to %sdk_version% +goto :eof + +:NoVersion + echo Please provide a version number, EG: 1.0.664.37 + goto :eof diff --git a/v2/internal/ffenestri/windows/wv2runtime/browser.go b/v2/internal/ffenestri/windows/wv2runtime/browser.go new file mode 100644 index 000000000..25f19f2e0 --- /dev/null +++ b/v2/internal/ffenestri/windows/wv2runtime/browser.go @@ -0,0 +1,23 @@ +// +build wv2runtime.browser + +package wv2runtime + +import ( + "fmt" + "github.com/leaanthony/webview2runtime" +) + +func doInstallationStrategy(installStatus installationStatus) error { + confirmed, err := webview2runtime.Confirm("This application requires the WebView2 runtime. Press OK to open the download page. Minimum version required: "+MinimumRuntimeVersion, "Missing Requirements") + if err != nil { + return err + } + if confirmed { + err = webview2runtime.OpenInstallerDownloadWebpage() + if err != nil { + return err + } + } + + return fmt.Errorf("webview2 runtime not installed") +} diff --git a/v2/internal/ffenestri/windows/wv2runtime/download.go b/v2/internal/ffenestri/windows/wv2runtime/download.go new file mode 100644 index 000000000..cfb2aa197 --- /dev/null +++ b/v2/internal/ffenestri/windows/wv2runtime/download.go @@ -0,0 +1,35 @@ +// +build !wv2runtime.error +// +build !wv2runtime.browser +// +build !wv2runtime.embed + +package wv2runtime + +import ( + "fmt" + "github.com/leaanthony/webview2runtime" +) + +func doInstallationStrategy(installStatus installationStatus) error { + message := "The WebView2 runtime is required. " + if installStatus == needsUpdating { + message = "The Webview2 runtime needs updating. " + } + message += "Press Ok to download and install. Note: The installer will download silently so please wait." + confirmed, err := webview2runtime.Confirm(message, "Missing Requirements") + if err != nil { + return err + } + if !confirmed { + return fmt.Errorf("webview2 runtime not installed") + } + installedCorrectly, err := webview2runtime.InstallUsingBootstrapper() + if err != nil { + _ = webview2runtime.Error(err.Error(), "Error") + return err + } + if !installedCorrectly { + err = webview2runtime.Error("The runtime failed to install correctly. Please try again.", "Error") + return err + } + return nil +} diff --git a/v2/internal/ffenestri/windows/wv2runtime/embed.go b/v2/internal/ffenestri/windows/wv2runtime/embed.go new file mode 100644 index 000000000..99a472d48 --- /dev/null +++ b/v2/internal/ffenestri/windows/wv2runtime/embed.go @@ -0,0 +1,33 @@ +// +build wv2runtime.embed + +package wv2runtime + +import ( + "fmt" + "github.com/leaanthony/webview2runtime" +) + +func doInstallationStrategy(installStatus installationStatus) error { + message := "The WebView2 runtime is required. " + if installStatus == needsUpdating { + message = "The Webview2 runtime needs updating. " + } + message += "Press Ok to install." + confirmed, err := webview2runtime.Confirm(message, "Missing Requirements") + if err != nil { + return err + } + if !confirmed { + return fmt.Errorf("webview2 runtime not installed") + } + installedCorrectly, err := webview2runtime.InstallUsingEmbeddedBootstrapper() + if err != nil { + _ = webview2runtime.Error(err.Error(), "Error") + return err + } + if !installedCorrectly { + err = webview2runtime.Error("The runtime failed to install correctly. Please try again.", "Error") + return err + } + return nil +} diff --git a/v2/internal/ffenestri/windows/wv2runtime/error.go b/v2/internal/ffenestri/windows/wv2runtime/error.go new file mode 100644 index 000000000..f03d8c81c --- /dev/null +++ b/v2/internal/ffenestri/windows/wv2runtime/error.go @@ -0,0 +1,13 @@ +// +build wv2runtime.error + +package wv2runtime + +import ( + "fmt" + "github.com/leaanthony/webview2runtime" +) + +func doInstallationStrategy(installStatus installationStatus) error { + _ = webview2runtime.Error("The WebView2 runtime is required to run this application. Please contact your system administrator.", "Error") + return fmt.Errorf("webview2 runtime not installed") +} diff --git a/v2/internal/ffenestri/windows/wv2runtime/wv2runtime.go b/v2/internal/ffenestri/windows/wv2runtime/wv2runtime.go new file mode 100644 index 000000000..7326d54b1 --- /dev/null +++ b/v2/internal/ffenestri/windows/wv2runtime/wv2runtime.go @@ -0,0 +1,35 @@ +package wv2runtime + +import ( + "github.com/leaanthony/go-webview2/webviewloader" + "github.com/leaanthony/webview2runtime" +) + +const MinimumRuntimeVersion string = "91.0.992.28" + +type installationStatus int + +const ( + needsInstalling installationStatus = iota + needsUpdating + installed +) + +func Process() (*webview2runtime.Info, error) { + installStatus := needsInstalling + installedVersion := webview2runtime.GetInstalledVersion() + if installedVersion != nil { + installStatus = installed + compareResult, err := webviewloader.CompareBrowserVersions(installedVersion.Version, MinimumRuntimeVersion) + if err != nil { + return nil, err + } + updateRequired := compareResult == -1 + // Installed and does not require updating + if !updateRequired { + return installedVersion, nil + } + + } + return installedVersion, doInstallationStrategy(installStatus) +} diff --git a/v2/internal/ffenestri/windows/x64/WebView2Loader.dll b/v2/internal/ffenestri/windows/x64/WebView2Loader.dll new file mode 100644 index 000000000..869459eca Binary files /dev/null and b/v2/internal/ffenestri/windows/x64/WebView2Loader.dll differ diff --git a/v2/internal/ffenestri/windows/x64/x64.go b/v2/internal/ffenestri/windows/x64/x64.go new file mode 100644 index 000000000..8e4e2f31b --- /dev/null +++ b/v2/internal/ffenestri/windows/x64/x64.go @@ -0,0 +1,8 @@ +// +build windows + +package x64 + +import _ "embed" + +//go:embed WebView2Loader.dll +var WebView2Loader []byte diff --git a/v2/internal/ffenestri/windows_checkboxes.go b/v2/internal/ffenestri/windows_checkboxes.go new file mode 100644 index 000000000..e76dfa8ca --- /dev/null +++ b/v2/internal/ffenestri/windows_checkboxes.go @@ -0,0 +1,93 @@ +//+build windows + +package ffenestri + +import ( + "fmt" + "github.com/leaanthony/slicer" + "github.com/wailsapp/wails/v2/internal/menumanager" + "os" + "sync" + "text/tabwriter" +) + +/* --------------------------------------------------------------------------------- + +Checkbox Cache +-------------- +The checkbox cache keeps a list of IDs that are associated with the same checkbox menu item. +This can happen when a checkbox is used in an application menu and a tray menu, eg "start at login". +The cache is used to bulk toggle the menu items when one is clicked. + +*/ + +type CheckboxCache struct { + cache map[*menumanager.ProcessedMenu]map[wailsMenuItemID][]win32MenuItemID + mutex sync.RWMutex +} + +func NewCheckboxCache() *CheckboxCache { + return &CheckboxCache{ + cache: make(map[*menumanager.ProcessedMenu]map[wailsMenuItemID][]win32MenuItemID), + } +} + +func (c *CheckboxCache) Dump() { + // Start a new tabwriter + w := new(tabwriter.Writer) + w.Init(os.Stdout, 8, 8, 0, '\t', 0) + + println("---------------- Checkbox", c, "Dump ----------------") + for _, processedMenu := range c.cache { + println("Menu", processedMenu) + for wailsMenuItemID, win32menus := range processedMenu { + println(" WailsMenu: ", wailsMenuItemID) + menus := slicer.String() + for _, win32menu := range win32menus { + menus.Add(fmt.Sprintf("%v", win32menu)) + } + _, _ = fmt.Fprintf(w, "%s\t%s\n", wailsMenuItemID, menus.Join(", ")) + _ = w.Flush() + } + } +} + +func (c *CheckboxCache) addToCheckboxCache(menu *menumanager.ProcessedMenu, item wailsMenuItemID, menuID win32MenuItemID) { + + // Get map for menu + if c.cache[menu] == nil { + c.cache[menu] = make(map[wailsMenuItemID][]win32MenuItemID) + } + menuMap := c.cache[menu] + + // Ensure we have a slice + if menuMap[item] == nil { + menuMap[item] = []win32MenuItemID{} + } + + c.mutex.Lock() + menuMap[item] = append(menuMap[item], menuID) + c.mutex.Unlock() + +} + +func (c *CheckboxCache) removeMenuFromCheckboxCache(menu *menumanager.ProcessedMenu) { + c.mutex.Lock() + delete(c.cache, menu) + c.mutex.Unlock() +} + +// win32MenuIDsForWailsMenuID returns all win32menuids that are used for a wails menu item id across +// all menus +func (c *CheckboxCache) win32MenuIDsForWailsMenuID(item wailsMenuItemID) []win32MenuItemID { + c.mutex.Lock() + result := []win32MenuItemID{} + for _, menu := range c.cache { + ids := menu[item] + if ids != nil { + result = append(result, ids...) + } + } + c.mutex.Unlock() + return result +} diff --git a/v2/internal/ffenestri/windows_errorhandler_debug.go b/v2/internal/ffenestri/windows_errorhandler_debug.go new file mode 100644 index 000000000..5de8758b6 --- /dev/null +++ b/v2/internal/ffenestri/windows_errorhandler_debug.go @@ -0,0 +1,28 @@ +//+build windows,debug + +package ffenestri + +import ( + "fmt" + "github.com/ztrue/tracerr" + "runtime" + "strings" +) + +func wall(err error, inputs ...interface{}) error { + if err == nil { + return nil + } + pc, _, _, _ := runtime.Caller(1) + funcName := runtime.FuncForPC(pc).Name() + splitName := strings.Split(funcName, ".") + message := "[" + splitName[len(splitName)-1] + "]" + if len(inputs) > 0 { + params := []string{} + for _, param := range inputs { + params = append(params, fmt.Sprintf("%v", param)) + } + message += "(" + strings.Join(params, " ") + ")" + } + return tracerr.Errorf(message) +} diff --git a/v2/internal/ffenestri/windows_errorhandler_production.go b/v2/internal/ffenestri/windows_errorhandler_production.go new file mode 100644 index 000000000..20c9dc9d8 --- /dev/null +++ b/v2/internal/ffenestri/windows_errorhandler_production.go @@ -0,0 +1,47 @@ +// +build windows,!debug + +package ffenestri + +import "C" +import ( + "fmt" + "golang.org/x/sys/windows" + "log" + "os" + "runtime" + "strings" + "syscall" +) + +func wall(err error, inputs ...interface{}) error { + if err == nil { + return nil + } + pc, _, _, _ := runtime.Caller(1) + funcName := runtime.FuncForPC(pc).Name() + splitName := strings.Split(funcName, ".") + message := "[" + splitName[len(splitName)-1] + "]" + if len(inputs) > 0 { + params := []string{} + for _, param := range inputs { + params = append(params, fmt.Sprintf("%v", param)) + } + message += "(" + strings.Join(params, " ") + ")" + } + + title, err := syscall.UTF16PtrFromString("Fatal Error") + if err != nil { + log.Fatal(err) + } + + text, err := syscall.UTF16PtrFromString("There has been a fatal error. Details:\n" + message) + if err != nil { + log.Fatal(err) + } + + var flags uint32 = windows.MB_ICONERROR | windows.MB_OK + + _, err = windows.MessageBox(0, text, title, flags|windows.MB_SYSTEMMODAL) + os.Exit(1) + return err +} diff --git a/v2/internal/ffenestri/windows_menu.go b/v2/internal/ffenestri/windows_menu.go new file mode 100644 index 000000000..384ffb7fe --- /dev/null +++ b/v2/internal/ffenestri/windows_menu.go @@ -0,0 +1,232 @@ +//+build windows + +package ffenestri + +import ( + "fmt" + "github.com/wailsapp/wails/v2/internal/menumanager" + "github.com/wailsapp/wails/v2/pkg/menu" + "github.com/wailsapp/wails/v2/pkg/menu/keys" + "runtime" + "strings" +) + +//-------------------- Types ------------------------ + +type win32MenuItemID uint32 +type win32Menu uintptr +type win32Window uintptr +type wailsMenuItemID string // The internal menu ID + +type Menu struct { + wailsMenu *menumanager.WailsMenu + menu win32Menu + menuType menuType + + // A list of all checkbox and radio menuitems we + // create for this menu + checkboxes []win32MenuItemID + radioboxes []win32MenuItemID + initiallySelectedRadioItems []win32MenuItemID +} + +func createMenu(wailsMenu *menumanager.WailsMenu, menuType menuType) (*Menu, error) { + + mainMenu, err := createWin32Menu() + if err != nil { + return nil, err + } + + result := &Menu{ + wailsMenu: wailsMenu, + menu: mainMenu, + menuType: menuType, + } + + // Process top level menus + for _, toplevelmenu := range applicationMenu.Menu.Items { + err := result.processMenuItem(result.menu, toplevelmenu) + if err != nil { + return nil, err + } + } + + err = result.processRadioGroups() + if err != nil { + return nil, err + } + + return result, nil +} + +func (m *Menu) processMenuItem(parent win32Menu, menuItem *menumanager.ProcessedMenuItem) error { + + // Ignore hidden items + if menuItem.Hidden { + return nil + } + + // Calculate the flags for this menu item + flags := uintptr(calculateFlags(menuItem)) + + switch menuItem.Type { + case menu.SubmenuType: + submenu, err := createWin32PopupMenu() + if err != nil { + return err + } + for _, submenuItem := range menuItem.SubMenu.Items { + err = m.processMenuItem(submenu, submenuItem) + if err != nil { + return err + } + } + err = appendWin32MenuItem(parent, flags, uintptr(submenu), menuItem.Label) + if err != nil { + return err + } + case menu.TextType, menu.CheckboxType, menu.RadioType: + win32ID := addMenuCacheEntry(parent, m.menuType, menuItem, m.wailsMenu.Menu) + if menuItem.Accelerator != nil { + m.processAccelerator(menuItem) + } + label := menuItem.Label + //label := fmt.Sprintf("%s (%d)", menuItem.Label, win32ID) + err := appendWin32MenuItem(parent, flags, uintptr(win32ID), label) + if err != nil { + return err + } + if menuItem.Type == menu.CheckboxType { + // We need to maintain a list of this menu's checkboxes + m.checkboxes = append(m.checkboxes, win32ID) + globalCheckboxCache.addToCheckboxCache(m.wailsMenu.Menu, wailsMenuItemID(menuItem.ID), win32ID) + } + if menuItem.Type == menu.RadioType { + // We need to maintain a list of this menu's radioitems + m.radioboxes = append(m.radioboxes, win32ID) + globalRadioGroupMap.addRadioGroupMapping(m.wailsMenu.Menu, wailsMenuItemID(menuItem.ID), win32ID) + if menuItem.Checked { + m.initiallySelectedRadioItems = append(m.initiallySelectedRadioItems, win32ID) + } + } + case menu.SeparatorType: + err := appendWin32MenuItem(parent, flags, 0, "") + if err != nil { + return err + } + } + return nil +} + +func (m *Menu) processRadioGroups() error { + + for _, rg := range applicationMenu.RadioGroups { + startWailsMenuID := wailsMenuItemID(rg.Members[0]) + endWailsMenuID := wailsMenuItemID(rg.Members[len(rg.Members)-1]) + + startIDs := globalRadioGroupMap.getRadioGroupMapping(startWailsMenuID) + endIDs := globalRadioGroupMap.getRadioGroupMapping(endWailsMenuID) + + var radioGroupMaps = []*radioGroupStartEnd{} + for index := range startIDs { + startID := startIDs[index] + endID := endIDs[index] + thisRadioGroup := &radioGroupStartEnd{ + startID: startID, + endID: endID, + } + radioGroupMaps = append(radioGroupMaps, thisRadioGroup) + } + + // Set this for each member + for _, member := range rg.Members { + id := wailsMenuItemID(member) + globalRadioGroupCache.addToRadioGroupCache(m.wailsMenu.Menu, id, radioGroupMaps) + } + } + + // Enable all initially checked radio items + for _, win32MenuID := range m.initiallySelectedRadioItems { + menuItemDetails := getMenuCacheEntry(win32MenuID) + wailsMenuID := wailsMenuItemID(menuItemDetails.item.ID) + err := selectRadioItemFromWailsMenuID(wailsMenuID, win32MenuID) + if err != nil { + return err + } + } + + return nil +} + +func (m *Menu) Destroy() error { + + // Release the MenuIDs + releaseMenuIDsForProcessedMenu(m.wailsMenu.Menu) + + // Unload this menu's checkboxes from the cache + globalCheckboxCache.removeMenuFromCheckboxCache(m.wailsMenu.Menu) + + // Unload this menu's radio groups from the cache + globalRadioGroupCache.removeMenuFromRadioBoxCache(m.wailsMenu.Menu) + + globalRadioGroupMap.removeMenuFromRadioGroupMapping(m.wailsMenu.Menu) + + // Free up callbacks + resetCallbacks() + + // Delete menu + return destroyWin32Menu(m.menu) +} + +func (m *Menu) processAccelerator(menuitem *menumanager.ProcessedMenuItem) { + + // Add in shortcut to label if there is no "\t" override + if !strings.Contains(menuitem.Label, "\t") { + menuitem.Label += "\t" + keys.Stringify(menuitem.Accelerator, runtime.GOOS) + } + + // Calculate the modifier + var modifiers uint8 + for _, mod := range menuitem.Accelerator.Modifiers { + switch mod { + case keys.ControlKey, keys.CmdOrCtrlKey: + modifiers |= 1 + case keys.OptionOrAltKey: + modifiers |= 2 + case keys.ShiftKey: + modifiers |= 4 + //case keys.SuperKey: + // modifiers |= 8 + } + } + + var keycode = calculateKeycode(strings.ToLower(menuitem.Accelerator.Key)) + if keycode == 0 { + fmt.Printf("WARNING: Key '%s' is unsupported in windows. Cannot bind callback.", menuitem.Accelerator.Key) + return + } + addMenuCallback(keycode, modifiers, menuitem.ID, m.menuType) + +} + +var flagMap = map[menu.Type]uint32{ + menu.TextType: MF_STRING, + menu.SeparatorType: MF_SEPARATOR, + menu.SubmenuType: MF_STRING | MF_POPUP, + menu.CheckboxType: MF_STRING, + menu.RadioType: MF_STRING, +} + +func calculateFlags(menuItem *menumanager.ProcessedMenuItem) uint32 { + result := flagMap[menuItem.Type] + + if menuItem.Disabled { + result |= MF_DISABLED + } + + if menuItem.Type == menu.CheckboxType && menuItem.Checked { + result |= MF_CHECKED + } + + return result +} diff --git a/v2/internal/ffenestri/windows_menu_cache.go b/v2/internal/ffenestri/windows_menu_cache.go new file mode 100644 index 000000000..5b6762d9b --- /dev/null +++ b/v2/internal/ffenestri/windows_menu_cache.go @@ -0,0 +1,74 @@ +//+build windows + +package ffenestri + +import ( + "github.com/leaanthony/idgen" + "github.com/wailsapp/wails/v2/internal/menumanager" + "sync" +) + +/** + +MenuCache +--------- +When windows calls back to Go (when an item is clicked), we need to +be able to retrieve information about the menu item: + - The menu that the menuitem is part of (parent) + - The original processed menu item + - The type of the menu (application, context or tray) + +This cache is built up when a menu is created. + +*/ + +// TODO: Make this like the other caches + +type menuCacheEntry struct { + parent win32Menu + menuType menuType + item *menumanager.ProcessedMenuItem + processedMenu *menumanager.ProcessedMenu +} + +var idGenerator = idgen.New() + +var menuCache = map[win32MenuItemID]*menuCacheEntry{} +var menuCacheLock sync.RWMutex +var wailsMenuIDtoWin32IDMap = map[wailsMenuItemID]win32MenuItemID{} + +// This releases the menuIDs back to the id generator +var winIDsOwnedByProcessedMenu = map[*menumanager.ProcessedMenu][]win32MenuItemID{} + +func releaseMenuIDsForProcessedMenu(processedMenu *menumanager.ProcessedMenu) { + for _, menuID := range winIDsOwnedByProcessedMenu[processedMenu] { + idGenerator.ReleaseID(uint(menuID)) + } + delete(winIDsOwnedByProcessedMenu, processedMenu) +} + +func addMenuCacheEntry(parent win32Menu, typ menuType, wailsMenuItem *menumanager.ProcessedMenuItem, processedMenu *menumanager.ProcessedMenu) win32MenuItemID { + menuCacheLock.Lock() + defer menuCacheLock.Unlock() + id, err := idGenerator.NewID() + checkFatal(err) + menuID := win32MenuItemID(id) + menuCache[menuID] = &menuCacheEntry{ + parent: parent, + menuType: typ, + item: wailsMenuItem, + processedMenu: processedMenu, + } + // save the mapping + wailsMenuIDtoWin32IDMap[wailsMenuItemID(wailsMenuItem.ID)] = menuID + // keep track of menuids owned by this menu (so we can release the ids) + winIDsOwnedByProcessedMenu[processedMenu] = append(winIDsOwnedByProcessedMenu[processedMenu], menuID) + return menuID + +} + +func getMenuCacheEntry(id win32MenuItemID) *menuCacheEntry { + menuCacheLock.Lock() + defer menuCacheLock.Unlock() + return menuCache[id] +} diff --git a/v2/internal/ffenestri/windows_menu_callbacks.go b/v2/internal/ffenestri/windows_menu_callbacks.go new file mode 100644 index 000000000..9bfae895b --- /dev/null +++ b/v2/internal/ffenestri/windows_menu_callbacks.go @@ -0,0 +1,126 @@ +package ffenestri + +type callbackData struct { + menuID string + menuType menuType +} + +var callbacks = map[uint16]map[uint8]callbackData{} + +func addMenuCallback(key uint16, modifiers uint8, menuID string, menutype menuType) { + + if callbacks[key] == nil { + callbacks[key] = make(map[uint8]callbackData) + } + callbacks[key][modifiers] = callbackData{ + menuID: menuID, + menuType: menutype, + } +} + +func resetCallbacks() { + callbacks = map[uint16]map[uint8]callbackData{} +} + +func getCallbackForKeyPress(key uint16, modifiers uint8) (string, menuType) { + if callbacks[key] == nil { + return "", "" + } + result := callbacks[key][modifiers] + return result.menuID, result.menuType +} + +func calculateKeycode(key string) uint16 { + return keymap[key] +} + +// TODO: Complete this list +var keymap = map[string]uint16{ + "0": 0x30, + "1": 0x31, + "2": 0x32, + "3": 0x33, + "4": 0x34, + "5": 0x35, + "6": 0x36, + "7": 0x37, + "8": 0x38, + "9": 0x39, + "a": 0x41, + "b": 0x42, + "c": 0x43, + "d": 0x44, + "e": 0x45, + "f": 0x46, + "g": 0x47, + "h": 0x48, + "i": 0x49, + "j": 0x4A, + "k": 0x4B, + "l": 0x4C, + "m": 0x4D, + "n": 0x4E, + "o": 0x4F, + "p": 0x50, + "q": 0x51, + "r": 0x52, + "s": 0x53, + "t": 0x54, + "u": 0x55, + "v": 0x56, + "w": 0x57, + "x": 0x58, + "y": 0x59, + "z": 0x5A, + "backspace": 0x08, + "tab": 0x09, + "return": 0x0D, + "enter": 0x0D, + "escape": 0x1B, + "left": 0x25, + "right": 0x27, + "up": 0x26, + "down": 0x28, + "space": 0x20, + "delete": 0x2E, + "home": 0x24, + "end": 0x23, + "page up": 0x21, + "page down": 0x22, + "f1": 0x70, + "f2": 0x71, + "f3": 0x72, + "f4": 0x73, + "f5": 0x74, + "f6": 0x75, + "f7": 0x76, + "f8": 0x77, + "f9": 0x78, + "f10": 0x79, + "f11": 0x7A, + "f12": 0x7B, + "f13": 0x7C, + "f14": 0x7D, + "f15": 0x7E, + "f16": 0x7F, + "f17": 0x80, + "f18": 0x81, + "f19": 0x82, + "f20": 0x83, + "f21": 0x84, + "f22": 0x85, + "f23": 0x86, + "f24": 0x87, + // Windows doesn't have these apparently so use 0 for unsupported + "f25": 0, + "f26": 0, + "f27": 0, + "f28": 0, + "f29": 0, + "f30": 0, + "f31": 0, + "f32": 0, + "f33": 0, + "f34": 0, + "f35": 0, +} diff --git a/v2/internal/ffenestri/windows_radiogroup.go b/v2/internal/ffenestri/windows_radiogroup.go new file mode 100644 index 000000000..3f3d349ff --- /dev/null +++ b/v2/internal/ffenestri/windows_radiogroup.go @@ -0,0 +1,194 @@ +//+build windows + +package ffenestri + +import ( + "fmt" + "github.com/leaanthony/slicer" + "os" + "sync" + "text/tabwriter" + + "github.com/wailsapp/wails/v2/internal/menumanager" +) + +/* --------------------------------------------------------------------------------- + +Radio Groups +------------ +Radio groups are stored by the ProcessedMenu as a list of menu ids. +Windows only cares about the start and end ids of the group so we +preprocess the radio groups and store this data in a radioGroupMap. +When a radio button is clicked, we use the menu id to read in the +radio group data and call CheckMenuRadioItem to update the group. + +*/ + +type radioGroupStartEnd struct { + startID win32MenuItemID + endID win32MenuItemID +} + +type RadioGroupCache struct { + cache map[*menumanager.ProcessedMenu]map[wailsMenuItemID][]*radioGroupStartEnd + mutex sync.RWMutex +} + +func NewRadioGroupCache() *RadioGroupCache { + return &RadioGroupCache{ + cache: make(map[*menumanager.ProcessedMenu]map[wailsMenuItemID][]*radioGroupStartEnd), + } +} + +func (c *RadioGroupCache) Dump() { + // Start a new tabwriter + w := new(tabwriter.Writer) + w.Init(os.Stdout, 8, 8, 0, '\t', 0) + + println("---------------- RadioGroupCache", c, "Dump ----------------") + for menu, processedMenu := range c.cache { + println("Menu", menu) + _, _ = fmt.Fprintf(w, "Wails ID \tWindows ID Pairs\n") + for wailsMenuItemID, radioGroupStartEnd := range processedMenu { + menus := slicer.String() + for _, se := range radioGroupStartEnd { + menus.Add(fmt.Sprintf("[%d -> %d]", se.startID, se.endID)) + } + _, _ = fmt.Fprintf(w, "%s\t%s\n", wailsMenuItemID, menus.Join(", ")) + _ = w.Flush() + } + } +} + +func (c *RadioGroupCache) addToRadioGroupCache(menu *menumanager.ProcessedMenu, item wailsMenuItemID, radioGroupMaps []*radioGroupStartEnd) { + + c.mutex.Lock() + + // Get map for menu + if c.cache[menu] == nil { + c.cache[menu] = make(map[wailsMenuItemID][]*radioGroupStartEnd) + } + menuMap := c.cache[menu] + + // Ensure we have a slice + if menuMap[item] == nil { + menuMap[item] = []*radioGroupStartEnd{} + } + + menuMap[item] = radioGroupMaps + + c.mutex.Unlock() + +} + +func (c *RadioGroupCache) removeMenuFromRadioBoxCache(menu *menumanager.ProcessedMenu) { + c.mutex.Lock() + delete(c.cache, menu) + c.mutex.Unlock() +} + +func (c *RadioGroupCache) getRadioGroupMappings(wailsMenuID wailsMenuItemID) []*radioGroupStartEnd { + c.mutex.Lock() + result := []*radioGroupStartEnd{} + for _, menugroups := range c.cache { + groups := menugroups[wailsMenuID] + if groups != nil { + result = append(result, groups...) + } + } + c.mutex.Unlock() + return result +} + +type RadioGroupMap struct { + cache map[*menumanager.ProcessedMenu]map[wailsMenuItemID][]win32MenuItemID + mutex sync.RWMutex +} + +func NewRadioGroupMap() *RadioGroupMap { + return &RadioGroupMap{ + cache: make(map[*menumanager.ProcessedMenu]map[wailsMenuItemID][]win32MenuItemID), + } +} + +func (c *RadioGroupMap) Dump() { + // Start a new tabwriter + w := new(tabwriter.Writer) + w.Init(os.Stdout, 8, 8, 0, '\t', 0) + + println("---------------- RadioGroupMap", c, "Dump ----------------") + for _, processedMenu := range c.cache { + _, _ = fmt.Fprintf(w, "Menu\tWails ID \tWindows IDs\n") + for wailsMenuItemID, win32menus := range processedMenu { + menus := slicer.String() + for _, win32menu := range win32menus { + menus.Add(fmt.Sprintf("%v", win32menu)) + } + _, _ = fmt.Fprintf(w, "%p\t%s\t%s\n", processedMenu, wailsMenuItemID, menus.Join(", ")) + _ = w.Flush() + } + } +} + +func (m *RadioGroupMap) addRadioGroupMapping(menu *menumanager.ProcessedMenu, item wailsMenuItemID, win32ID win32MenuItemID) { + m.mutex.Lock() + + // Get map for menu + if m.cache[menu] == nil { + m.cache[menu] = make(map[wailsMenuItemID][]win32MenuItemID) + } + menuMap := m.cache[menu] + + // Ensure we have a slice + if menuMap[item] == nil { + menuMap[item] = []win32MenuItemID{} + } + + menuMap[item] = append(menuMap[item], win32ID) + + m.mutex.Unlock() +} + +func (m *RadioGroupMap) removeMenuFromRadioGroupMapping(menu *menumanager.ProcessedMenu) { + m.mutex.Lock() + delete(m.cache, menu) + m.mutex.Unlock() +} + +func (m *RadioGroupMap) getRadioGroupMapping(wailsMenuID wailsMenuItemID) []win32MenuItemID { + m.mutex.Lock() + result := []win32MenuItemID{} + for _, menuids := range m.cache { + ids := menuids[wailsMenuID] + if ids != nil { + result = append(result, ids...) + } + } + m.mutex.Unlock() + return result +} + +func selectRadioItemFromWailsMenuID(wailsMenuID wailsMenuItemID, win32MenuID win32MenuItemID) error { + radioItemGroups := globalRadioGroupCache.getRadioGroupMappings(wailsMenuID) + // Figure out offset into group + var offset win32MenuItemID = 0 + for _, radioItemGroup := range radioItemGroups { + if win32MenuID >= radioItemGroup.startID && win32MenuID <= radioItemGroup.endID { + offset = win32MenuID - radioItemGroup.startID + break + } + } + for _, radioItemGroup := range radioItemGroups { + selectedMenuID := radioItemGroup.startID + offset + menuItemDetails := getMenuCacheEntry(selectedMenuID) + if menuItemDetails != nil { + if menuItemDetails.parent != 0 { + err := selectRadioItem(selectedMenuID, radioItemGroup.startID, radioItemGroup.endID, menuItemDetails.parent) + if err != nil { + return err + } + } + } + } + return nil +} diff --git a/v2/internal/ffenestri/windows_win32.go b/v2/internal/ffenestri/windows_win32.go new file mode 100644 index 000000000..5942b9bcf --- /dev/null +++ b/v2/internal/ffenestri/windows_win32.go @@ -0,0 +1,130 @@ +//+build windows + +package ffenestri + +import ( + "unsafe" + + "github.com/wailsapp/wails/v2/internal/menumanager" + "golang.org/x/sys/windows" +) + +var ( + // DLL stuff + user32 = windows.NewLazySystemDLL("User32.dll") + win32CreateMenu = user32.NewProc("CreateMenu") + win32DestroyMenu = user32.NewProc("DestroyMenu") + win32CreatePopupMenu = user32.NewProc("CreatePopupMenu") + win32AppendMenuW = user32.NewProc("AppendMenuW") + win32SetMenu = user32.NewProc("SetMenu") + win32CheckMenuItem = user32.NewProc("CheckMenuItem") + win32GetMenuState = user32.NewProc("GetMenuState") + win32CheckMenuRadioItem = user32.NewProc("CheckMenuRadioItem") + + applicationMenu *menumanager.WailsMenu + menuManager *menumanager.Manager +) + +const MF_BITMAP uint32 = 0x00000004 +const MF_CHECKED uint32 = 0x00000008 +const MF_DISABLED uint32 = 0x00000002 +const MF_ENABLED uint32 = 0x00000000 +const MF_GRAYED uint32 = 0x00000001 +const MF_MENUBARBREAK uint32 = 0x00000020 +const MF_MENUBREAK uint32 = 0x00000040 +const MF_OWNERDRAW uint32 = 0x00000100 +const MF_POPUP uint32 = 0x00000010 +const MF_SEPARATOR uint32 = 0x00000800 +const MF_STRING uint32 = 0x00000000 +const MF_UNCHECKED uint32 = 0x00000000 +const MF_BYCOMMAND uint32 = 0x00000000 +const MF_BYPOSITION uint32 = 0x00000400 + +const WM_SIZE = 5 +const WM_GETMINMAXINFO = 36 + +type Win32Rect struct { + Left int32 + Top int32 + Right int32 + Bottom int32 +} + +// ------------------- win32 calls ----------------------- + +func createWin32Menu() (win32Menu, error) { + res, _, err := win32CreateMenu.Call() + if res == 0 { + return 0, wall(err) + } + return win32Menu(res), nil +} + +func destroyWin32Menu(menu win32Menu) error { + res, _, err := win32DestroyMenu.Call(uintptr(menu)) + if res == 0 { + return wall(err, "Menu:", menu) + } + return nil +} + +func createWin32PopupMenu() (win32Menu, error) { + res, _, err := win32CreatePopupMenu.Call() + if res == 0 { + return 0, wall(err) + } + return win32Menu(res), nil +} + +func appendWin32MenuItem(menu win32Menu, flags uintptr, submenuOrID uintptr, label string) error { + menuText, err := windows.UTF16PtrFromString(label) + if err != nil { + return err + } + res, _, err := win32AppendMenuW.Call( + uintptr(menu), + flags, + submenuOrID, + uintptr(unsafe.Pointer(menuText)), + ) + if res == 0 { + return wall(err, "Menu", menu, "Flags", flags, "submenuOrID", submenuOrID, "label", label) + } + return nil +} + +func setWindowMenu(window win32Window, menu win32Menu) error { + res, _, err := win32SetMenu.Call(uintptr(window), uintptr(menu)) + if res == 0 { + return wall(err, "window", window, "menu", menu) + } + return nil +} + +func selectRadioItem(selectedMenuID, startMenuItemID, endMenuItemID win32MenuItemID, parent win32Menu) error { + res, _, err := win32CheckMenuRadioItem.Call(uintptr(parent), uintptr(startMenuItemID), uintptr(endMenuItemID), uintptr(selectedMenuID), uintptr(MF_BYCOMMAND)) + if int(res) == 0 { + return wall(err, selectedMenuID, startMenuItemID, endMenuItemID, parent) + } + return nil +} + +// +//func getWindowRect(window win32Window) (*Win32Rect, error) { +// var windowRect Win32Rect +// res, _, err := win32GetWindowRect.Call(uintptr(window), uintptr(unsafe.Pointer(&windowRect))) +// if res == 0 { +// return nil, err +// } +// return &windowRect, nil +//} +// +//func getClientRect(window win32Window) (*Win32Rect, error) { +// var clientRect Win32Rect +// res, _, err := win32GetClientRect.Call(uintptr(window), uintptr(unsafe.Pointer(&clientRect))) +// if res == 0 { +// return nil, err +// } +// return &clientRect, nil +//} +// diff --git a/v2/internal/ffenestri/wv2ComHandler_windows.h b/v2/internal/ffenestri/wv2ComHandler_windows.h new file mode 100644 index 000000000..60fc43574 --- /dev/null +++ b/v2/internal/ffenestri/wv2ComHandler_windows.h @@ -0,0 +1,126 @@ + +#ifndef WV2COMHANDLER_H +#define WV2COMHANDLER_H + +#include "ffenestri_windows.h" +#include "windows/WebView2.h" + +#include +#include + +class wv2ComHandler + : public ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler, + public ICoreWebView2CreateCoreWebView2ControllerCompletedHandler, + public ICoreWebView2WebMessageReceivedEventHandler, + public ICoreWebView2PermissionRequestedEventHandler, + public ICoreWebView2AcceleratorKeyPressedEventHandler +{ + + struct Application *app; + HWND window; + messageCallback mcb; + comHandlerCallback cb; + + public: + wv2ComHandler(struct Application *app, HWND window, messageCallback mcb, comHandlerCallback cb) { + this->app = app; + this->window = window; + this->mcb = mcb; + this->cb = cb; + } + ULONG STDMETHODCALLTYPE AddRef() { return 1; } + ULONG STDMETHODCALLTYPE Release() { return 1; } + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID *ppv) { + return S_OK; + } + HRESULT STDMETHODCALLTYPE Invoke(HRESULT res, + ICoreWebView2Environment *env) { + env->CreateCoreWebView2Controller(window, this); + return S_OK; + } + HRESULT STDMETHODCALLTYPE Invoke(HRESULT res, + ICoreWebView2Controller *controller) { + controller->AddRef(); + + ICoreWebView2 *webview; + ::EventRegistrationToken token; + controller->get_CoreWebView2(&webview); + controller->add_AcceleratorKeyPressed(this, &token); + webview->add_WebMessageReceived(this, &token); + webview->add_PermissionRequested(this, &token); + + cb(controller); + return S_OK; + } + + // This is our keyboard callback method + HRESULT STDMETHODCALLTYPE Invoke(ICoreWebView2Controller *controller, ICoreWebView2AcceleratorKeyPressedEventArgs * args) { + // Prevent WebView2 from processing the key + args->put_Handled(TRUE); + + COREWEBVIEW2_KEY_EVENT_KIND kind; + args->get_KeyEventKind(&kind); + if (kind == COREWEBVIEW2_KEY_EVENT_KIND_KEY_DOWN || + kind == COREWEBVIEW2_KEY_EVENT_KIND_SYSTEM_KEY_DOWN) + { + UINT key; + args->get_VirtualKey(&key); + COREWEBVIEW2_PHYSICAL_KEY_STATUS status; + args->get_PhysicalKeyStatus(&status); + if (!status.WasKeyDown) + { + processKeyPress(key); + } + } + return S_OK; + } + + // This is called when JS posts a message back to webkit + HRESULT STDMETHODCALLTYPE Invoke( + ICoreWebView2 *sender, ICoreWebView2WebMessageReceivedEventArgs *args) { + LPWSTR message; + args->TryGetWebMessageAsString(&message); + if ( message == nullptr ) { + return S_OK; + } + const char *m = LPWSTRToCstr(message); + + // check for internal messages + if (strcmp(m, "completed") == 0) { + completed(app); + return S_OK; + } + else if (strcmp(m, "initialised") == 0) { + loadAssets(app); + return S_OK; + } + else if (strcmp(m, "wails-drag") == 0) { + // We don't drag in fullscreen mode + if (!app->isFullscreen) { + ReleaseCapture(); + SendMessage(this->window, WM_NCLBUTTONDOWN, HTCAPTION, 0); + } + return S_OK; + } + else { + messageFromWindowCallback(m); + } + delete[] m; + return S_OK; + } + HRESULT STDMETHODCALLTYPE + Invoke(ICoreWebView2 *sender, + ICoreWebView2PermissionRequestedEventArgs *args) { + printf("DDDDDDDDDDDD\n"); + + COREWEBVIEW2_PERMISSION_KIND kind; + args->get_PermissionKind(&kind); + if (kind == COREWEBVIEW2_PERMISSION_KIND_CLIPBOARD_READ) { + args->put_State(COREWEBVIEW2_PERMISSION_STATE_ALLOW); + } + return S_OK; + } + +}; + +#endif \ No newline at end of file diff --git a/v2/internal/frontend/assetserver/assetserver_browser_dev.go b/v2/internal/frontend/assetserver/assetserver_browser_dev.go new file mode 100644 index 000000000..dc1bfb15e --- /dev/null +++ b/v2/internal/frontend/assetserver/assetserver_browser_dev.go @@ -0,0 +1,115 @@ +//go:build dev +// +build dev + +package assetserver + +import ( + "bytes" + "github.com/wailsapp/wails/v2/internal/frontend/runtime" + "github.com/wailsapp/wails/v2/pkg/options" + "golang.org/x/net/html" + "path/filepath" + "strings" +) + +/* + +The assetserver for dev serves assets from disk. +It injects a websocket based IPC script into `index.html`. + +*/ + +import ( + "os" +) + +type BrowserAssetServer struct { + runtimeJS []byte + assetdir string + appOptions *options.App +} + +func NewBrowserAssetServer(assetdir string, bindingsJSON string, appOptions *options.App) (*BrowserAssetServer, error) { + result := &BrowserAssetServer{ + assetdir: assetdir, + appOptions: appOptions, + } + + var buffer bytes.Buffer + buffer.WriteString(`window.wailsbindings='` + bindingsJSON + `';` + "\n") + buffer.Write(runtime.RuntimeDesktopJS) + result.runtimeJS = buffer.Bytes() + return result, nil +} + +func (a *BrowserAssetServer) loadFileFromDisk(filename string) ([]byte, error) { + return os.ReadFile(filepath.Join(a.assetdir, filename)) +} + +func (a *BrowserAssetServer) processIndexHTML() ([]byte, error) { + indexHTML, err := a.loadFileFromDisk("index.html") + if err != nil { + return nil, err + } + htmlNode, err := getHTMLNode(indexHTML) + if err != nil { + return nil, err + } + err = appendSpinnerToBody(htmlNode) + if err != nil { + return nil, err + } + wailsOptions, err := extractOptions(indexHTML) + if err != nil { + return nil, err + } + + if wailsOptions.disableIPCInjection == false { + err := insertScriptInHead(htmlNode, "/wails/ipc.js") + if err != nil { + return nil, err + } + } + + if wailsOptions.disableRuntimeInjection == false { + err := insertScriptInHead(htmlNode, "/wails/runtime.js") + if err != nil { + return nil, err + } + } + + var buffer bytes.Buffer + err = html.Render(&buffer, htmlNode) + if err != nil { + return nil, err + } + return buffer.Bytes(), nil +} + +func (a *BrowserAssetServer) Load(filename string) ([]byte, string, error) { + var content []byte + var err error + switch filename { + case "/": + content, err = a.processIndexHTML() + case "/wails/runtime.js": + content = a.runtimeJS + case "/wails/ipc.js": + content = runtime.WebsocketIPC + default: + content, err = a.loadFileFromDisk(filename) + if strings.HasSuffix(filename, ".js") { + var buffer bytes.Buffer + buffer.WriteString("window.awaitIPC('" + filename + "', ()=>{") + buffer.Write(content) + buffer.WriteString(` +});`) + content = buffer.Bytes() + } + } + if err != nil { + return nil, "", err + } + mimeType := GetMimetype(filename, content) + return content, mimeType, nil +} diff --git a/v2/internal/frontend/assetserver/assetserver_desktop.go b/v2/internal/frontend/assetserver/assetserver_desktop.go new file mode 100644 index 000000000..1ec4a7532 --- /dev/null +++ b/v2/internal/frontend/assetserver/assetserver_desktop.go @@ -0,0 +1,156 @@ +package assetserver + +import ( + "bytes" + "context" + "embed" + "fmt" + "github.com/leaanthony/debme" + "github.com/leaanthony/slicer" + "github.com/wailsapp/wails/v2/internal/frontend/runtime" + "github.com/wailsapp/wails/v2/internal/logger" + "io/fs" + "log" + "path/filepath" + "strings" +) + +type DesktopAssetServer struct { + assets debme.Debme + runtimeJS []byte + assetdir string + logger *logger.Logger +} + +func NewDesktopAssetServer(ctx context.Context, assets embed.FS, bindingsJSON string) (*DesktopAssetServer, error) { + result := &DesktopAssetServer{} + + _logger := ctx.Value("logger") + if _logger != nil { + result.logger = _logger.(*logger.Logger) + } + + _assetdir := ctx.Value("assetdir") + if _assetdir != nil { + result.assetdir = _assetdir.(string) + absdir, err := filepath.Abs(result.assetdir) + if err != nil { + return nil, err + } + result.LogDebug("Loading assets from: %s", absdir) + } + + var buffer bytes.Buffer + buffer.WriteString(`window.wailsbindings='` + bindingsJSON + `';` + "\n") + buffer.Write(runtime.RuntimeDesktopJS) + result.runtimeJS = buffer.Bytes() + err := result.init(assets) + return result, err +} + +func (d *DesktopAssetServer) LogDebug(message string, args ...interface{}) { + if d.logger != nil { + d.logger.Debug("[DesktopAssetServer] "+message, args...) + } +} + +func (d *DesktopAssetServer) SetAssetDir(assetdir string) { + d.assetdir = assetdir +} + +func PathToIndexHTML(assets embed.FS) (string, error) { + stat, err := fs.Stat(assets, "index.html") + if stat != nil { + return ".", nil + } + var indexFiles slicer.StringSlicer + err = fs.WalkDir(assets, ".", func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if strings.HasSuffix(path, "index.html") { + indexFiles.Add(path) + } + return nil + }) + if err != nil { + return "", err + } + + if indexFiles.Length() > 1 { + return "", fmt.Errorf("multiple 'index.html' files found in assets") + } + + path, _ := filepath.Split(indexFiles.AsSlice()[0]) + return path, nil +} + +func processAssets(assets embed.FS) (debme.Debme, error) { + + result, err := debme.FS(assets, ".") + if err != nil { + return result, err + } + // Find index.html + path, err := PathToIndexHTML(assets) + if err != nil { + return debme.Debme{}, err + } + return debme.FS(assets, path) +} + +func (a *DesktopAssetServer) init(assets embed.FS) error { + + var err error + a.assets, err = processAssets(assets) + if err != nil { + return err + } + return nil +} + +func (a *DesktopAssetServer) processIndexHTML() ([]byte, error) { + indexHTML, err := a.ReadFile("index.html") + if err != nil { + return nil, err + } + wailsOptions, err := extractOptions(indexHTML) + if err != nil { + log.Fatal(err) + return nil, err + } + if wailsOptions.disableRuntimeInjection == false { + indexHTML, err = injectHTML(string(indexHTML), ``) + if err != nil { + return nil, err + } + } + if wailsOptions.disableIPCInjection == false { + indexHTML, err = injectHTML(string(indexHTML), ``) + if err != nil { + return nil, err + } + } + + return indexHTML, nil +} + +func (a *DesktopAssetServer) Load(filename string) ([]byte, string, error) { + var content []byte + var err error + switch filename { + case "/": + content, err = a.processIndexHTML() + case "/wails/runtime.js": + content = a.runtimeJS + case "/wails/ipc.js": + content = runtime.DesktopIPC + default: + content, err = a.ReadFile(filename) + } + if err != nil { + return nil, "", err + } + mimeType := GetMimetype(filename, content) + return content, mimeType, nil +} diff --git a/v2/internal/frontend/assetserver/assetserver_desktop_dev.go b/v2/internal/frontend/assetserver/assetserver_desktop_dev.go new file mode 100644 index 000000000..42726ae3a --- /dev/null +++ b/v2/internal/frontend/assetserver/assetserver_desktop_dev.go @@ -0,0 +1,13 @@ +//go:build dev + +package assetserver + +import ( + "os" + "path/filepath" +) + +func (a *DesktopAssetServer) ReadFile(filename string) ([]byte, error) { + a.LogDebug("Loading file from disk: %s", filename) + return os.ReadFile(filepath.Join(a.assetdir, filename)) +} diff --git a/v2/internal/frontend/assetserver/assetserver_desktop_production.go b/v2/internal/frontend/assetserver/assetserver_desktop_production.go new file mode 100644 index 000000000..fb09ee1a3 --- /dev/null +++ b/v2/internal/frontend/assetserver/assetserver_desktop_production.go @@ -0,0 +1,7 @@ +//go:build production + +package assetserver + +func (a *DesktopAssetServer) ReadFile(filename string) ([]byte, error) { + return a.assets.ReadFile(filename) +} diff --git a/v2/internal/frontend/assetserver/common.go b/v2/internal/frontend/assetserver/common.go new file mode 100644 index 000000000..0695d7f27 --- /dev/null +++ b/v2/internal/frontend/assetserver/common.go @@ -0,0 +1,163 @@ +package assetserver + +import ( + "bytes" + "errors" + "fmt" + "golang.org/x/net/html" + "strings" +) + +type optionType string + +const ( + noAutoInject optionType = "noautoinject" + noAutoInjectRuntime optionType = "noautoinjectruntime" + noAutoInjectIPC optionType = "noautoinjectipc" +) + +type Options struct { + disableRuntimeInjection bool + disableIPCInjection bool +} + +func newOptions(optionString string) *Options { + var result = &Options{} + optionString = strings.ToLower(optionString) + options := strings.Split(optionString, ",") + for _, option := range options { + switch optionType(strings.TrimSpace(option)) { + case noAutoInject: + result.disableRuntimeInjection = true + result.disableIPCInjection = true + case noAutoInjectIPC: + result.disableIPCInjection = true + case noAutoInjectRuntime: + result.disableRuntimeInjection = true + } + } + return result +} + +func injectHTML(input string, html string) ([]byte, error) { + splits := strings.Split(input, "") + if len(splits) != 2 { + return nil, fmt.Errorf("unable to locate a tag in your html") + } + + var result bytes.Buffer + result.WriteString(splits[0]) + result.WriteString(html) + result.WriteString("") + result.WriteString(splits[1]) + return result.Bytes(), nil +} + +func extractOptions(htmldata []byte) (*Options, error) { + doc, err := html.Parse(bytes.NewReader(htmldata)) + if err != nil { + return nil, err + } + var extractor func(*html.Node) *Options + extractor = func(node *html.Node) *Options { + if node.Type == html.ElementNode && node.Data == "meta" { + isWailsOptionsTag := false + wailsOptions := "" + for _, attr := range node.Attr { + if isWailsOptionsTag && attr.Key == "content" { + wailsOptions = attr.Val + } + if attr.Val == "wails-options" { + isWailsOptionsTag = true + } + } + return newOptions(wailsOptions) + } + for child := node.FirstChild; child != nil; child = child.NextSibling { + result := extractor(child) + if result != nil { + return result + } + } + return nil + } + result := extractor(doc) + if result == nil { + result = &Options{} + } + return result, nil +} + +func createScriptNode(scriptName string) *html.Node { + return &html.Node{ + Type: html.ElementNode, + Data: "script", + Attr: []html.Attribute{ + { + Key: "src", + Val: scriptName, + }, + }, + } +} + +func createDivNode(id string) *html.Node { + return &html.Node{ + Type: html.ElementNode, + Data: "div", + Attr: []html.Attribute{ + { + Namespace: "", + Key: "id", + Val: id, + }, + }, + } +} + +func insertScriptInHead(htmlNode *html.Node, scriptName string) error { + headNode := findFirstTag(htmlNode, "head") + if headNode == nil { + return errors.New("cannot find head in HTML") + } + scriptNode := createScriptNode(scriptName) + if headNode.FirstChild != nil { + headNode.InsertBefore(scriptNode, headNode.FirstChild) + } else { + headNode.AppendChild(scriptNode) + } + return nil +} + +func appendSpinnerToBody(htmlNode *html.Node) error { + bodyNode := findFirstTag(htmlNode, "body") + if bodyNode == nil { + return errors.New("cannot find body in HTML") + } + scriptNode := createDivNode("wails-spinner") + bodyNode.AppendChild(scriptNode) + return nil +} + +func getHTMLNode(htmldata []byte) (*html.Node, error) { + return html.Parse(bytes.NewReader(htmldata)) +} + +func findFirstTag(htmlnode *html.Node, tagName string) *html.Node { + var extractor func(*html.Node) *html.Node + var result *html.Node + extractor = func(node *html.Node) *html.Node { + if node.Type == html.ElementNode && node.Data == tagName { + return node + } + for child := node.FirstChild; child != nil; child = child.NextSibling { + result := extractor(child) + if result != nil { + return result + } + } + return nil + } + result = extractor(htmlnode) + return result +} diff --git a/v2/internal/frontend/assetserver/common_test.go b/v2/internal/frontend/assetserver/common_test.go new file mode 100644 index 000000000..a60e1e12f --- /dev/null +++ b/v2/internal/frontend/assetserver/common_test.go @@ -0,0 +1,70 @@ +package assetserver + +import ( + "reflect" + "testing" +) + +const realHTML = ` + + + test3 + + + + + + +
Please enter your name below �
+
+ + +
+ + + + + +` + +func genMeta(content string) []byte { + return []byte("") +} + +func genOptions(runtime bool, bindings bool) *Options { + return &Options{ + disableRuntimeInjection: runtime, + disableIPCInjection: bindings, + } +} + +func Test_extractOptions(t *testing.T) { + tests := []struct { + name string + htmldata []byte + want *Options + wantError bool + }{ + {"empty", []byte(""), &Options{}, false}, + {"bad data", []byte("<"), &Options{}, false}, + {"bad options", genMeta("noauto"), genOptions(false, false), false}, + {"realhtml", []byte(realHTML), genOptions(true, true), false}, + {"noautoinject", genMeta("noautoinject"), genOptions(true, true), false}, + {"noautoinjectipc", genMeta("noautoinjectipc"), genOptions(false, true), false}, + {"noautoinjectruntime", genMeta("noautoinjectruntime"), genOptions(true, false), false}, + {"spaces", genMeta(" noautoinjectruntime "), genOptions(true, false), false}, + {"multiple", genMeta("noautoinjectruntime,noautoinjectipc"), genOptions(true, true), false}, + {"multiple spaces", genMeta(" noautoinjectruntime, noautoinjectipc "), genOptions(true, true), false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := extractOptions(tt.htmldata) + if !tt.wantError && err != nil { + t.Errorf("did not want error but got it") + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("extractOptions() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/v2/internal/frontend/assetserver/mimecache.go b/v2/internal/frontend/assetserver/mimecache.go new file mode 100644 index 000000000..ae33f7a54 --- /dev/null +++ b/v2/internal/frontend/assetserver/mimecache.go @@ -0,0 +1,47 @@ +package assetserver + +import ( + "net/http" + "path/filepath" + "strings" + "sync" + + "github.com/gabriel-vasile/mimetype" +) + +var ( + cache = map[string]string{} + mutex sync.Mutex +) + +func GetMimetype(filename string, data []byte) string { + mutex.Lock() + defer mutex.Unlock() + + result := cache[filename] + if result != "" { + return result + } + + detect := mimetype.Detect(data) + if detect == nil { + result = http.DetectContentType(data) + } else { + result = detect.String() + } + + if filepath.Ext(filename) == ".css" && strings.HasPrefix(result, "text/plain") { + result = strings.Replace(result, "text/plain", "text/css", 1) + } + + if filepath.Ext(filename) == ".js" && strings.HasPrefix(result, "text/plain") { + result = strings.Replace(result, "text/plain", "text/javascript", 1) + } + + if result == "" { + result = "application/octet-stream" + } + + cache[filename] = result + return result +} diff --git a/v2/internal/frontend/assetserver/mimecache_test.go b/v2/internal/frontend/assetserver/mimecache_test.go new file mode 100644 index 000000000..d6dbb9dfc --- /dev/null +++ b/v2/internal/frontend/assetserver/mimecache_test.go @@ -0,0 +1,26 @@ +package assetserver + +import "testing" + +func TestGetMimetype(t *testing.T) { + type args struct { + filename string + data []byte + } + tests := []struct { + name string + args args + want string + }{ + // TODO: Add test cases. + {"css", args{"test.css", []byte("body{margin:0;padding:0;background-color:#d579b2}#app{font-family:Avenir,Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-align:center;color:#2c3e50;background-color:#ededed}#nav{padding:30px}#nav a{font-weight:700;color:#2c\n3e50}#nav a.router-link-exact-active{color:#42b983}.hello[data-v-4e26ad49]{margin:10px 0}")}, "text/css; charset=utf-8"}, + {"js", args{"test.js", []byte("let foo = 'bar'; console.log(foo);")}, "text/javascript; charset=utf-8"}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := GetMimetype(tt.args.filename, tt.args.data); got != tt.want { + t.Errorf("GetMimetype() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/v2/pkg/assetserver/testdata/index.html b/v2/internal/frontend/assetserver/testdata/index.html similarity index 100% rename from v2/pkg/assetserver/testdata/index.html rename to v2/internal/frontend/assetserver/testdata/index.html diff --git a/v2/pkg/assetserver/testdata/main.css b/v2/internal/frontend/assetserver/testdata/main.css similarity index 100% rename from v2/pkg/assetserver/testdata/main.css rename to v2/internal/frontend/assetserver/testdata/main.css diff --git a/v2/pkg/assetserver/testdata/main.js b/v2/internal/frontend/assetserver/testdata/main.js similarity index 100% rename from v2/pkg/assetserver/testdata/main.js rename to v2/internal/frontend/assetserver/testdata/main.js diff --git a/v2/pkg/assetserver/testdata/subdir/index.html b/v2/internal/frontend/assetserver/testdata/subdir/index.html similarity index 100% rename from v2/pkg/assetserver/testdata/subdir/index.html rename to v2/internal/frontend/assetserver/testdata/subdir/index.html diff --git a/v2/pkg/assetserver/testdata/subdir/main.css b/v2/internal/frontend/assetserver/testdata/subdir/main.css similarity index 100% rename from v2/pkg/assetserver/testdata/subdir/main.css rename to v2/internal/frontend/assetserver/testdata/subdir/main.css diff --git a/v2/pkg/assetserver/testdata/subdir/main.js b/v2/internal/frontend/assetserver/testdata/subdir/main.js similarity index 100% rename from v2/pkg/assetserver/testdata/subdir/main.js rename to v2/internal/frontend/assetserver/testdata/subdir/main.js diff --git a/v2/pkg/assetserver/testdata/testdata.go b/v2/internal/frontend/assetserver/testdata/testdata.go similarity index 100% rename from v2/pkg/assetserver/testdata/testdata.go rename to v2/internal/frontend/assetserver/testdata/testdata.go diff --git a/v2/internal/frontend/calls.go b/v2/internal/frontend/calls.go index 5401106bc..3983c24bf 100644 --- a/v2/internal/frontend/calls.go +++ b/v2/internal/frontend/calls.go @@ -1,5 +1,5 @@ package frontend type Calls interface { - Callback(message string) + Callback(string) } diff --git a/v2/internal/frontend/desktop/darwin/AppDelegate.h b/v2/internal/frontend/desktop/darwin/AppDelegate.h index a8d10f647..3799aae04 100644 --- a/v2/internal/frontend/desktop/darwin/AppDelegate.h +++ b/v2/internal/frontend/desktop/darwin/AppDelegate.h @@ -9,25 +9,12 @@ #define AppDelegate_h #import -#import "WailsContext.h" -@interface AppDelegate : NSResponder +@interface AppDelegate : NSResponder @property bool alwaysOnTop; -@property bool startHidden; -@property (retain) NSString* singleInstanceUniqueId; -@property bool singleInstanceLockEnabled; -@property bool startFullscreen; -@property (retain) WailsWindow* mainWindow; +@property (retain) NSWindow* mainWindow; @end -extern void HandleOpenFile(char *); - -extern void HandleSecondInstanceData(char * message); - -void SendDataToFirstInstance(char * singleInstanceUniqueId, char * text); - -char* GetMacOsNativeTempDir(); - #endif /* AppDelegate_h */ diff --git a/v2/internal/frontend/desktop/darwin/AppDelegate.m b/v2/internal/frontend/desktop/darwin/AppDelegate.m index a73ec3ec3..24cfaa017 100644 --- a/v2/internal/frontend/desktop/darwin/AppDelegate.m +++ b/v2/internal/frontend/desktop/darwin/AppDelegate.m @@ -9,91 +9,44 @@ #import #import "AppDelegate.h" -#import "CustomProtocol.h" -#import "message.h" @implementation AppDelegate --(BOOL)application:(NSApplication *)sender openFile:(NSString *)filename -{ - const char* utf8FileName = filename.UTF8String; - HandleOpenFile((char*)utf8FileName); - return YES; -} - -- (BOOL)application:(NSApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray> * _Nullable))restorationHandler { - if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) { - NSURL *url = userActivity.webpageURL; - if (url) { - HandleOpenURL((char*)[[url absoluteString] UTF8String]); - return YES; - } - } - return NO; -} - - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender { - return NO; + return NO; } - -- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { - processMessage("Q"); - return NSTerminateCancel; -} - - (void)applicationWillFinishLaunching:(NSNotification *)aNotification { [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; + [self.mainWindow makeKeyAndOrderFront:self]; if (self.alwaysOnTop) { - [self.mainWindow setLevel:NSFloatingWindowLevel]; - } - if ( !self.startHidden ) { - [self.mainWindow makeKeyAndOrderFront:self]; + [self.mainWindow setLevel:NSStatusWindowLevel]; } } - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { [NSApp activateIgnoringOtherApps:YES]; - if ( self.startFullscreen ) { - NSWindowCollectionBehavior behaviour = [self.mainWindow collectionBehavior]; - behaviour |= NSWindowCollectionBehaviorFullScreenPrimary; - [self.mainWindow setCollectionBehavior:behaviour]; - [self.mainWindow toggleFullScreen:nil]; - } - - if ( self.singleInstanceLockEnabled ) { - [[NSDistributedNotificationCenter defaultCenter] addObserver:self - selector:@selector(handleSecondInstanceNotification:) name:self.singleInstanceUniqueId object:nil]; - } -} - -void SendDataToFirstInstance(char * singleInstanceUniqueId, char * message) { - // we pass message in object because otherwise sandboxing will prevent us from sending it https://developer.apple.com/forums/thread/129437 - NSString * myString = [NSString stringWithUTF8String:message]; - [[NSDistributedNotificationCenter defaultCenter] - postNotificationName:[NSString stringWithUTF8String:singleInstanceUniqueId] - object:(__bridge const void *)(myString) - userInfo:nil - deliverImmediately:YES]; -} - -char* GetMacOsNativeTempDir() { - NSString *tempDir = NSTemporaryDirectory(); - char *copy = strdup([tempDir UTF8String]); - - return copy; -} - -- (void)handleSecondInstanceNotification:(NSNotification *)note; -{ - if (note.object != nil) { - NSString * message = (__bridge NSString *)note.object; - const char* utf8Message = message.UTF8String; - HandleSecondInstanceData((char*)utf8Message); - } -} - -- (void)dealloc { - [super dealloc]; } +// +//- (void) CreateMenu { +// [NSApplication sharedApplication]; +// menubar = [[NSMenu new] autorelease]; +// id appMenuItem = [[NSMenuItem new] autorelease]; +// [menubar addItem:appMenuItem]; +// [NSApp setMainMenu:menubar]; +// id appMenu = [[NSMenu new] autorelease]; +// id appName = [[NSProcessInfo processInfo] processName]; +// id quitTitle = [@"Quit " stringByAppendingString:appName]; +// id quitMenuItem = [[[NSMenuItem alloc] initWithTitle:quitTitle +// action:@selector(terminate:) keyEquivalent:@"q"] +// autorelease]; +// [appMenu addItem:quitMenuItem]; +// [appMenuItem setSubmenu:appMenu]; +//} +// +//- (void) dealloc { +// [super dealloc]; +// window = nil; +// menubar = nil; +//} @synthesize touchBar; diff --git a/v2/internal/frontend/desktop/darwin/Application.h b/v2/internal/frontend/desktop/darwin/Application.h index 4d8bbd37b..05ead41a6 100644 --- a/v2/internal/frontend/desktop/darwin/Application.h +++ b/v2/internal/frontend/desktop/darwin/Application.h @@ -12,18 +12,12 @@ #import #import "WailsContext.h" -#define WindowStartsNormal 0 -#define WindowStartsMaximised 1 -#define WindowStartsMinimised 2 -#define WindowStartsFullscreen 3 - -WailsContext* Create(const char* title, int width, int height, int frameless, int resizable, int zoomable, int fullscreen, int fullSizeContent, int hideTitleBar, int titlebarAppearsTransparent, int hideTitle, int useToolbar, int hideToolbarSeparator, int webviewIsTransparent, int alwaysOnTop, int hideWindowOnClose, const char *appearance, int windowIsTranslucent, int contentProtection, int devtoolsEnabled, int defaultContextMenuEnabled, int windowStartState, int startsHidden, int minWidth, int minHeight, int maxWidth, int maxHeight, bool fraudulentWebsiteWarningEnabled, struct Preferences preferences, int singleInstanceLockEnabled, const char* singleInstanceUniqueId, bool enableDragAndDrop, bool disableWebViewDragAndDrop); -void Run(void*, const char* url); +WailsContext* Create(const char* title, int width, int height, int frameless, int resizable, int fullscreen, int fullSizeContent, int hideTitleBar, int titlebarAppearsTransparent, int hideTitle, int useToolbar, int hideToolbarSeparator, int webviewIsTransparent, int alwaysOnTop, int hideWindowOnClose, const char *appearance, int windowIsTranslucent, int debug); +void Run(void*); void SetTitle(void* ctx, const char *title); void Center(void* ctx); void SetSize(void* ctx, int width, int height); -void SetAlwaysOnTop(void* ctx, int onTop); void SetMinSize(void* ctx, int width, int height); void SetMaxSize(void* ctx, int width, int height); void SetPosition(void* ctx, int x, int y); @@ -31,44 +25,20 @@ void Fullscreen(void* ctx); void UnFullscreen(void* ctx); void Minimise(void* ctx); void UnMinimise(void* ctx); -void ToggleMaximise(void* ctx); void Maximise(void* ctx); void UnMaximise(void* ctx); void Hide(void* ctx); void Show(void* ctx); -void HideApplication(void* ctx); -void ShowApplication(void* ctx); -void SetBackgroundColour(void* ctx, int r, int g, int b, int a); +void SetRGBA(void* ctx, int r, int g, int b, int a); void ExecJS(void* ctx, const char*); void Quit(void*); -void WindowPrint(void* ctx); const char* GetSize(void *ctx); -const char* GetPosition(void *ctx); -const bool IsFullScreen(void *ctx); -const bool IsMinimised(void *ctx); -const bool IsMaximised(void *ctx); +const char* GetPos(void *ctx); -/* Dialogs */ +void ProcessURLResponse(void *inctx, const char *url, const char *contentType, const char *data, int datalength); -void MessageDialog(void *inctx, const char* dialogType, const char* title, const char* message, const char* button1, const char* button2, const char* button3, const char* button4, const char* defaultButton, const char* cancelButton, void* iconData, int iconDataLength); +void MessageDialog(void *inctx, const char* dialogType, const char* title, const char* message, const char* button1, const char* button2, const char* button3, const char* button4, const char* defaultButton, const char* cancelButton); void OpenFileDialog(void *inctx, const char* title, const char* defaultFilename, const char* defaultDirectory, int allowDirectories, int allowFiles, int canCreateDirectories, int treatPackagesAsDirectories, int resolveAliases, int showHiddenFiles, int allowMultipleSelection, const char* filters); void SaveFileDialog(void *inctx, const char* title, const char* defaultFilename, const char* defaultDirectory, int canCreateDirectories, int treatPackagesAsDirectories, int showHiddenFiles, const char* filters); - -/* Application Menu */ -void* NewMenu(const char* name); -void AppendSubmenu(void* parent, void* child); -void AppendRole(void *inctx, void *inMenu, int role); -void SetAsApplicationMenu(void *inctx, void *inMenu); -void UpdateApplicationMenu(void *inctx); - -void SetAbout(void *inctx, const char* title, const char* description, void* imagedata, int datalen); -void* AppendMenuItem(void* inctx, void* nsmenu, const char* label, const char* shortcutKey, int modifiers, int disabled, int checked, int menuItemID); -void AppendSeparator(void* inMenu); -void UpdateMenuItem(void* nsmenuitem, int checked); -void RunMainLoop(void); -void ReleaseContext(void *inctx); - -NSString* safeInit(const char* input); - #endif /* Application_h */ diff --git a/v2/internal/frontend/desktop/darwin/Application.m b/v2/internal/frontend/desktop/darwin/Application.m index 38d349c2c..ac730d523 100644 --- a/v2/internal/frontend/desktop/darwin/Application.m +++ b/v2/internal/frontend/desktop/darwin/Application.m @@ -1,4 +1,3 @@ -//go:build darwin // // Application.m // @@ -10,82 +9,51 @@ #import "WailsContext.h" #import "Application.h" #import "AppDelegate.h" -#import "WindowDelegate.h" -#import "WailsMenu.h" -#import "WailsMenuItem.h" - -WailsContext* Create(const char* title, int width, int height, int frameless, int resizable, int zoomable, int fullscreen, int fullSizeContent, int hideTitleBar, int titlebarAppearsTransparent, int hideTitle, int useToolbar, int hideToolbarSeparator, int webviewIsTransparent, int alwaysOnTop, int hideWindowOnClose, const char *appearance, int windowIsTranslucent, int contentProtection, int devtoolsEnabled, int defaultContextMenuEnabled, int windowStartState, int startsHidden, int minWidth, int minHeight, int maxWidth, int maxHeight, bool fraudulentWebsiteWarningEnabled, struct Preferences preferences, int singleInstanceLockEnabled, const char* singleInstanceUniqueId, bool enableDragAndDrop, bool disableWebViewDragAndDrop) { - - [NSApplication sharedApplication]; +WailsContext* Create(const char* title, int width, int height, int frameless, int resizable, int fullscreen, int fullSizeContent, int hideTitleBar, int titlebarAppearsTransparent, int hideTitle, int useToolbar, int hideToolbarSeparator, int webviewIsTransparent, int alwaysOnTop, int hideWindowOnClose, const char *appearance, int windowIsTranslucent, int debug) { + WailsContext *result = [WailsContext new]; - result.devtoolsEnabled = devtoolsEnabled; - result.defaultContextMenuEnabled = defaultContextMenuEnabled; - - if ( windowStartState == WindowStartsFullscreen ) { - fullscreen = 1; - } - - [result CreateWindow:width :height :frameless :resizable :zoomable :fullscreen :fullSizeContent :hideTitleBar :titlebarAppearsTransparent :hideTitle :useToolbar :hideToolbarSeparator :webviewIsTransparent :hideWindowOnClose :safeInit(appearance) :windowIsTranslucent :minWidth :minHeight :maxWidth :maxHeight :fraudulentWebsiteWarningEnabled :preferences :enableDragAndDrop :disableWebViewDragAndDrop]; - [result SetTitle:safeInit(title)]; + result.debug = debug; + + [result CreateWindow:width :height :frameless :resizable :fullscreen :fullSizeContent :hideTitleBar :titlebarAppearsTransparent :hideTitle :useToolbar :hideToolbarSeparator :webviewIsTransparent :hideWindowOnClose :appearance :windowIsTranslucent]; + [result SetTitle:title]; [result Center]; - - if (contentProtection == 1 && - [result.mainWindow respondsToSelector:@selector(setSharingType:)]) { - [result.mainWindow setSharingType:NSWindowSharingNone]; - } - - switch( windowStartState ) { - case WindowStartsMaximised: - [result.mainWindow zoom:nil]; - break; - case WindowStartsMinimised: - //TODO: Can you start a mac app minimised? - break; - } - - if ( startsHidden == 1 ) { - result.startHidden = true; - } - - if ( fullscreen == 1 ) { - result.startFullscreen = true; - } - - if ( singleInstanceLockEnabled == 1 ) { - result.singleInstanceLockEnabled = true; - result.singleInstanceUniqueId = safeInit(singleInstanceUniqueId); - } - + result.alwaysOnTop = alwaysOnTop; result.hideOnClose = hideWindowOnClose; - + return result; } +void ProcessURLResponse(void *inctx, const char *url, const char *contentType, const char* data, int datalength) { + WailsContext *ctx = (__bridge WailsContext*) inctx; + NSString *nsurl = [[NSString alloc] initWithUTF8String:url]; + NSString *nsContentType = [[NSString alloc] initWithUTF8String:contentType]; + NSData *nsdata = [NSData dataWithBytes:data length:datalength]; + + [ctx processURLResponse:nsurl :nsContentType :nsdata]; +} + void ExecJS(void* inctx, const char *script) { WailsContext *ctx = (__bridge WailsContext*) inctx; - NSString *nsscript = safeInit(script); ON_MAIN_THREAD( - [ctx ExecJS:nsscript]; - [nsscript release]; + [ctx ExecJS:script]; ); } void SetTitle(void* inctx, const char *title) { WailsContext *ctx = (__bridge WailsContext*) inctx; - NSString *_title = safeInit(title); ON_MAIN_THREAD( - [ctx SetTitle:_title]; + [ctx SetTitle:title]; ); } -void SetBackgroundColour(void *inctx, int r, int g, int b, int a) { +void SetRGBA(void *inctx, int r, int g, int b, int a) { WailsContext *ctx = (__bridge WailsContext*) inctx; ON_MAIN_THREAD( - [ctx SetBackgroundColour:r :g :b :a]; + [ctx SetRGBA:r :g :b :a]; ); } @@ -96,13 +64,6 @@ void SetSize(void* inctx, int width, int height) { ); } -void SetAlwaysOnTop(void* inctx, int onTop) { - WailsContext *ctx = (__bridge WailsContext*) inctx; - ON_MAIN_THREAD( - [ctx SetAlwaysOnTop:onTop]; - ); -} - void SetMinSize(void* inctx, int width, int height) { WailsContext *ctx = (__bridge WailsContext*) inctx; ON_MAIN_THREAD( @@ -120,7 +81,7 @@ void SetMaxSize(void* inctx, int width, int height) { void SetPosition(void* inctx, int x, int y) { WailsContext *ctx = (__bridge WailsContext*) inctx; ON_MAIN_THREAD( - [ctx SetPosition:x :y]; + [ctx SetSize:x :y]; ); } @@ -166,13 +127,6 @@ void Maximise(void* inctx) { ); } -void ToggleMaximise(void* inctx) { - WailsContext *ctx = (__bridge WailsContext*) inctx; - ON_MAIN_THREAD( - [ctx ToggleMaximise]; - ); -} - const char* GetSize(void *inctx) { WailsContext *ctx = (__bridge WailsContext*) inctx; NSRect frame = [ctx.mainWindow frame]; @@ -180,7 +134,7 @@ const char* GetSize(void *inctx) { return [result UTF8String]; } -const char* GetPosition(void *inctx) { +const char* GetPos(void *inctx) { WailsContext *ctx = (__bridge WailsContext*) inctx; NSScreen* screen = [ctx getCurrentScreen]; NSRect windowFrame = [ctx.mainWindow frame]; @@ -190,21 +144,7 @@ const char* GetPosition(void *inctx) { y = screenFrame.size.height - y - windowFrame.size.height; NSString *result = [NSString stringWithFormat:@"%d,%d",x,y]; return [result UTF8String]; -} - -const bool IsFullScreen(void *inctx) { - WailsContext *ctx = (__bridge WailsContext*) inctx; - return [ctx IsFullScreen]; -} - -const bool IsMinimised(void *inctx) { - WailsContext *ctx = (__bridge WailsContext*) inctx; - return [ctx IsMinimised]; -} - -const bool IsMaximised(void *inctx) { - WailsContext *ctx = (__bridge WailsContext*) inctx; - return [ctx IsMaximised]; + } void UnMaximise(void* inctx) { @@ -217,7 +157,6 @@ void UnMaximise(void* inctx) { void Quit(void *inctx) { WailsContext *ctx = (__bridge WailsContext*) inctx; [NSApp stop:ctx]; - [NSApp abortModal]; } void Hide(void *inctx) { @@ -234,200 +173,42 @@ void Show(void *inctx) { ); } - -void HideApplication(void *inctx) { +void MessageDialog(void *inctx, const char* dialogType, const char* title, const char* message, const char* button1, const char* button2, const char* button3, const char* button4, const char* defaultButton, const char* cancelButton) { WailsContext *ctx = (__bridge WailsContext*) inctx; ON_MAIN_THREAD( - [ctx HideApplication]; - ); -} - -void ShowApplication(void *inctx) { - WailsContext *ctx = (__bridge WailsContext*) inctx; - ON_MAIN_THREAD( - [ctx ShowApplication]; - ); -} - -NSString* safeInit(const char* input) { - NSString *result = nil; - if (input != nil) { - result = [NSString stringWithUTF8String:input]; - } - return result; -} - -void MessageDialog(void *inctx, const char* dialogType, const char* title, const char* message, const char* button1, const char* button2, const char* button3, const char* button4, const char* defaultButton, const char* cancelButton, void* iconData, int iconDataLength) { - WailsContext *ctx = (__bridge WailsContext*) inctx; - - NSString *_dialogType = safeInit(dialogType); - NSString *_title = safeInit(title); - NSString *_message = safeInit(message); - NSString *_button1 = safeInit(button1); - NSString *_button2 = safeInit(button2); - NSString *_button3 = safeInit(button3); - NSString *_button4 = safeInit(button4); - NSString *_defaultButton = safeInit(defaultButton); - NSString *_cancelButton = safeInit(cancelButton); - - ON_MAIN_THREAD( - [ctx MessageDialog:_dialogType :_title :_message :_button1 :_button2 :_button3 :_button4 :_defaultButton :_cancelButton :iconData :iconDataLength]; + [ctx MessageDialog:dialogType :title :message :button1 :button2 :button3 :button4 :defaultButton :cancelButton]; ) } void OpenFileDialog(void *inctx, const char* title, const char* defaultFilename, const char* defaultDirectory, int allowDirectories, int allowFiles, int canCreateDirectories, int treatPackagesAsDirectories, int resolveAliases, int showHiddenFiles, int allowMultipleSelection, const char* filters) { - WailsContext *ctx = (__bridge WailsContext*) inctx; - NSString *_title = safeInit(title); - NSString *_defaultFilename = safeInit(defaultFilename); - NSString *_defaultDirectory = safeInit(defaultDirectory); - NSString *_filters = safeInit(filters); - ON_MAIN_THREAD( - [ctx OpenFileDialog:_title :_defaultFilename :_defaultDirectory :allowDirectories :allowFiles :canCreateDirectories :treatPackagesAsDirectories :resolveAliases :showHiddenFiles :allowMultipleSelection :_filters]; + [ctx OpenFileDialog:title :defaultFilename :defaultDirectory :allowDirectories :allowFiles :canCreateDirectories :treatPackagesAsDirectories :resolveAliases :showHiddenFiles :allowMultipleSelection :filters]; ) } void SaveFileDialog(void *inctx, const char* title, const char* defaultFilename, const char* defaultDirectory, int canCreateDirectories, int treatPackagesAsDirectories, int showHiddenFiles, const char* filters) { - WailsContext *ctx = (__bridge WailsContext*) inctx; - NSString *_title = safeInit(title); - NSString *_defaultFilename = safeInit(defaultFilename); - NSString *_defaultDirectory = safeInit(defaultDirectory); - NSString *_filters = safeInit(filters); - ON_MAIN_THREAD( - [ctx SaveFileDialog:_title :_defaultFilename :_defaultDirectory :canCreateDirectories :treatPackagesAsDirectories :showHiddenFiles :_filters]; + [ctx SaveFileDialog:title :defaultFilename :defaultDirectory :canCreateDirectories :treatPackagesAsDirectories :showHiddenFiles :filters]; ) } -void AppendRole(void *inctx, void *inMenu, int role) { + + + +void Run(void *inctx) { WailsContext *ctx = (__bridge WailsContext*) inctx; - WailsMenu *menu = (__bridge WailsMenu*) inMenu; - [menu appendRole :ctx :role]; -} - -void* NewMenu(const char *name) { - NSString *title = @""; - if (name != nil) { - title = [NSString stringWithUTF8String:name]; - } - WailsMenu *result = [[WailsMenu new] initWithNSTitle:title]; - return result; -} - -void AppendSubmenu(void* inparent, void* inchild) { - WailsMenu *parent = (__bridge WailsMenu*) inparent; - WailsMenu *child = (__bridge WailsMenu*) inchild; - [parent appendSubmenu:child]; -} - -void SetAsApplicationMenu(void *inctx, void *inMenu) { - WailsContext *ctx = (__bridge WailsContext*) inctx; - WailsMenu *menu = (__bridge WailsMenu*) inMenu; - ctx.applicationMenu = menu; -} - -void UpdateApplicationMenu(void *inctx) { - WailsContext *ctx = (__bridge WailsContext*) inctx; - ON_MAIN_THREAD( - NSApplication *app = [NSApplication sharedApplication]; - [app setMainMenu:ctx.applicationMenu]; - ) -} - -void SetAbout(void *inctx, const char* title, const char* description, void* imagedata, int datalen) { - WailsContext *ctx = (__bridge WailsContext*) inctx; - NSString *_title = safeInit(title); - NSString *_description = safeInit(description); - - [ctx SetAbout :_title :_description :imagedata :datalen]; -} - -void* AppendMenuItem(void* inctx, void* inMenu, const char* label, const char* shortcutKey, int modifiers, int disabled, int checked, int menuItemID) { - WailsContext *ctx = (__bridge WailsContext*) inctx; - WailsMenu *menu = (__bridge WailsMenu*) inMenu; - NSString *_label = safeInit(label); - NSString *_shortcutKey = safeInit(shortcutKey); - - return [menu AppendMenuItem:ctx :_label :_shortcutKey :modifiers :disabled :checked :menuItemID]; -} - -void UpdateMenuItem(void* nsmenuitem, int checked) { - ON_MAIN_THREAD( - WailsMenuItem *menuItem = (__bridge WailsMenuItem*) nsmenuitem; - [menuItem setState:(checked == 1?NSControlStateValueOn:NSControlStateValueOff)]; - ) -} - - -void AppendSeparator(void* inMenu) { - WailsMenu *menu = (__bridge WailsMenu*) inMenu; - [menu AppendSeparator]; -} - - - -void Run(void *inctx, const char* url) { - WailsContext *ctx = (__bridge WailsContext*) inctx; - NSApplication *app = [NSApplication sharedApplication]; + [NSApplication sharedApplication]; AppDelegate* delegate = [AppDelegate new]; - [app setDelegate:(id)delegate]; + [NSApp setDelegate:(id)delegate]; ctx.appdelegate = delegate; delegate.mainWindow = ctx.mainWindow; delegate.alwaysOnTop = ctx.alwaysOnTop; - delegate.startHidden = ctx.startHidden; - delegate.singleInstanceLockEnabled = ctx.singleInstanceLockEnabled; - delegate.singleInstanceUniqueId = ctx.singleInstanceUniqueId; - delegate.startFullscreen = ctx.startFullscreen; - NSString *_url = safeInit(url); - [ctx loadRequest:_url]; - [_url release]; - - [app setMainMenu:ctx.applicationMenu]; -} - -void RunMainLoop(void) { - NSApplication *app = [NSApplication sharedApplication]; - [app run]; -} - -void ReleaseContext(void *inctx) { - WailsContext *ctx = (__bridge WailsContext*) inctx; + [ctx loadRequest:@"wails://wails/"]; + + [NSApp run]; [ctx release]; -} - -// Credit: https://stackoverflow.com/q/33319295 -void WindowPrint(void *inctx) { - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 110000 - if (@available(macOS 11.0, *)) { - ON_MAIN_THREAD( - WailsContext *ctx = (__bridge WailsContext*) inctx; - WKWebView* webView = ctx.webview; - - // I think this should be exposed as a config - // It directly affects the printed output/PDF - NSPrintInfo *pInfo = [NSPrintInfo sharedPrintInfo]; - pInfo.horizontalPagination = NSPrintingPaginationModeAutomatic; - pInfo.verticalPagination = NSPrintingPaginationModeAutomatic; - pInfo.verticallyCentered = YES; - pInfo.horizontallyCentered = YES; - pInfo.orientation = NSPaperOrientationLandscape; - pInfo.leftMargin = 0; - pInfo.rightMargin = 0; - pInfo.topMargin = 0; - pInfo.bottomMargin = 0; - - NSPrintOperation *po = [webView printOperationWithPrintInfo:pInfo]; - po.showsPrintPanel = YES; - po.showsProgressPanel = YES; - - po.view.frame = webView.bounds; - - [po runOperationModalForWindow:ctx.mainWindow delegate:ctx.mainWindow.delegate didRunSelector:nil contextInfo:nil]; - ) - } -#endif + NSLog(@"Here"); } diff --git a/v2/internal/frontend/desktop/darwin/CustomProtocol.h b/v2/internal/frontend/desktop/darwin/CustomProtocol.h deleted file mode 100644 index 0698a4d45..000000000 --- a/v2/internal/frontend/desktop/darwin/CustomProtocol.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef CustomProtocol_h -#define CustomProtocol_h - -#import - -extern void HandleOpenURL(char*); - -@interface CustomProtocolSchemeHandler : NSObject -+ (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent; -@end - -void StartCustomProtocolHandler(void); - -#endif /* CustomProtocol_h */ diff --git a/v2/internal/frontend/desktop/darwin/CustomProtocol.m b/v2/internal/frontend/desktop/darwin/CustomProtocol.m deleted file mode 100644 index ebc61aa00..000000000 --- a/v2/internal/frontend/desktop/darwin/CustomProtocol.m +++ /dev/null @@ -1,20 +0,0 @@ -#include "CustomProtocol.h" - -@implementation CustomProtocolSchemeHandler -+ (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent { - [event paramDescriptorForKeyword:keyDirectObject]; - - NSString *urlStr = [[event paramDescriptorForKeyword:keyDirectObject] stringValue]; - - HandleOpenURL((char*)[[[event paramDescriptorForKeyword:keyDirectObject] stringValue] UTF8String]); -} -@end - -void StartCustomProtocolHandler(void) { - NSAppleEventManager *appleEventManager = [NSAppleEventManager sharedAppleEventManager]; - - [appleEventManager setEventHandler:[CustomProtocolSchemeHandler class] - andSelector:@selector(handleGetURLEvent:withReplyEvent:) - forEventClass:kInternetEventClass - andEventID: kAEGetURL]; -} diff --git a/v2/internal/frontend/desktop/darwin/Role.h b/v2/internal/frontend/desktop/darwin/Role.h deleted file mode 100644 index 6b8877a09..000000000 --- a/v2/internal/frontend/desktop/darwin/Role.h +++ /dev/null @@ -1,17 +0,0 @@ -// -// Role.h -// test -// -// Created by Lea Anthony on 24/10/21. -// - -#ifndef Role_h -#define Role_h - -typedef int Role; - -static const Role AppMenu = 1; -static const Role EditMenu = 2; -static const Role WindowMenu = 3; - -#endif /* Role_h */ diff --git a/v2/internal/frontend/desktop/darwin/WailsAlert.h b/v2/internal/frontend/desktop/darwin/WailsAlert.h index 29dc839f6..69e8ee170 100644 --- a/v2/internal/frontend/desktop/darwin/WailsAlert.h +++ b/v2/internal/frontend/desktop/darwin/WailsAlert.h @@ -11,7 +11,7 @@ #import @interface WailsAlert : NSAlert -- (void)addButton:(NSString*)text :(NSString*)defaultButton :(NSString*)cancelButton; +- (void)addButton:(const char*)text :(const char*)defaultButton :(const char*)cancelButton; @end diff --git a/v2/internal/frontend/desktop/darwin/WailsAlert.m b/v2/internal/frontend/desktop/darwin/WailsAlert.m index 3c8b7305a..04105634c 100644 --- a/v2/internal/frontend/desktop/darwin/WailsAlert.m +++ b/v2/internal/frontend/desktop/darwin/WailsAlert.m @@ -1,4 +1,3 @@ -//go:build darwin // // WailsAlert.m // test @@ -12,14 +11,14 @@ @implementation WailsAlert -- (void)addButton:(NSString*)text :(NSString*)defaultButton :(NSString*)cancelButton { +- (void)addButton:(const char*)text :(const char*)defaultButton :(const char*)cancelButton { if( text == nil ) { return; } - NSButton *button = [self addButtonWithTitle:text]; - if( defaultButton != nil && [text isEqualToString:defaultButton]) { + NSButton *button = [self addButtonWithTitle:[NSString stringWithUTF8String:text]]; + if( defaultButton != nil && strcmp(text, defaultButton) == 0) { [button setKeyEquivalent:@"\r"]; - } else if( cancelButton != nil && [text isEqualToString:cancelButton]) { + } else if( cancelButton != nil && strcmp(text, cancelButton) == 0) { [button setKeyEquivalent:@"\033"]; } else { [button setKeyEquivalent:@""]; diff --git a/v2/internal/frontend/desktop/darwin/WailsContext.h b/v2/internal/frontend/desktop/darwin/WailsContext.h index 2ec6d8707..c4b6e409b 100644 --- a/v2/internal/frontend/desktop/darwin/WailsContext.h +++ b/v2/internal/frontend/desktop/darwin/WailsContext.h @@ -10,99 +10,64 @@ #import #import -#import "WailsWebView.h" - -#if __has_include() -#define USE_NEW_FILTERS -#import -#endif #define ON_MAIN_THREAD(str) dispatch_async(dispatch_get_main_queue(), ^{ str; }); -#define unicode(input) [NSString stringWithFormat:@"%C", input] @interface WailsWindow : NSWindow - -@property NSSize userMinSize; -@property NSSize userMaxSize; - -- (BOOL) canBecomeKeyWindow; -- (void) applyWindowConstraints; -- (void) disableWindowConstraints; +- (BOOL)canBecomeKeyWindow; @end -@interface WailsContext : NSObject +@interface WailsContext : NSObject @property (retain) WailsWindow* mainWindow; -@property (retain) WailsWebView* webview; +@property (retain) WKWebView* webview; @property (nonatomic, assign) id appdelegate; @property bool hideOnClose; @property bool shuttingDown; -@property bool startHidden; -@property bool startFullscreen; -@property bool singleInstanceLockEnabled; -@property (retain) NSString* singleInstanceUniqueId; +@property NSSize maxSize; +@property NSSize minSize; @property (retain) NSEvent* mouseEvent; @property bool alwaysOnTop; +@property bool maximised; -@property bool devtoolsEnabled; -@property bool defaultContextMenuEnabled; +@property bool debug; @property (retain) WKUserContentController* userContentController; -@property (retain) NSMenu* applicationMenu; +@property (retain) NSMutableDictionary *urlRequests; -@property (retain) NSImage* aboutImage; -@property (retain) NSString* aboutTitle; -@property (retain) NSString* aboutDescription; - -struct Preferences { - bool *tabFocusesLinks; - bool *textInteractionEnabled; - bool *fullscreenEnabled; -}; - -- (void) CreateWindow:(int)width :(int)height :(bool)frameless :(bool)resizable :(bool)zoomable :(bool)fullscreen :(bool)fullSizeContent :(bool)hideTitleBar :(bool)titlebarAppearsTransparent :(bool)hideTitle :(bool)useToolbar :(bool)hideToolbarSeparator :(bool)webviewIsTransparent :(bool)hideWindowOnClose :(NSString *)appearance :(bool)windowIsTranslucent :(int)minWidth :(int)minHeight :(int)maxWidth :(int)maxHeight :(bool)fraudulentWebsiteWarningEnabled :(struct Preferences)preferences :(bool)enableDragAndDrop :(bool)disableWebViewDragAndDrop; +- (void) CreateWindow:(int)width :(int)height :(bool)frameless :(bool)resizable :(bool)fullscreen :(bool)fullSizeContent :(bool)hideTitleBar :(bool)titlebarAppearsTransparent :(bool)hideTitle :(bool)useToolbar :(bool)hideToolbarSeparator :(bool)webviewIsTransparent :(bool)hideWindowOnClose :(const char *)appearance :(bool)windowIsTranslucent; - (void) SetSize:(int)width :(int)height; - (void) SetPosition:(int)x :(int) y; - (void) SetMinSize:(int)minWidth :(int)minHeight; - (void) SetMaxSize:(int)maxWidth :(int)maxHeight; -- (void) SetTitle:(NSString*)title; -- (void) SetAlwaysOnTop:(int)onTop; +- (void) SetTitle:(const char*)title; - (void) Center; - (void) Fullscreen; - (void) UnFullscreen; -- (bool) IsFullScreen; - (void) Minimise; - (void) UnMinimise; -- (bool) IsMinimised; - (void) Maximise; -- (void) ToggleMaximise; - (void) UnMaximise; -- (bool) IsMaximised; -- (void) SetBackgroundColour:(int)r :(int)g :(int)b :(int)a; +- (void) SetRGBA:(int)r :(int)g :(int)b :(int)a; - (void) HideMouse; - (void) ShowMouse; - (void) Hide; - (void) Show; -- (void) HideApplication; -- (void) ShowApplication; -- (void) Quit; --(void) MessageDialog :(NSString*)dialogType :(NSString*)title :(NSString*)message :(NSString*)button1 :(NSString*)button2 :(NSString*)button3 :(NSString*)button4 :(NSString*)defaultButton :(NSString*)cancelButton :(void*)iconData :(int)iconDataLength; -- (void) OpenFileDialog :(NSString*)title :(NSString*)defaultFilename :(NSString*)defaultDirectory :(bool)allowDirectories :(bool)allowFiles :(bool)canCreateDirectories :(bool)treatPackagesAsDirectories :(bool)resolveAliases :(bool)showHiddenFiles :(bool)allowMultipleSelection :(NSString*)filters; -- (void) SaveFileDialog :(NSString*)title :(NSString*)defaultFilename :(NSString*)defaultDirectory :(bool)canCreateDirectories :(bool)treatPackagesAsDirectories :(bool)showHiddenFiles :(NSString*)filters; +-(void) MessageDialog :(const char*)dialogType :(const char*)title :(const char*)message :(const char*)button1 :(const char*)button2 :(const char*)button3 :(const char*)button4 :(const char*)defaultButton :(const char*)cancelButton; +-(void) OpenFileDialog :(const char*)title :(const char*)defaultFilename :(const char*)defaultDirectory :(bool)allowDirectories :(bool)allowFiles :(bool)canCreateDirectories :(bool)treatPackagesAsDirectories :(bool)resolveAliases :(bool)showHiddenFiles :(bool)allowMultipleSelection :(const char*)filters; +-(void) SaveFileDialog :(const char*)title :(const char*)defaultFilename :(const char*)defaultDirectory :(bool)canCreateDirectories :(bool)treatPackagesAsDirectories :(bool)showHiddenFiles :(const char*)filters; - (void) loadRequest:(NSString*)url; -- (void) ExecJS:(NSString*)script; +- (void) processURLResponse:(NSString *)url :(NSString *)contentType :(NSData*)data; +- (void) ExecJS:(const char*)script; - (NSScreen*) getCurrentScreen; -- (void) SetAbout :(NSString*)title :(NSString*)description :(void*)imagedata :(int)datalen; -- (void) dealloc; - @end diff --git a/v2/internal/frontend/desktop/darwin/WailsContext.m b/v2/internal/frontend/desktop/darwin/WailsContext.m index 7c9660d54..967931f8c 100644 --- a/v2/internal/frontend/desktop/darwin/WailsContext.m +++ b/v2/internal/frontend/desktop/darwin/WailsContext.m @@ -9,13 +9,8 @@ #import #import "WailsContext.h" #import "WailsAlert.h" -#import "WailsMenu.h" -#import "WailsWebView.h" #import "WindowDelegate.h" #import "message.h" -#import "Role.h" - -typedef void (^schemeTaskCaller)(id); @implementation WailsWindow @@ -24,24 +19,14 @@ typedef void (^schemeTaskCaller)(id); return YES; } -- (void) applyWindowConstraints { - [self setMinSize:self.userMinSize]; - [self setMaxSize:self.userMaxSize]; -} - -- (void) disableWindowConstraints { - [self setMinSize:NSMakeSize(0, 0)]; - [self setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)]; -} - @end @implementation WailsContext - (void) SetSize:(int)width :(int)height { - + if (self.shuttingDown) return; - + NSRect frame = [self.mainWindow frame]; frame.origin.y += frame.size.height - height; frame.size.width = width; @@ -50,66 +35,71 @@ typedef void (^schemeTaskCaller)(id); } - (void) SetPosition:(int)x :(int)y { - + if (self.shuttingDown) return; - + NSScreen* screen = [self getCurrentScreen]; NSRect windowFrame = [self.mainWindow frame]; NSRect screenFrame = [screen visibleFrame]; - windowFrame.origin.x = screenFrame.origin.x + (float)x; - windowFrame.origin.y = (screenFrame.origin.y + screenFrame.size.height) - windowFrame.size.height - (float)y; - + windowFrame.origin.x += screenFrame.origin.x + (float)x; + windowFrame.origin.y += (screenFrame.origin.y + screenFrame.size.height) - windowFrame.size.height - (float)y; + [self.mainWindow setFrame:windowFrame display:TRUE animate:FALSE]; } - (void) SetMinSize:(int)minWidth :(int)minHeight { - + if (self.shuttingDown) return; - + NSSize size = { minWidth, minHeight }; - self.mainWindow.userMinSize = size; + + self.minSize = size; + [self.mainWindow setMinSize:size]; + [self adjustWindowSize]; } - (void) SetMaxSize:(int)maxWidth :(int)maxHeight { - + if (self.shuttingDown) return; - + NSSize size = { FLT_MAX, FLT_MAX }; - + size.width = maxWidth > 0 ? maxWidth : FLT_MAX; size.height = maxHeight > 0 ? maxHeight : FLT_MAX; - - self.mainWindow.userMaxSize = size; - [self.mainWindow setMaxSize:size]; + + self.maxSize = size; + + [self.mainWindow setMinSize:size]; + [self adjustWindowSize]; } - (void) adjustWindowSize { - + if (self.shuttingDown) return; - + NSRect currentFrame = [self.mainWindow frame]; - - if ( currentFrame.size.width > self.mainWindow.userMaxSize.width ) currentFrame.size.width = self.mainWindow.userMaxSize.width; - if ( currentFrame.size.width < self.mainWindow.userMinSize.width ) currentFrame.size.width = self.mainWindow.userMinSize.width; - if ( currentFrame.size.height > self.mainWindow.userMaxSize.height ) currentFrame.size.height = self.mainWindow.userMaxSize.height; - if ( currentFrame.size.height < self.mainWindow.userMinSize.height ) currentFrame.size.height = self.mainWindow.userMinSize.height; - - [self.mainWindow setFrame:currentFrame display:YES animate:FALSE]; - + + if ( currentFrame.size.width > self.maxSize.width ) currentFrame.size.width = self.maxSize.width; + if ( currentFrame.size.width < self.minSize.width ) currentFrame.size.width = self.minSize.width; + if ( currentFrame.size.height > self.maxSize.height ) currentFrame.size.height = self.maxSize.height; + if ( currentFrame.size.height < self.minSize.height ) currentFrame.size.height = self.minSize.height; + + [self.mainWindow setFrame:currentFrame display:TRUE animate:FALSE]; + } - (void) dealloc { + [super dealloc]; [self.appdelegate release]; [self.mainWindow release]; [self.mouseEvent release]; [self.userContentController release]; - [self.applicationMenu release]; - [super dealloc]; + [self.urlRequests release]; } - (NSScreen*) getCurrentScreen { @@ -120,57 +110,56 @@ typedef void (^schemeTaskCaller)(id); return screen; } -- (void) SetTitle:(NSString*)title { - [self.mainWindow setTitle:title]; +- (void) SetTitle:(const char *)title { + NSString *_title = [NSString stringWithUTF8String:title]; + [self.mainWindow setTitle:_title]; } - (void) Center { - [self.mainWindow center]; + [self.mainWindow center]; } -- (BOOL) isFullscreen { - NSWindowStyleMask masks = [self.mainWindow styleMask]; - if ( masks & NSWindowStyleMaskFullScreen ) { - return YES; - } - return NO; -} - -- (void) CreateWindow:(int)width :(int)height :(bool)frameless :(bool)resizable :(bool)zoomable :(bool)fullscreen :(bool)fullSizeContent :(bool)hideTitleBar :(bool)titlebarAppearsTransparent :(bool)hideTitle :(bool)useToolbar :(bool)hideToolbarSeparator :(bool)webviewIsTransparent :(bool)hideWindowOnClose :(NSString*)appearance :(bool)windowIsTranslucent :(int)minWidth :(int)minHeight :(int)maxWidth :(int)maxHeight :(bool)fraudulentWebsiteWarningEnabled :(struct Preferences)preferences :(bool)enableDragAndDrop :(bool)disableWebViewDragAndDrop { - NSWindowStyleMask styleMask = 0; - - if( !frameless ) { - if (!hideTitleBar) { - styleMask |= NSWindowStyleMaskTitled; +- (void) CreateWindow:(int)width :(int)height :(bool)frameless :(bool)resizable :(bool)fullscreen :(bool)fullSizeContent :(bool)hideTitleBar :(bool)titlebarAppearsTransparent :(bool)hideTitle :(bool)useToolbar :(bool)hideToolbarSeparator :(bool)webviewIsTransparent :(bool)hideWindowOnClose :(const char *)appearance :(bool)windowIsTranslucent { + + self.urlRequests = [NSMutableDictionary new]; + + NSWindowStyleMask styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable; + + if (frameless) { + styleMask = NSWindowStyleMaskBorderless; + } else { + if (resizable) { + styleMask |= NSWindowStyleMaskResizable; } - styleMask |= NSWindowStyleMaskClosable; } - - styleMask |= NSWindowStyleMaskMiniaturizable; - + if (fullscreen) { + styleMask |= NSWindowStyleMaskFullScreen; + } + if( fullSizeContent || frameless || titlebarAppearsTransparent ) { styleMask |= NSWindowStyleMaskFullSizeContentView; } - - if (resizable) { - styleMask |= NSWindowStyleMaskResizable; + + self.mainWindow = [[[WailsWindow alloc] initWithContentRect:NSMakeRect(0, 0, width, height) + styleMask:styleMask backing:NSBackingStoreBuffered defer:NO] + autorelease]; + + if (frameless) { + return; } - - self.mainWindow = [[WailsWindow alloc] initWithContentRect:NSMakeRect(0, 0, width, height) - styleMask:styleMask backing:NSBackingStoreBuffered defer:NO]; - if (!frameless && useToolbar) { + + if (useToolbar) { + NSLog(@"Using Toolbar"); id toolbar = [[NSToolbar alloc] initWithIdentifier:@"wails.toolbar"]; [toolbar autorelease]; [toolbar setShowsBaselineSeparator:!hideToolbarSeparator]; [self.mainWindow setToolbar:toolbar]; - } - + [self.mainWindow setTitleVisibility:hideTitle]; [self.mainWindow setTitlebarAppearsTransparent:titlebarAppearsTransparent]; - -// [self.mainWindow canBecomeKeyWindow]; - + [self.mainWindow canBecomeKeyWindow]; + id contentView = [self.mainWindow contentView]; if (windowIsTranslucent) { NSVisualEffectView *effectView = [NSVisualEffectView alloc]; @@ -181,115 +170,62 @@ typedef void (^schemeTaskCaller)(id); [effectView setState:NSVisualEffectStateActive]; [contentView addSubview:effectView positioned:NSWindowBelow relativeTo:nil]; } - + if (appearance != nil) { - NSAppearance *nsAppearance = [NSAppearance appearanceNamed:appearance]; + NSString *name = [NSString stringWithUTF8String:appearance]; + NSAppearance *nsAppearance = [NSAppearance appearanceNamed:name]; [self.mainWindow setAppearance:nsAppearance]; } - - if (!zoomable && resizable) { - NSButton *button = [self.mainWindow standardWindowButton:NSWindowZoomButton]; - [button setEnabled: NO]; - } - - - NSSize minSize = { minWidth, minHeight }; - NSSize maxSize = { maxWidth, maxHeight }; - if (maxSize.width == 0) { - maxSize.width = FLT_MAX; - } - if (maxSize.height == 0) { - maxSize.height = FLT_MAX; - } - self.mainWindow.userMaxSize = maxSize; - self.mainWindow.userMinSize = minSize; - - if( !fullscreen ) { - [self.mainWindow applyWindowConstraints]; - } - + + // Set up min/max + NSSize maxSize = { FLT_MAX, FLT_MAX }; + self.maxSize = maxSize; + NSSize minSize = { 0, 0 }; + self.minSize = minSize; + [self adjustWindowSize]; + WindowDelegate *windowDelegate = [WindowDelegate new]; windowDelegate.hideOnClose = hideWindowOnClose; - windowDelegate.ctx = self; [self.mainWindow setDelegate:windowDelegate]; - + // Webview stuff here! WKWebViewConfiguration *config = [WKWebViewConfiguration new]; - // Disable suppressesIncrementalRendering on macOS 26+ to prevent WebView crashes - // during rapid UI updates. See: https://github.com/wailsapp/wails/issues/4592 - if (@available(macOS 26.0, *)) { - config.suppressesIncrementalRendering = false; - } else { - config.suppressesIncrementalRendering = true; - } - config.applicationNameForUserAgent = @"wails.io"; + config.suppressesIncrementalRendering = true; [config setURLSchemeHandler:self forURLScheme:@"wails"]; - - if (preferences.tabFocusesLinks != NULL) { - config.preferences.tabFocusesLinks = *preferences.tabFocusesLinks; - } - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 110300 - if (@available(macOS 11.3, *)) { - if (preferences.textInteractionEnabled != NULL) { - config.preferences.textInteractionEnabled = *preferences.textInteractionEnabled; - } - } -#endif - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 120300 - if (@available(macOS 12.3, *)) { - if (preferences.fullscreenEnabled != NULL) { - config.preferences.elementFullscreenEnabled = *preferences.fullscreenEnabled; - } - } -#endif - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101500 - if (@available(macOS 10.15, *)) { - config.preferences.fraudulentWebsiteWarningEnabled = fraudulentWebsiteWarningEnabled; - } -#endif - + + [config.preferences setValue:[NSNumber numberWithBool:true] forKey:@"developerExtrasEnabled"]; + WKUserContentController* userContentController = [WKUserContentController new]; [userContentController addScriptMessageHandler:self name:@"external"]; config.userContentController = userContentController; self.userContentController = userContentController; - - if (self.devtoolsEnabled) { + if (self.debug) { [config.preferences setValue:@YES forKey:@"developerExtrasEnabled"]; - } - - if (!self.defaultContextMenuEnabled) { + } else { // Disable default context menus WKUserScript *initScript = [WKUserScript new]; - [initScript initWithSource:@"window.wails.flags.disableDefaultContextMenu = true;" + [initScript initWithSource:@"window.wails.flags.disableWailsDefaultContextMenu = true;" injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:false]; [userContentController addUserScript:initScript]; + } - - self.webview = [WailsWebView alloc]; - self.webview.enableDragAndDrop = enableDragAndDrop; - self.webview.disableWebViewDragAndDrop = disableWebViewDragAndDrop; - + + self.webview = [WKWebView alloc]; CGRect init = { 0,0,0,0 }; [self.webview initWithFrame:init configuration:config]; [contentView addSubview:self.webview]; [self.webview setAutoresizingMask: NSViewWidthSizable|NSViewHeightSizable]; CGRect contentViewBounds = [contentView bounds]; [self.webview setFrame:contentViewBounds]; - + if (webviewIsTransparent) { [self.webview setValue:[NSNumber numberWithBool:!webviewIsTransparent] forKey:@"drawsBackground"]; } - - [self.webview setNavigationDelegate:self]; - self.webview.UIDelegate = self; - + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [defaults setBool:FALSE forKey:@"NSAutomaticQuoteSubstitutionEnabled"]; - + // Mouse monitors [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskLeftMouseDown handler:^NSEvent * _Nullable(NSEvent * _Nonnull event) { id window = [event window]; @@ -298,7 +234,7 @@ typedef void (^schemeTaskCaller)(id); } return event; }]; - + [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskLeftMouseUp handler:^NSEvent * _Nullable(NSEvent * _Nonnull event) { id window = [event window]; if (window == self.mainWindow) { @@ -307,31 +243,7 @@ typedef void (^schemeTaskCaller)(id); } return event; }]; - - self.applicationMenu = [NSMenu new]; - -} - -- (NSMenuItem*) newMenuItem :(NSString*)title :(SEL)selector :(NSString*)key :(NSEventModifierFlags)flags { - NSMenuItem *result = [[[NSMenuItem alloc] initWithTitle:title action:selector keyEquivalent:key] autorelease]; - if( flags != 0 ) { - [result setKeyEquivalentModifierMask:flags]; - } - return result; -} - -- (NSMenuItem*) newMenuItem :(NSString*)title :(SEL)selector :(NSString*)key { - return [self newMenuItem :title :selector :key :0]; -} - -- (NSMenu*) newMenu :(NSString*)title { - WailsMenu *result = [[WailsMenu new] initWithTitle:title]; - [result setAutoenablesItems:NO]; - return result; -} - -- (void) Quit { - processMessage("Q"); + } - (void) loadRequest :(NSString*)url { @@ -340,14 +252,14 @@ typedef void (^schemeTaskCaller)(id); [self.webview loadRequest:wkRequest]; } -- (void) SetBackgroundColour:(int)r :(int)g :(int)b :(int)a { - float red = r/255.0; - float green = g/255.0; - float blue = b/255.0; - float alpha = a/255.0; - +- (void) SetRGBA:(int)r :(int)g :(int)b :(int)a { + float red = r/255; + float green = g/255; + float blue = b/255; + float alpha = a/255; + id colour = [NSColor colorWithCalibratedRed:red green:green blue:blue alpha:alpha ]; - + [self.mainWindow setBackgroundColor:colour]; } @@ -359,23 +271,21 @@ typedef void (^schemeTaskCaller)(id); [NSCursor unhide]; } -- (bool) IsFullScreen { +- (bool) isFullScreen { long mask = [self.mainWindow styleMask]; return (mask & NSWindowStyleMaskFullScreen) == NSWindowStyleMaskFullScreen; } // Fullscreen sets the main window to be fullscreen - (void) Fullscreen { - if( ! [self IsFullScreen] ) { - [self.mainWindow disableWindowConstraints]; + if( ! [self isFullScreen] ) { [self.mainWindow toggleFullScreen:nil]; } } // UnFullscreen resets the main window after a fullscreen - (void) UnFullscreen { - if( [self IsFullScreen] ) { - [self.mainWindow applyWindowConstraints]; + if( [self isFullScreen] ) { [self.mainWindow toggleFullScreen:nil]; } } @@ -388,10 +298,6 @@ typedef void (^schemeTaskCaller)(id); [self.mainWindow deminiaturize:nil]; } -- (bool) IsMinimised { - return [self.mainWindow isMiniaturized]; -} - - (void) Hide { [self.mainWindow orderOut:nil]; } @@ -401,156 +307,99 @@ typedef void (^schemeTaskCaller)(id); [NSApp activateIgnoringOtherApps:YES]; } -- (void) HideApplication { - [[NSApplication sharedApplication] hide:self]; -} - -- (void) ShowApplication { - [[NSApplication sharedApplication] unhide:self]; - [[NSApplication sharedApplication] activateIgnoringOtherApps:TRUE]; - -} - - (void) Maximise { - if (![self.mainWindow isZoomed]) { + if (! self.maximised) { [self.mainWindow zoom:nil]; } } -- (void) ToggleMaximise { - [self.mainWindow zoom:nil]; -} - - (void) UnMaximise { - if ([self.mainWindow isZoomed]) { + if (self.maximised) { [self.mainWindow zoom:nil]; } } -- (void) SetAlwaysOnTop:(int)onTop { - if (onTop) { - [self.mainWindow setLevel:NSFloatingWindowLevel]; - } else { - [self.mainWindow setLevel:NSNormalWindowLevel]; - } +- (void) ExecJS:(const char*)script { + NSString *nsscript = [NSString stringWithUTF8String:script]; + [self.webview evaluateJavaScript:nsscript completionHandler:nil]; } -- (bool) IsMaximised { - return [self.mainWindow isZoomed]; -} - -- (void) ExecJS:(NSString*)script { - [self.webview evaluateJavaScript:script completionHandler:nil]; -} - -- (void)webView:(WKWebView *)webView runOpenPanelWithParameters:(WKOpenPanelParameters *)parameters - initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSArray * URLs))completionHandler { - - NSOpenPanel *openPanel = [NSOpenPanel openPanel]; - openPanel.allowsMultipleSelection = parameters.allowsMultipleSelection; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101400 - if (@available(macOS 10.14, *)) { - openPanel.canChooseDirectories = parameters.allowsDirectories; - } -#endif - [openPanel - beginSheetModalForWindow:webView.window - completionHandler:^(NSInteger result) { - if (result == NSModalResponseOK) - completionHandler(openPanel.URLs); - else - completionHandler(nil); - }]; +- (void) processURLResponse:(NSString *)url :(NSString *)contentType :(NSData *)data { + id urlSchemeTask = self.urlRequests[url]; + NSURL *nsurl = [NSURL URLWithString:url]; + + NSHTTPURLResponse *response = [NSHTTPURLResponse new]; + NSMutableDictionary *headerFields = [NSMutableDictionary new]; + headerFields[@"content-type"] = contentType; + [response initWithURL:nsurl statusCode:200 HTTPVersion:@"HTTP/1.1" headerFields:headerFields]; + [urlSchemeTask didReceiveResponse:response]; + [urlSchemeTask didReceiveData:data]; + [urlSchemeTask didFinish]; + [self.urlRequests removeObjectForKey:url]; } - (void)webView:(nonnull WKWebView *)webView startURLSchemeTask:(nonnull id)urlSchemeTask { - // This callback is run with an autorelease pool - processURLRequest(self, urlSchemeTask); + // Do something + self.urlRequests[urlSchemeTask.request.URL.absoluteString] = urlSchemeTask; + processURLRequest(self, [urlSchemeTask.request.URL.absoluteString UTF8String]); } - (void)webView:(nonnull WKWebView *)webView stopURLSchemeTask:(nonnull id)urlSchemeTask { - NSInputStream *stream = urlSchemeTask.request.HTTPBodyStream; - if (stream) { - NSStreamStatus status = stream.streamStatus; - if (status != NSStreamStatusClosed && status != NSStreamStatusNotOpen) { - [stream close]; - } - } -} - -- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation { - processMessage("DomReady"); + } - (void)userContentController:(nonnull WKUserContentController *)userContentController didReceiveScriptMessage:(nonnull WKScriptMessage *)message { - // Get the origin from the message's frame - NSString *origin = nil; - if (message.frameInfo && message.frameInfo.request && message.frameInfo.request.URL) { - NSURL *url = message.frameInfo.request.URL; - if (url.scheme && url.host) { - origin = [url absoluteString]; - } - } - NSString *m = message.body; - + // Check for drag if ( [m isEqualToString:@"drag"] ) { - if( [self IsFullScreen] ) { + if( ! [self isFullScreen] ) { + if( self.mouseEvent != nil ) { + [self HideMouse]; + ON_MAIN_THREAD( + [self.mainWindow performWindowDragWithEvent:self.mouseEvent]; + ); + } return; } - if( self.mouseEvent != nil ) { - [self.mainWindow performWindowDragWithEvent:self.mouseEvent]; - } - return; } - + const char *_m = [m UTF8String]; - const char *_origin = [origin UTF8String]; - - processBindingMessage(_m, _origin, message.frameInfo.isMainFrame); + + processMessage(_m); } + /***** Dialogs ******/ --(void) MessageDialog :(NSString*)dialogType :(NSString*)title :(NSString*)message :(NSString*)button1 :(NSString*)button2 :(NSString*)button3 :(NSString*)button4 :(NSString*)defaultButton :(NSString*)cancelButton :(void*)iconData :(int)iconDataLength { +-(void) MessageDialog :(const char*)dialogType :(const char*)title :(const char*)message :(const char*)button1 :(const char*)button2 :(const char*)button3 :(const char*)button4 :(const char*)defaultButton :(const char*)cancelButton { WailsAlert *alert = [WailsAlert new]; - + int style = NSAlertStyleInformational; if (dialogType != nil ) { - if( [dialogType isEqualToString:@"warning"] ) { + if( strcmp(dialogType, "warning") == 0 ) { style = NSAlertStyleWarning; } - if( [dialogType isEqualToString:@"error"] ) { + if( strcmp(dialogType, "error") == 0) { style = NSAlertStyleCritical; } } [alert setAlertStyle:style]; - if( title != nil ) { - [alert setMessageText:title]; + if( strlen(title) > 0 ) { + [alert setMessageText:[NSString stringWithUTF8String:title]]; } - if( message != nil ) { - [alert setInformativeText:message]; + if( strlen(message) > 0 ) { + [alert setInformativeText:[NSString stringWithUTF8String:message]]; } - + [alert addButton:button1 :defaultButton :cancelButton]; [alert addButton:button2 :defaultButton :cancelButton]; [alert addButton:button3 :defaultButton :cancelButton]; [alert addButton:button4 :defaultButton :cancelButton]; - - NSImage *icon = nil; - if (iconData != nil) { - NSData *imageData = [NSData dataWithBytes:iconData length:iconDataLength]; - icon = [[NSImage alloc] initWithData:imageData]; - } - if( icon != nil) { - [alert setIcon:icon]; - } - [alert.window setLevel:NSFloatingWindowLevel]; - + long response = [alert runModal]; int result; - + if( response == NSAlertFirstButtonReturn ) { result = 0; } @@ -565,56 +414,40 @@ typedef void (^schemeTaskCaller)(id); processMessageDialogResponse(result); } --(void) OpenFileDialog :(NSString*)title :(NSString*)defaultFilename :(NSString*)defaultDirectory :(bool)allowDirectories :(bool)allowFiles :(bool)canCreateDirectories :(bool)treatPackagesAsDirectories :(bool)resolveAliases :(bool)showHiddenFiles :(bool)allowMultipleSelection :(NSString*)filters { - - +-(void) OpenFileDialog :(const char*)title :(const char*)defaultFilename :(const char*)defaultDirectory :(bool)allowDirectories :(bool)allowFiles :(bool)canCreateDirectories :(bool)treatPackagesAsDirectories :(bool)resolveAliases :(bool)showHiddenFiles :(bool)allowMultipleSelection :(const char*)filters { + + // Create the dialog NSOpenPanel *dialog = [NSOpenPanel openPanel]; // Valid but appears to do nothing.... :/ - if( title != nil ) { - [dialog setTitle:title]; + if( strlen(title) > 0 ) { + [dialog setTitle:[NSString stringWithUTF8String:title]]; } // Filters - semicolon delimited list of file extensions if( allowFiles ) { - if( filters != nil && [filters length] > 0) { - filters = [filters stringByReplacingOccurrencesOfString:@"*." withString:@""]; - filters = [filters stringByReplacingOccurrencesOfString:@" " withString:@""]; - NSArray *filterList = [filters componentsSeparatedByString:@";"]; -#ifdef USE_NEW_FILTERS - NSMutableArray *contentTypes = [[NSMutableArray new] autorelease]; - for (NSString *filter in filterList) { -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 110000 - if (@available(macOS 11.0, *)) { - UTType *t = [UTType typeWithFilenameExtension:filter]; - [contentTypes addObject:t]; - } -#endif - } -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 110000 - if (@available(macOS 11.0, *)) { - [dialog setAllowedContentTypes:contentTypes]; - } -#endif -#else - [dialog setAllowedFileTypes:filterList]; -#endif + if( filters != nil && strlen(filters) > 0) { + NSString *filterString = [[NSString stringWithUTF8String:filters] stringByReplacingOccurrencesOfString:@"*." withString:@""]; + filterString = [filterString stringByReplacingOccurrencesOfString:@" " withString:@""]; + NSArray *filterList = [filterString componentsSeparatedByString:@";"]; + [dialog setAllowedFileTypes:filterList]; } else { [dialog setAllowsOtherFileTypes:true]; } // Default Filename - if( defaultFilename != nil ) { - [dialog setNameFieldStringValue:defaultFilename]; + if( defaultFilename != NULL && strlen(defaultFilename) > 0 ) { + [dialog setNameFieldStringValue:[NSString stringWithUTF8String:defaultFilename]]; } - + [dialog setAllowsMultipleSelection: allowMultipleSelection]; + [dialog setShowsHiddenFiles: showHiddenFiles]; + } - [dialog setShowsHiddenFiles: showHiddenFiles]; // Default Directory - if( defaultDirectory != nil ) { - NSURL *url = [NSURL fileURLWithPath:defaultDirectory]; + if( defaultDirectory != NULL && strlen(defaultDirectory) > 0 ) { + NSURL *url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:defaultDirectory]]; [dialog setDirectoryURL:url]; } @@ -628,10 +461,6 @@ typedef void (^schemeTaskCaller)(id); // Setup callback handler [dialog beginSheetModalForWindow:self.mainWindow completionHandler:^(NSModalResponse returnCode) { - if ( returnCode != NSModalResponseOK) { - processOpenFileDialogResponse("[]"); - return; - } NSMutableArray *arr = [NSMutableArray new]; for (NSURL *url in [dialog URLs]) { [arr addObject:[url path]]; @@ -639,117 +468,60 @@ typedef void (^schemeTaskCaller)(id); NSData *jsonData = [NSJSONSerialization dataWithJSONObject:arr options:0 error:nil]; NSString *nsjson = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; processOpenFileDialogResponse([nsjson UTF8String]); - [nsjson release]; - [arr release]; }]; + + [dialog runModal]; + } --(void) SaveFileDialog :(NSString*)title :(NSString*)defaultFilename :(NSString*)defaultDirectory :(bool)canCreateDirectories :(bool)treatPackagesAsDirectories :(bool)showHiddenFiles :(NSString*)filters; { - - +-(void) SaveFileDialog :(const char*)title :(const char*)defaultFilename :(const char*)defaultDirectory :(bool)canCreateDirectories :(bool)treatPackagesAsDirectories :(bool)showHiddenFiles :(const char*)filters; { + + // Create the dialog - NSSavePanel *dialog = [NSSavePanel savePanel]; - - // Do not hide extension - [dialog setExtensionHidden:false]; + NSSavePanel *dialog = [NSOpenPanel savePanel]; // Valid but appears to do nothing.... :/ - if( title != nil ) { - [dialog setTitle:title]; + if( strlen(title) > 0 ) { + [dialog setTitle:[NSString stringWithUTF8String:title]]; } // Filters - semicolon delimited list of file extensions - if( filters != nil && [filters length] > 0) { - filters = [filters stringByReplacingOccurrencesOfString:@"*." withString:@""]; - filters = [filters stringByReplacingOccurrencesOfString:@" " withString:@""]; - NSArray *filterList = [filters componentsSeparatedByString:@";"]; -#ifdef USE_NEW_FILTERS - NSMutableArray *contentTypes = [[NSMutableArray new] autorelease]; - for (NSString *filter in filterList) { -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 110000 - if (@available(macOS 11.0, *)) { - UTType *t = [UTType typeWithFilenameExtension:filter]; - [contentTypes addObject:t]; - } -#endif - } - if( contentTypes.count == 0) { - [dialog setAllowsOtherFileTypes:true]; - } else { -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 110000 - if (@available(macOS 11.0, *)) { - [dialog setAllowedContentTypes:contentTypes]; - } -#endif - } - -#else - [dialog setAllowedFileTypes:filterList]; -#endif + if( filters != nil && strlen(filters) > 0) { + NSString *filterString = [[NSString stringWithUTF8String:filters] stringByReplacingOccurrencesOfString:@"*." withString:@""]; + filterString = [filterString stringByReplacingOccurrencesOfString:@" " withString:@""]; + NSArray *filterList = [filterString componentsSeparatedByString:@";"]; + [dialog setAllowedFileTypes:filterList]; } else { [dialog setAllowsOtherFileTypes:true]; } // Default Filename - if( defaultFilename != nil ) { - [dialog setNameFieldStringValue:defaultFilename]; + if( defaultFilename != NULL && strlen(defaultFilename) > 0 ) { + [dialog setNameFieldStringValue:[NSString stringWithUTF8String:defaultFilename]]; } - + // Default Directory - if( defaultDirectory != nil ) { - NSURL *url = [NSURL fileURLWithPath:defaultDirectory]; + if( defaultDirectory != NULL && strlen(defaultDirectory) > 0 ) { + NSURL *url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:defaultDirectory]]; [dialog setDirectoryURL:url]; } // Setup Options - [dialog setCanSelectHiddenExtension:true]; -// dialog.isExtensionHidden = false; [dialog setCanCreateDirectories: canCreateDirectories]; [dialog setTreatsFilePackagesAsDirectories: treatPackagesAsDirectories]; [dialog setShowsHiddenFiles: showHiddenFiles]; // Setup callback handler [dialog beginSheetModalForWindow:self.mainWindow completionHandler:^(NSModalResponse returnCode) { - if ( returnCode == NSModalResponseOK ) { - NSURL *url = [dialog URL]; - if ( url != nil ) { - processSaveFileDialogResponse([url.path UTF8String]); - return; - } - } - processSaveFileDialogResponse(""); + NSURL *url = [dialog URL]; + processSaveFileDialogResponse([url.path UTF8String]); }]; - + + [dialog runModal]; + } -- (void) SetAbout :(NSString*)title :(NSString*)description :(void*)imagedata :(int)datalen { - self.aboutTitle = title; - self.aboutDescription = description; - - NSData *imageData = [NSData dataWithBytes:imagedata length:datalen]; - self.aboutImage = [[NSImage alloc] initWithData:imageData]; -} - --(void) About { - - WailsAlert *alert = [WailsAlert new]; - [alert setAlertStyle:NSAlertStyleInformational]; - if( self.aboutTitle != nil ) { - [alert setMessageText:self.aboutTitle]; - } - if( self.aboutDescription != nil ) { - [alert setInformativeText:self.aboutDescription]; - } - - - [alert.window setLevel:NSFloatingWindowLevel]; - if ( self.aboutImage != nil) { - [alert setIcon:self.aboutImage]; - } - - [alert runModal]; -} @end diff --git a/v2/internal/frontend/desktop/darwin/WailsMenu.h b/v2/internal/frontend/desktop/darwin/WailsMenu.h deleted file mode 100644 index 8ef120356..000000000 --- a/v2/internal/frontend/desktop/darwin/WailsMenu.h +++ /dev/null @@ -1,30 +0,0 @@ -// -// WailsMenu.h -// test -// -// Created by Lea Anthony on 25/10/21. -// - -#ifndef WailsMenu_h -#define WailsMenu_h - -#import -#import "Role.h" -#import "WailsMenu.h" -#import "WailsContext.h" - -@interface WailsMenu : NSMenu - -//- (void) AddMenuByRole :(Role)role; -- (WailsMenu*) initWithNSTitle :(NSString*)title; -- (void) appendSubmenu :(WailsMenu*)child; -- (void) appendRole :(WailsContext*)ctx :(Role)role; - -- (NSMenuItem*) newMenuItemWithContext :(WailsContext*)ctx :(NSString*)title :(SEL)selector :(NSString*)key :(NSEventModifierFlags)flags; -- (void*) AppendMenuItem :(WailsContext*)ctx :(NSString*)label :(NSString *)shortcutKey :(int)modifiers :(bool)disabled :(bool)checked :(int)menuItemID; -- (void) AppendSeparator; - -@end - - -#endif /* WailsMenu_h */ diff --git a/v2/internal/frontend/desktop/darwin/WailsMenu.m b/v2/internal/frontend/desktop/darwin/WailsMenu.m deleted file mode 100644 index 66e5dd399..000000000 --- a/v2/internal/frontend/desktop/darwin/WailsMenu.m +++ /dev/null @@ -1,340 +0,0 @@ -//go:build darwin -// -// WailsMenu.m -// test -// -// Created by Lea Anthony on 25/10/21. -// - -#import -#import "WailsMenu.h" -#import "WailsMenuItem.h" -#import "Role.h" - -@implementation WailsMenu - -- (NSMenuItem*) newMenuItem :(NSString*)title :(SEL)selector :(NSString*)key :(NSEventModifierFlags)flags { - NSMenuItem *result = [[[NSMenuItem alloc] initWithTitle:title action:selector keyEquivalent:key] autorelease]; - [result setKeyEquivalentModifierMask:flags]; - return result; -} - -- (NSMenuItem*) newMenuItemWithContext :(WailsContext*)ctx :(NSString*)title :(SEL)selector :(NSString*)key :(NSEventModifierFlags)flags { - NSMenuItem *result = [NSMenuItem new]; - if ( title != nil ) { - [result setTitle:title]; - } - if (selector != nil) { - [result setAction:selector]; - } - if (key) { - [result setKeyEquivalent:key]; - } - if( flags != 0 ) { - [result setKeyEquivalentModifierMask:flags]; - } - result.target = ctx; - return result; -} - -- (NSMenuItem*) newMenuItem :(NSString*)title :(SEL)selector :(NSString*)key { - return [self newMenuItem :title :selector :key :0]; -} - -- (WailsMenu*) initWithNSTitle:(NSString *)title { - if( title != nil ) { - [super initWithTitle:title]; - } else { - [self init]; - } - [self setAutoenablesItems:NO]; - return self; -} - -- (void) appendSubmenu :(WailsMenu*)child { - NSMenuItem *childMenuItem = [[NSMenuItem new] autorelease]; - [childMenuItem setTitle:child.title]; - [self addItem:childMenuItem]; - [childMenuItem setSubmenu:child]; -} - -- (void) appendRole :(WailsContext*)ctx :(Role)role { - - switch(role) { - case AppMenu: - { - NSString *appName = [NSRunningApplication currentApplication].localizedName; - if( appName == nil ) { - appName = [[NSProcessInfo processInfo] processName]; - } - WailsMenu *appMenu = [[[WailsMenu new] initWithNSTitle:appName] autorelease]; - - if (ctx.aboutTitle != nil) { - [appMenu addItem:[self newMenuItemWithContext :ctx :[@"About " stringByAppendingString:appName] :@selector(About) :nil :0]]; - [appMenu addItem:[NSMenuItem separatorItem]]; - } - - [appMenu addItem:[self newMenuItem:[@"Hide " stringByAppendingString:appName] :@selector(hide:) :@"h" :NSEventModifierFlagCommand]]; - [appMenu addItem:[self newMenuItem:@"Hide Others" :@selector(hideOtherApplications:) :@"h" :(NSEventModifierFlagOption | NSEventModifierFlagCommand)]]; - [appMenu addItem:[self newMenuItem:@"Show All" :@selector(unhideAllApplications:) :@""]]; - [appMenu addItem:[NSMenuItem separatorItem]]; - - id quitTitle = [@"Quit " stringByAppendingString:appName]; - NSMenuItem* quitMenuItem = [self newMenuItem:quitTitle :@selector(Quit) :@"q" :NSEventModifierFlagCommand]; - quitMenuItem.target = ctx; - [appMenu addItem:quitMenuItem]; - [self appendSubmenu:appMenu]; - break; - } - case EditMenu: - { - WailsMenu *editMenu = [[[WailsMenu new] initWithNSTitle:@"Edit"] autorelease]; - [editMenu addItem:[self newMenuItem:@"Undo" :@selector(undo:) :@"z" :NSEventModifierFlagCommand]]; - [editMenu addItem:[self newMenuItem:@"Redo" :@selector(redo:) :@"z" :(NSEventModifierFlagShift | NSEventModifierFlagCommand)]]; - [editMenu addItem:[NSMenuItem separatorItem]]; - [editMenu addItem:[self newMenuItem:@"Cut" :@selector(cut:) :@"x" :NSEventModifierFlagCommand]]; - [editMenu addItem:[self newMenuItem:@"Copy" :@selector(copy:) :@"c" :NSEventModifierFlagCommand]]; - [editMenu addItem:[self newMenuItem:@"Paste" :@selector(paste:) :@"v" :NSEventModifierFlagCommand]]; - [editMenu addItem:[self newMenuItem:@"Paste and Match Style" :@selector(pasteAsRichText:) :@"v" :(NSEventModifierFlagOption | NSEventModifierFlagShift | NSEventModifierFlagCommand)]]; - [editMenu addItem:[self newMenuItem:@"Delete" :@selector(delete:) :[self accel:@"backspace"] :0]]; - [editMenu addItem:[self newMenuItem:@"Select All" :@selector(selectAll:) :@"a" :NSEventModifierFlagCommand]]; - [editMenu addItem:[NSMenuItem separatorItem]]; -// NSMenuItem *speechMenuItem = [[NSMenuItem new] autorelease]; -// [speechMenuItem setTitle:@"Speech"]; -// [editMenu addItem:speechMenuItem]; - WailsMenu *speechMenu = [[[WailsMenu new] initWithNSTitle:@"Speech"] autorelease]; - [speechMenu addItem:[self newMenuItem:@"Start Speaking" :@selector(startSpeaking:) :@""]]; - [speechMenu addItem:[self newMenuItem:@"Stop Speaking" :@selector(stopSpeaking:) :@""]]; - [editMenu appendSubmenu:speechMenu]; - [self appendSubmenu:editMenu]; - - break; - } - case WindowMenu: - { - WailsMenu *windowMenu = [[[WailsMenu new] initWithNSTitle:@"Window"] autorelease]; - [windowMenu addItem:[self newMenuItem:@"Minimize" :@selector(performMiniaturize:) :@"m" :NSEventModifierFlagCommand]]; - [windowMenu addItem:[self newMenuItem:@"Zoom" :@selector(performZoom:) :@""]]; - [windowMenu addItem:[NSMenuItem separatorItem]]; - [windowMenu addItem:[self newMenuItem:@"Full Screen" :@selector(enterFullScreenMode:) :@"f" :(NSEventModifierFlagControl | NSEventModifierFlagCommand)]]; - [self appendSubmenu:windowMenu]; - - break; - } - } -} - -- (void*) AppendMenuItem :(WailsContext*)ctx :(NSString*)label :(NSString *)shortcutKey :(int)modifiers :(bool)disabled :(bool)checked :(int)menuItemID { - - NSString *nslabel = @""; - if (label != nil ) { - nslabel = label; - } - WailsMenuItem *menuItem = [WailsMenuItem new]; - - // Label - menuItem.title = nslabel; - - // Process callback - menuItem.menuItemID = menuItemID; - menuItem.action = @selector(handleClick); - menuItem.target = menuItem; - - // Shortcut - if (shortcutKey != nil) { - [menuItem setKeyEquivalent:[self accel:shortcutKey]]; - [menuItem setKeyEquivalentModifierMask:modifiers]; - } - - // Enabled/Disabled - [menuItem setEnabled:!disabled]; - - // Checked - [menuItem setState:(checked ? NSControlStateValueOn : NSControlStateValueOff)]; - - [self addItem:menuItem]; - return menuItem; -} - -- (void) AppendSeparator { - [self addItem:[NSMenuItem separatorItem]]; -} - - -- (NSString*) accel :(NSString*)key { - - // Guard against no accelerator key - if( key == NULL ) { - return @""; - } - - if( [key isEqualToString:@"backspace"] ) { - return unicode(0x0008); - } - if( [key isEqualToString:@"tab"] ) { - return unicode(0x0009); - } - if( [key isEqualToString:@"return"] ) { - return unicode(0x000d); - } - if( [key isEqualToString:@"enter"] ) { - return unicode(0x000d); - } - if( [key isEqualToString:@"escape"] ) { - return unicode(0x001b); - } - if( [key isEqualToString:@"left"] ) { - return unicode(0x001c); - } - if( [key isEqualToString:@"right"] ) { - return unicode(0x001d); - } - if( [key isEqualToString:@"up"] ) { - return unicode(0x001e); - } - if( [key isEqualToString:@"down"] ) { - return unicode(0x001f); - } - if( [key isEqualToString:@"space"] ) { - return unicode(0x0020); - } - if( [key isEqualToString:@"delete"] ) { - return unicode(0x007f); - } - if( [key isEqualToString:@"home"] ) { - return unicode(0x2196); - } - if( [key isEqualToString:@"end"] ) { - return unicode(0x2198); - } - if( [key isEqualToString:@"page up"] ) { - return unicode(0x21de); - } - if( [key isEqualToString:@"page down"] ) { - return unicode(0x21df); - } - if( [key isEqualToString:@"f1"] ) { - return unicode(0xf704); - } - if( [key isEqualToString:@"f2"] ) { - return unicode(0xf705); - } - if( [key isEqualToString:@"f3"] ) { - return unicode(0xf706); - } - if( [key isEqualToString:@"f4"] ) { - return unicode(0xf707); - } - if( [key isEqualToString:@"f5"] ) { - return unicode(0xf708); - } - if( [key isEqualToString:@"f6"] ) { - return unicode(0xf709); - } - if( [key isEqualToString:@"f7"] ) { - return unicode(0xf70a); - } - if( [key isEqualToString:@"f8"] ) { - return unicode(0xf70b); - } - if( [key isEqualToString:@"f9"] ) { - return unicode(0xf70c); - } - if( [key isEqualToString:@"f10"] ) { - return unicode(0xf70d); - } - if( [key isEqualToString:@"f11"] ) { - return unicode(0xf70e); - } - if( [key isEqualToString:@"f12"] ) { - return unicode(0xf70f); - } - if( [key isEqualToString:@"f13"] ) { - return unicode(0xf710); - } - if( [key isEqualToString:@"f14"] ) { - return unicode(0xf711); - } - if( [key isEqualToString:@"f15"] ) { - return unicode(0xf712); - } - if( [key isEqualToString:@"f16"] ) { - return unicode(0xf713); - } - if( [key isEqualToString:@"f17"] ) { - return unicode(0xf714); - } - if( [key isEqualToString:@"f18"] ) { - return unicode(0xf715); - } - if( [key isEqualToString:@"f19"] ) { - return unicode(0xf716); - } - if( [key isEqualToString:@"f20"] ) { - return unicode(0xf717); - } - if( [key isEqualToString:@"f21"] ) { - return unicode(0xf718); - } - if( [key isEqualToString:@"f22"] ) { - return unicode(0xf719); - } - if( [key isEqualToString:@"f23"] ) { - return unicode(0xf71a); - } - if( [key isEqualToString:@"f24"] ) { - return unicode(0xf71b); - } - if( [key isEqualToString:@"f25"] ) { - return unicode(0xf71c); - } - if( [key isEqualToString:@"f26"] ) { - return unicode(0xf71d); - } - if( [key isEqualToString:@"f27"] ) { - return unicode(0xf71e); - } - if( [key isEqualToString:@"f28"] ) { - return unicode(0xf71f); - } - if( [key isEqualToString:@"f29"] ) { - return unicode(0xf720); - } - if( [key isEqualToString:@"f30"] ) { - return unicode(0xf721); - } - if( [key isEqualToString:@"f31"] ) { - return unicode(0xf722); - } - if( [key isEqualToString:@"f32"] ) { - return unicode(0xf723); - } - if( [key isEqualToString:@"f33"] ) { - return unicode(0xf724); - } - if( [key isEqualToString:@"f34"] ) { - return unicode(0xf725); - } - if( [key isEqualToString:@"f35"] ) { - return unicode(0xf726); - } -// if( [key isEqualToString:@"Insert"] ) { -// return unicode(0xf727); -// } -// if( [key isEqualToString:@"PrintScreen"] ) { -// return unicode(0xf72e); -// } -// if( [key isEqualToString:@"ScrollLock"] ) { -// return unicode(0xf72f); -// } - if( [key isEqualToString:@"numLock"] ) { - return unicode(0xf739); - } - - return key; -} - - -@end - - diff --git a/v2/internal/frontend/desktop/darwin/WailsMenuItem.h b/v2/internal/frontend/desktop/darwin/WailsMenuItem.h deleted file mode 100644 index 278bac80f..000000000 --- a/v2/internal/frontend/desktop/darwin/WailsMenuItem.h +++ /dev/null @@ -1,22 +0,0 @@ -// -// WailsMenuItem.h -// test -// -// Created by Lea Anthony on 27/10/21. -// - -#ifndef WailsMenuItem_h -#define WailsMenuItem_h - -#import - -@interface WailsMenuItem : NSMenuItem - -@property int menuItemID; - -- (void) handleClick; - -@end - - -#endif /* WailsMenuItem_h */ diff --git a/v2/internal/frontend/desktop/darwin/WailsMenuItem.m b/v2/internal/frontend/desktop/darwin/WailsMenuItem.m deleted file mode 100644 index a34a67239..000000000 --- a/v2/internal/frontend/desktop/darwin/WailsMenuItem.m +++ /dev/null @@ -1,21 +0,0 @@ -//go:build darwin -// -// WailsMenuItem.m -// test -// -// Created by Lea Anthony on 27/10/21. -// - -#import - -#import "WailsMenuItem.h" -#include "message.h" - - -@implementation WailsMenuItem - -- (void) handleClick { - processCallback(self.menuItemID); -} - -@end diff --git a/v2/internal/frontend/desktop/darwin/WailsWebView.h b/v2/internal/frontend/desktop/darwin/WailsWebView.h deleted file mode 100644 index b6f746cf2..000000000 --- a/v2/internal/frontend/desktop/darwin/WailsWebView.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef WailsWebView_h -#define WailsWebView_h - -#import -#import - -// We will override WKWebView, so we can detect file drop in obj-c -// and grab their file path, to then inject into JS -@interface WailsWebView : WKWebView -@property bool disableWebViewDragAndDrop; -@property bool enableDragAndDrop; -@end - -#endif /* WailsWebView_h */ diff --git a/v2/internal/frontend/desktop/darwin/WailsWebView.m b/v2/internal/frontend/desktop/darwin/WailsWebView.m deleted file mode 100644 index de23ac794..000000000 --- a/v2/internal/frontend/desktop/darwin/WailsWebView.m +++ /dev/null @@ -1,122 +0,0 @@ -#import "WailsWebView.h" -#import "message.h" - - -@implementation WailsWebView -@synthesize disableWebViewDragAndDrop; -@synthesize enableDragAndDrop; - -- (BOOL)prepareForDragOperation:(id)sender -{ - if ( !enableDragAndDrop ) { - return [super prepareForDragOperation: sender]; - } - - if ( disableWebViewDragAndDrop ) { - return YES; - } - - return [super prepareForDragOperation: sender]; -} - -- (BOOL)performDragOperation:(id )sender -{ - if ( !enableDragAndDrop ) { - return [super performDragOperation: sender]; - } - - NSPasteboard *pboard = [sender draggingPasteboard]; - - // if no types, then we'll just let the WKWebView handle the drag-n-drop as normal - NSArray * types = [pboard types]; - if( !types ) - return [super performDragOperation: sender]; - - // getting all NSURL types - NSArray *url_class = @[[NSURL class]]; - NSDictionary *options = @{}; - NSArray *files = [pboard readObjectsForClasses:url_class options:options]; - - // collecting all file paths - NSMutableArray *files_strs = [[NSMutableArray alloc] init]; - for (NSURL *url in files) - { - const char *fs_path = [url fileSystemRepresentation]; //Will be UTF-8 encoded - NSString *fs_path_str = [[NSString alloc] initWithCString:fs_path encoding:NSUTF8StringEncoding]; - [files_strs addObject:fs_path_str]; -// NSLog( @"performDragOperation: file path: %s", fs_path ); - } - - NSString *joined=[files_strs componentsJoinedByString:@"\n"]; - - // Release the array of file paths - [files_strs release]; - - int dragXLocation = [sender draggingLocation].x - [self frame].origin.x; - int dragYLocation = [self frame].size.height - [sender draggingLocation].y; // Y coordinate is inverted, so we need to subtract from the height - -// NSLog( @"draggingUpdated: X coord: %d", dragXLocation ); -// NSLog( @"draggingUpdated: Y coord: %d", dragYLocation ); - - NSString *message = [NSString stringWithFormat:@"DD:%d:%d:%@", dragXLocation, dragYLocation, joined]; - - const char* res = message.UTF8String; - - processMessage(res); - - if ( disableWebViewDragAndDrop ) { - return YES; - } - - return [super performDragOperation: sender]; -} - -- (NSDragOperation)draggingUpdated:(id )sender { - if ( !enableDragAndDrop ) { - return [super draggingUpdated: sender]; - } - - NSPasteboard *pboard = [sender draggingPasteboard]; - - // if no types, then we'll just let the WKWebView handle the drag-n-drop as normal - NSArray * types = [pboard types]; - if( !types ) { - return [super draggingUpdated: sender]; - } - - if ( disableWebViewDragAndDrop ) { - // we should call supper as otherwise events will not pass - [super draggingUpdated: sender]; - - // pass NSDragOperationGeneric = 4 to show regular hover for drag and drop. As we want to ignore webkit behaviours that depends on webpage - return 4; - } - - return [super draggingUpdated: sender]; -} - -- (NSDragOperation)draggingEntered:(id )sender { - if ( !enableDragAndDrop ) { - return [super draggingEntered: sender]; - } - - NSPasteboard *pboard = [sender draggingPasteboard]; - - // if no types, then we'll just let the WKWebView handle the drag-n-drop as normal - NSArray * types = [pboard types]; - if( !types ) { - return [super draggingEntered: sender]; - } - - if ( disableWebViewDragAndDrop ) { - // we should call supper as otherwise events will not pass - [super draggingEntered: sender]; - - // pass NSDragOperationGeneric = 4 to show regular hover for drag and drop. As we want to ignore webkit behaviours that depends on webpage - return 4; - } - - return [super draggingEntered: sender]; -} - -@end diff --git a/v2/internal/frontend/desktop/darwin/WindowDelegate.h b/v2/internal/frontend/desktop/darwin/WindowDelegate.h index 6f83e0e48..e4ba038d1 100644 --- a/v2/internal/frontend/desktop/darwin/WindowDelegate.h +++ b/v2/internal/frontend/desktop/darwin/WindowDelegate.h @@ -8,17 +8,10 @@ #ifndef WindowDelegate_h #define WindowDelegate_h -#import "WailsContext.h" - @interface WindowDelegate : NSObject @property bool hideOnClose; -@property (assign) WailsContext* ctx; - -- (void)windowDidExitFullScreen:(NSNotification *)notification; - - @end diff --git a/v2/internal/frontend/desktop/darwin/WindowDelegate.m b/v2/internal/frontend/desktop/darwin/WindowDelegate.m index 915f12853..549413e45 100644 --- a/v2/internal/frontend/desktop/darwin/WindowDelegate.m +++ b/v2/internal/frontend/desktop/darwin/WindowDelegate.m @@ -1,4 +1,3 @@ -//go:build darwin // // WindowDelegate.m // test @@ -10,29 +9,15 @@ #import #import "WindowDelegate.h" #import "message.h" -#import "WailsContext.h" @implementation WindowDelegate -- (BOOL)windowShouldClose:(WailsWindow *)sender { - if( self.hideOnClose ) { - [NSApp hide:nil]; - return false; + +- (BOOL)windowShouldClose:(NSWindow *)sender { + [sender orderOut:nil]; + if( self.hideOnClose == false ) { + processMessage("Q"); } - processMessage("Q"); - return false; + return !self.hideOnClose; } -- (void)windowDidExitFullScreen:(NSNotification *)notification { - [self.ctx.mainWindow applyWindowConstraints]; -} - -- (void)windowWillEnterFullScreen:(NSNotification *)notification { - [self.ctx.mainWindow disableWindowConstraints]; -} - -- (NSApplicationPresentationOptions)window:(WailsWindow *)window willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions { - return NSApplicationPresentationAutoHideToolbar | NSApplicationPresentationAutoHideMenuBar | NSApplicationPresentationFullScreen; -} - - @end diff --git a/v2/internal/frontend/desktop/darwin/browser.go b/v2/internal/frontend/desktop/darwin/browser.go index c865ab6d9..417501c8e 100644 --- a/v2/internal/frontend/desktop/darwin/browser.go +++ b/v2/internal/frontend/desktop/darwin/browser.go @@ -4,21 +4,11 @@ package darwin import ( - "fmt" "github.com/pkg/browser" - "github.com/wailsapp/wails/v2/internal/frontend/utils" ) // BrowserOpenURL Use the default browser to open the url -func (f *Frontend) BrowserOpenURL(rawURL string) { - url, err := utils.ValidateAndSanitizeURL(rawURL) - if err != nil { - f.logger.Error(fmt.Sprintf("Invalid URL %s", err.Error())) - return - } - +func (f *Frontend) BrowserOpenURL(url string) { // Specific method implementation - if err := browser.OpenURL(url); err != nil { - f.logger.Error("Unable to open default system browser") - } + _ = browser.OpenURL(url) } diff --git a/v2/internal/frontend/desktop/darwin/callbacks.go b/v2/internal/frontend/desktop/darwin/callbacks.go deleted file mode 100644 index ab0d18e47..000000000 --- a/v2/internal/frontend/desktop/darwin/callbacks.go +++ /dev/null @@ -1,51 +0,0 @@ -//go:build darwin -// +build darwin - -package darwin - -/* -#cgo CFLAGS: -x objective-c -#cgo LDFLAGS: -framework Foundation -framework Cocoa -framework WebKit -#import -#import "Application.h" - -#include -*/ -import "C" - -import ( - "errors" - "strconv" - - "github.com/wailsapp/wails/v2/pkg/menu" -) - -func (f *Frontend) handleCallback(menuItemID uint) error { - menuItem := getMenuItemForID(menuItemID) - if menuItem == nil { - return errors.New("unknown menuItem ID: " + strconv.Itoa(int(menuItemID))) - } - - wailsMenuItem := menuItem.wailsMenuItem - if wailsMenuItem.Type == menu.CheckboxType { - wailsMenuItem.Checked = !wailsMenuItem.Checked - C.UpdateMenuItem(menuItem.nsmenuitem, bool2Cint(wailsMenuItem.Checked)) - } - if wailsMenuItem.Type == menu.RadioType { - // Ignore if we clicked the item that is already checked - if !wailsMenuItem.Checked { - for _, item := range menuItem.radioGroupMembers { - if item.wailsMenuItem.Checked { - item.wailsMenuItem.Checked = false - C.UpdateMenuItem(item.nsmenuitem, C.int(0)) - } - } - wailsMenuItem.Checked = true - C.UpdateMenuItem(menuItem.nsmenuitem, C.int(1)) - } - } - if wailsMenuItem.Click != nil { - go wailsMenuItem.Click(&menu.CallbackData{MenuItem: wailsMenuItem}) - } - return nil -} diff --git a/v2/internal/frontend/desktop/darwin/calloc.go b/v2/internal/frontend/desktop/darwin/calloc.go index afd0a9115..b1939900e 100644 --- a/v2/internal/frontend/desktop/darwin/calloc.go +++ b/v2/internal/frontend/desktop/darwin/calloc.go @@ -1,5 +1,3 @@ -//go:build darwin - package darwin /* diff --git a/v2/internal/frontend/desktop/darwin/clipboard.go b/v2/internal/frontend/desktop/darwin/clipboard.go deleted file mode 100644 index c40ba8771..000000000 --- a/v2/internal/frontend/desktop/darwin/clipboard.go +++ /dev/null @@ -1,35 +0,0 @@ -//go:build darwin - -package darwin - -import ( - "os/exec" -) - -func (f *Frontend) ClipboardGetText() (string, error) { - pasteCmd := exec.Command("pbpaste") - out, err := pasteCmd.Output() - if err != nil { - return "", err - } - return string(out), nil -} - -func (f *Frontend) ClipboardSetText(text string) error { - copyCmd := exec.Command("pbcopy") - in, err := copyCmd.StdinPipe() - if err != nil { - return err - } - - if err := copyCmd.Start(); err != nil { - return err - } - if _, err := in.Write([]byte(text)); err != nil { - return err - } - if err := in.Close(); err != nil { - return err - } - return copyCmd.Wait() -} diff --git a/v2/internal/frontend/desktop/darwin/dialog.go b/v2/internal/frontend/desktop/darwin/dialog.go index 66bb2f13a..9e359f249 100644 --- a/v2/internal/frontend/desktop/darwin/dialog.go +++ b/v2/internal/frontend/desktop/darwin/dialog.go @@ -11,25 +11,21 @@ package darwin #import "WailsContext.h" */ import "C" - import ( "encoding/json" "fmt" "strings" "sync" - "unsafe" "github.com/leaanthony/slicer" "github.com/wailsapp/wails/v2/internal/frontend" ) // Obj-C dialog methods send the response to this channel -var ( - messageDialogResponse = make(chan int) - openFileDialogResponse = make(chan string) - saveFileDialogResponse = make(chan string) - dialogLock sync.Mutex -) +var messageDialogResponse = make(chan int) +var openFileDialogResponse = make(chan string) +var saveFileDialogResponse = make(chan string) +var dialogLock sync.Mutex // OpenDirectoryDialog prompts the user to select a directory func (f *Frontend) OpenDirectoryDialog(options frontend.OpenDialogOptions) (string, error) { @@ -77,7 +73,7 @@ func (f *Frontend) openDialog(options *frontend.OpenDialogOptions, multiple bool filters := filterStrings.Join(";") C.OpenFileDialog(f.mainWindow.context, title, defaultFilename, defaultDirectory, allowDirectories, allowFiles, canCreateDirectories, treatPackagesAsDirectories, resolveAliases, showHiddenFiles, allowMultipleFileSelection, c.String(filters)) - result := <-openFileDialogResponse + var result = <-openFileDialogResponse var parsedResults []string err := json.Unmarshal([]byte(result), &parsedResults) @@ -87,7 +83,7 @@ func (f *Frontend) openDialog(options *frontend.OpenDialogOptions, multiple bool // OpenFileDialog prompts the user to select a file func (f *Frontend) OpenFileDialog(options frontend.OpenDialogOptions) (string, error) { - results, err := f.openDialog(&options, false, true, false) + results, err := f.openDialog(&options, false, options.AllowFiles, options.AllowDirectories) if err != nil { return "", err } @@ -100,7 +96,7 @@ func (f *Frontend) OpenFileDialog(options frontend.OpenDialogOptions) (string, e // OpenMultipleFilesDialog prompts the user to select a file func (f *Frontend) OpenMultipleFilesDialog(options frontend.OpenDialogOptions) ([]string, error) { - return f.openDialog(&options, true, true, false) + return f.openDialog(&options, true, options.AllowFiles, options.AllowDirectories) } // SaveFileDialog prompts the user to select a file @@ -133,7 +129,7 @@ func (f *Frontend) SaveFileDialog(options frontend.SaveDialogOptions) (string, e filters := filterStrings.Join(";") C.SaveFileDialog(f.mainWindow.context, title, defaultFilename, defaultDirectory, canCreateDirectories, treatPackagesAsDirectories, showHiddenFiles, c.String(filters)) - result := <-saveFileDialogResponse + var result = <-saveFileDialogResponse return result, nil } @@ -159,16 +155,9 @@ func (f *Frontend) MessageDialog(options frontend.MessageDialogOptions) (string, buttons[index] = c.String(buttonText) } - var iconData unsafe.Pointer - var iconDataLength C.int - if options.Icon != nil { - iconData = unsafe.Pointer(&options.Icon[0]) - iconDataLength = C.int(len(options.Icon)) - } + C.MessageDialog(f.mainWindow.context, dialogType, title, message, buttons[0], buttons[1], buttons[2], buttons[3], defaultButton, cancelButton) - C.MessageDialog(f.mainWindow.context, dialogType, title, message, buttons[0], buttons[1], buttons[2], buttons[3], defaultButton, cancelButton, iconData, iconDataLength) - - result := <-messageDialogResponse + var result = <-messageDialogResponse selectedC := buttons[result] var selected string diff --git a/v2/internal/frontend/desktop/darwin/frontend.go b/v2/internal/frontend/desktop/darwin/frontend.go index 6566445d5..04f366f86 100644 --- a/v2/internal/frontend/desktop/darwin/frontend.go +++ b/v2/internal/frontend/desktop/darwin/frontend.go @@ -8,202 +8,102 @@ package darwin #cgo LDFLAGS: -framework Foundation -framework Cocoa -framework WebKit #import #import "Application.h" -#import "CustomProtocol.h" #import "WailsContext.h" #include */ import "C" - import ( "context" "encoding/json" - "fmt" "html/template" "log" - "net" - "net/url" - "os" + "strconv" + "strings" "unsafe" - "github.com/wailsapp/wails/v2/pkg/assetserver" - "github.com/wailsapp/wails/v2/pkg/assetserver/webview" - "github.com/wailsapp/wails/v2/internal/binding" "github.com/wailsapp/wails/v2/internal/frontend" - "github.com/wailsapp/wails/v2/internal/frontend/originvalidator" - "github.com/wailsapp/wails/v2/internal/frontend/runtime" + "github.com/wailsapp/wails/v2/internal/frontend/assetserver" "github.com/wailsapp/wails/v2/internal/logger" "github.com/wailsapp/wails/v2/pkg/options" ) -const startURL = "wails://wails/" - -type bindingsMessage struct { - message string - source string - isMainFrame bool +type request struct { + url *C.char + ctx unsafe.Pointer } -var ( - messageBuffer = make(chan string, 100) - bindingsMessageBuffer = make(chan *bindingsMessage, 100) - requestBuffer = make(chan webview.Request, 100) - callbackBuffer = make(chan uint, 10) - openFilepathBuffer = make(chan string, 100) - openUrlBuffer = make(chan string, 100) - secondInstanceBuffer = make(chan options.SecondInstanceData, 1) -) +var messageBuffer = make(chan string, 100) +var requestBuffer = make(chan *request, 100) type Frontend struct { + // Context ctx context.Context frontendOptions *options.App logger *logger.Logger debug bool - devtoolsEnabled bool - - // Keep single instance lock file, so that it will not be GC and lock will exist while app is running - singleInstanceLockFile *os.File // Assets - assets *assetserver.AssetServer - startURL *url.URL + assets *assetserver.DesktopAssetServer // main window handle - mainWindow *Window - bindings *binding.Bindings - dispatcher frontend.Dispatcher - - originValidator *originvalidator.OriginValidator -} - -func (f *Frontend) RunMainLoop() { - C.RunMainLoop() -} - -func (f *Frontend) WindowClose() { - C.ReleaseContext(f.mainWindow.context) + mainWindow *Window + minWidth, minHeight, maxWidth, maxHeight int + bindings *binding.Bindings + dispatcher frontend.Dispatcher + servingFromDisk bool } func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.Logger, appBindings *binding.Bindings, dispatcher frontend.Dispatcher) *Frontend { + result := &Frontend{ frontendOptions: appoptions, logger: myLogger, bindings: appBindings, dispatcher: dispatcher, ctx: ctx, + minHeight: appoptions.MinHeight, + minWidth: appoptions.MinWidth, + maxHeight: appoptions.MaxHeight, + maxWidth: appoptions.MaxWidth, } - result.startURL, _ = url.Parse(startURL) - result.originValidator = originvalidator.NewOriginValidator(result.startURL, appoptions.BindingsAllowedOrigins) - // this should be initialized as early as possible to handle first instance launch - C.StartCustomProtocolHandler() - - if _starturl, _ := ctx.Value("starturl").(*url.URL); _starturl != nil { - result.startURL = _starturl - result.originValidator = originvalidator.NewOriginValidator(result.startURL, appoptions.BindingsAllowedOrigins) - } else { - if port, _ := ctx.Value("assetserverport").(string); port != "" { - result.startURL.Host = net.JoinHostPort(result.startURL.Host+".localhost", port) - result.originValidator = originvalidator.NewOriginValidator(result.startURL, appoptions.BindingsAllowedOrigins) - } - - var bindings string - var err error - if _obfuscated, _ := ctx.Value("obfuscated").(bool); !_obfuscated { - bindings, err = appBindings.ToJSON() - if err != nil { - log.Fatal(err) - } - } else { - appBindings.DB().UpdateObfuscatedCallMap() - } - - assets, err := assetserver.NewAssetServerMainPage(bindings, appoptions, ctx.Value("assetdir") != nil, myLogger, runtime.RuntimeAssetsBundle) - if err != nil { - log.Fatal(err) - } - assets.ExpectedWebViewHost = result.startURL.Host - result.assets = assets - - go result.startRequestProcessor() + // Check if we have been given a directory to serve assets from. + // If so, this means we are in dev mode and are serving assets off disk. + // We indicate this through the `servingFromDisk` flag to ensure requests + // aren't cached by WebView2 in dev mode + _assetdir := ctx.Value("assetdir") + if _assetdir != nil { + result.servingFromDisk = true } + bindingsJSON, err := appBindings.ToJSON() + if err != nil { + log.Fatal(err) + } + assets, err := assetserver.NewDesktopAssetServer(ctx, appoptions.Assets, bindingsJSON) + if err != nil { + log.Fatal(err) + } + result.assets = assets + go result.startMessageProcessor() - go result.startBindingsMessageProcessor() - go result.startCallbackProcessor() - go result.startFileOpenProcessor() - go result.startUrlOpenProcessor() - go result.startSecondInstanceProcessor() + go result.startRequestProcessor() return result } -func (f *Frontend) startFileOpenProcessor() { - for filePath := range openFilepathBuffer { - f.ProcessOpenFileEvent(filePath) - } -} - -func (f *Frontend) startUrlOpenProcessor() { - for url := range openUrlBuffer { - f.ProcessOpenUrlEvent(url) - } -} - -func (f *Frontend) startSecondInstanceProcessor() { - for secondInstanceData := range secondInstanceBuffer { - if f.frontendOptions.SingleInstanceLock != nil && - f.frontendOptions.SingleInstanceLock.OnSecondInstanceLaunch != nil { - f.frontendOptions.SingleInstanceLock.OnSecondInstanceLaunch(secondInstanceData) - } - } -} - func (f *Frontend) startMessageProcessor() { for message := range messageBuffer { f.processMessage(message) } } - -func (f *Frontend) startBindingsMessageProcessor() { - for msg := range bindingsMessageBuffer { - // Apple webkit doesn't provide origin of main frame. So we can't verify in case of iFrame that top level origin is allowed. - if !msg.isMainFrame { - f.logger.Error("Blocked request from not main frame") - continue - } - - origin, err := f.originValidator.GetOriginFromURL(msg.source) - if err != nil { - f.logger.Error(fmt.Sprintf("failed to get origin for URL %q: %v", msg.source, err)) - continue - } - - allowed := f.originValidator.IsOriginAllowed(origin) - if !allowed { - f.logger.Error("Blocked request from unauthorized origin: %s", origin) - continue - } - - f.processMessage(msg.message) - } -} - func (f *Frontend) startRequestProcessor() { for request := range requestBuffer { - f.assets.ServeWebViewRequest(request) - } -} - -func (f *Frontend) startCallbackProcessor() { - for callback := range callbackBuffer { - err := f.handleCallback(callback) - if err != nil { - println(err.Error()) - } + f.processRequest(request) } } @@ -211,37 +111,16 @@ func (f *Frontend) WindowReload() { f.ExecJS("runtime.WindowReload();") } -func (f *Frontend) WindowReloadApp() { - f.ExecJS(fmt.Sprintf("window.location.href = '%s';", f.startURL)) -} - -func (f *Frontend) WindowSetSystemDefaultTheme() { -} - -func (f *Frontend) WindowSetLightTheme() { -} - -func (f *Frontend) WindowSetDarkTheme() { -} - func (f *Frontend) Run(ctx context.Context) error { - f.ctx = ctx - if f.frontendOptions.SingleInstanceLock != nil { - f.singleInstanceLockFile = SetupSingleInstance(f.frontendOptions.SingleInstanceLock.UniqueId) - } - - _debug := ctx.Value("debug") - _devtoolsEnabled := ctx.Value("devtoolsEnabled") + f.ctx = context.WithValue(ctx, "frontend", f) + var _debug = ctx.Value("debug") if _debug != nil { f.debug = _debug.(bool) } - if _devtoolsEnabled != nil { - f.devtoolsEnabled = _devtoolsEnabled.(bool) - } - mainWindow := NewWindow(f.frontendOptions, f.debug, f.devtoolsEnabled) + mainWindow := NewWindow(f.frontendOptions, f.debug) f.mainWindow = mainWindow f.mainWindow.Center() @@ -250,7 +129,7 @@ func (f *Frontend) Run(ctx context.Context) error { f.frontendOptions.OnStartup(f.ctx) } }() - mainWindow.Run(f.startURL.String()) + mainWindow.Run() return nil } @@ -258,16 +137,11 @@ func (f *Frontend) WindowCenter() { f.mainWindow.Center() } -func (f *Frontend) WindowSetAlwaysOnTop(onTop bool) { - f.mainWindow.SetAlwaysOnTop(onTop) +func (f *Frontend) WindowSetPos(x, y int) { + f.mainWindow.SetPos(x, y) } - -func (f *Frontend) WindowSetPosition(x, y int) { - f.mainWindow.SetPosition(x, y) -} - -func (f *Frontend) WindowGetPosition() (int, int) { - return f.mainWindow.GetPosition() +func (f *Frontend) WindowGetPos() (int, int) { + return f.mainWindow.Pos() } func (f *Frontend) WindowSetSize(width, height int) { @@ -283,11 +157,15 @@ func (f *Frontend) WindowSetTitle(title string) { } func (f *Frontend) WindowFullscreen() { + f.mainWindow.SetMaxSize(0, 0) + f.mainWindow.SetMinSize(0, 0) f.mainWindow.Fullscreen() } -func (f *Frontend) WindowUnfullscreen() { +func (f *Frontend) WindowUnFullscreen() { f.mainWindow.UnFullscreen() + f.mainWindow.SetMaxSize(f.maxWidth, f.maxHeight) + f.mainWindow.SetMinSize(f.minWidth, f.minHeight) } func (f *Frontend) WindowShow() { @@ -297,86 +175,41 @@ func (f *Frontend) WindowShow() { func (f *Frontend) WindowHide() { f.mainWindow.Hide() } - -func (f *Frontend) Show() { - f.mainWindow.ShowApplication() -} - -func (f *Frontend) Hide() { - f.mainWindow.HideApplication() -} - func (f *Frontend) WindowMaximise() { f.mainWindow.Maximise() } - -func (f *Frontend) WindowToggleMaximise() { - f.mainWindow.ToggleMaximise() -} - func (f *Frontend) WindowUnmaximise() { f.mainWindow.UnMaximise() } - func (f *Frontend) WindowMinimise() { f.mainWindow.Minimise() } - func (f *Frontend) WindowUnminimise() { f.mainWindow.UnMinimise() } func (f *Frontend) WindowSetMinSize(width int, height int) { + f.minWidth = width + f.minHeight = height f.mainWindow.SetMinSize(width, height) } - func (f *Frontend) WindowSetMaxSize(width int, height int) { + f.maxWidth = width + f.maxHeight = height f.mainWindow.SetMaxSize(width, height) } -func (f *Frontend) WindowSetBackgroundColour(col *options.RGBA) { +func (f *Frontend) WindowSetRGBA(col *options.RGBA) { if col == nil { return } - f.mainWindow.SetBackgroundColour(col.R, col.G, col.B, col.A) -} - -func (f *Frontend) ScreenGetAll() ([]frontend.Screen, error) { - return GetAllScreens(f.mainWindow.context) -} - -func (f *Frontend) WindowIsMaximised() bool { - return f.mainWindow.IsMaximised() -} - -func (f *Frontend) WindowIsMinimised() bool { - return f.mainWindow.IsMinimised() -} - -func (f *Frontend) WindowIsNormal() bool { - return f.mainWindow.IsNormal() -} - -func (f *Frontend) WindowIsFullscreen() bool { - return f.mainWindow.IsFullScreen() + f.mainWindow.SetRGBA(col.R, col.G, col.B, col.A) } func (f *Frontend) Quit() { - if f.frontendOptions.OnBeforeClose != nil { - go func() { - if !f.frontendOptions.OnBeforeClose(f.ctx) { - f.mainWindow.Quit() - } - }() - return - } f.mainWindow.Quit() } -func (f *Frontend) WindowPrint() { - f.mainWindow.Print() -} - type EventNotify struct { Name string `json:"name"` Data []interface{} `json:"data"` @@ -396,94 +229,67 @@ func (f *Frontend) Notify(name string, data ...interface{}) { } func (f *Frontend) processMessage(message string) { - if message == "DomReady" { - if f.frontendOptions.OnDomReady != nil { - f.frontendOptions.OnDomReady(f.ctx) - } - return - } - - if message == "runtime:ready" { - cmd := fmt.Sprintf("window.wails.setCSSDragProperties('%s', '%s');", f.frontendOptions.CSSDragProperty, f.frontendOptions.CSSDragValue) - f.ExecJS(cmd) - - if f.frontendOptions.DragAndDrop != nil && f.frontendOptions.DragAndDrop.EnableFileDrop { - f.ExecJS("window.wails.flags.enableWailsDragAndDrop = true;") - } - - return - } - - if message == "wails:openInspector" { - showInspector(f.mainWindow.context) - return - } - - //if strings.HasPrefix(message, "systemevent:") { - // f.processSystemEvent(message) - // return - //} - - go func() { - result, err := f.dispatcher.ProcessMessage(message, f) + if message == "drag" { + err := f.startDrag() if err != nil { f.logger.Error(err.Error()) - f.Callback(result) - return } - if result == "" { - return - } - - switch result[0] { - case 'c': - // Callback from a method call - f.Callback(result[1:]) - default: - f.logger.Info("Unknown message returned from dispatcher: %+v", result) - } - }() -} - -func (f *Frontend) ProcessOpenFileEvent(filePath string) { - if f.frontendOptions.Mac != nil && f.frontendOptions.Mac.OnFileOpen != nil { - f.frontendOptions.Mac.OnFileOpen(filePath) + return + } + result, err := f.dispatcher.ProcessMessage(message, f) + if err != nil { + f.logger.Error(err.Error()) + f.Callback(result) + return + } + if result == "" { + return } -} -func (f *Frontend) ProcessOpenUrlEvent(url string) { - if f.frontendOptions.Mac != nil && f.frontendOptions.Mac.OnUrlOpen != nil { - f.frontendOptions.Mac.OnUrlOpen(url) + switch result[0] { + case 'c': + // Callback from a method call + f.Callback(result[1:]) + default: + f.logger.Info("Unknown message returned from dispatcher: %+v", result) } } func (f *Frontend) Callback(message string) { - escaped, err := json.Marshal(message) - if err != nil { - panic(err) - } - f.ExecJS(`window.wails.Callback(` + string(escaped) + `);`) + f.ExecJS(`window.wails.Callback(` + strconv.Quote(message) + `);`) +} + +func (f *Frontend) startDrag() error { + //if !w32.ReleaseCapture() { + // return fmt.Errorf("unable to release mouse capture") + //} + //w32.SendMessage(f.mainWindow.Handle(), w32.WM_NCLBUTTONDOWN, w32.HTCAPTION, 0) + return nil } func (f *Frontend) ExecJS(js string) { f.mainWindow.ExecJS(js) } -//func (f *Frontend) processSystemEvent(message string) { -// sl := strings.Split(message, ":") -// if len(sl) != 2 { -// f.logger.Error("Invalid system message: %s", message) -// return -// } -// switch sl[1] { -// case "fullscreen": -// f.mainWindow.DisableSizeConstraints() -// case "unfullscreen": -// f.mainWindow.EnableSizeConstraints() -// default: -// f.logger.Error("Unknown system message: %s", message) -// } -//} +func (f *Frontend) processRequest(r *request) { + url := C.GoString(r.url) + url = strings.TrimPrefix(url, "wails://wails") + if !strings.HasPrefix(url, "/") { + return + } + _contents, _mimetype, err := f.assets.Load(url) + if err != nil { + f.logger.Error(err.Error()) + //TODO: Handle errors + return + } + data := C.CString(string(_contents)) + defer C.free(unsafe.Pointer(data)) + mimetype := C.CString(_mimetype) + defer C.free(unsafe.Pointer(mimetype)) + + C.ProcessURLResponse(r.ctx, r.url, mimetype, data, C.int(len(_contents))) +} //export processMessage func processMessage(message *C.char) { @@ -491,35 +297,10 @@ func processMessage(message *C.char) { messageBuffer <- goMessage } -//export processBindingMessage -func processBindingMessage(message *C.char, source *C.char, fromMainFrame bool) { - goMessage := C.GoString(message) - goSource := C.GoString(source) - bindingsMessageBuffer <- &bindingsMessage{ - message: goMessage, - source: goSource, - isMainFrame: fromMainFrame, +//export processURLRequest +func processURLRequest(ctx unsafe.Pointer, url *C.char) { + requestBuffer <- &request{ + url: url, + ctx: ctx, } } - -//export processCallback -func processCallback(callbackID uint) { - callbackBuffer <- callbackID -} - -//export processURLRequest -func processURLRequest(_ unsafe.Pointer, wkURLSchemeTask unsafe.Pointer) { - requestBuffer <- webview.NewRequest(wkURLSchemeTask) -} - -//export HandleOpenFile -func HandleOpenFile(filePath *C.char) { - goFilepath := C.GoString(filePath) - openFilepathBuffer <- goFilepath -} - -//export HandleOpenURL -func HandleOpenURL(url *C.char) { - goUrl := C.GoString(url) - openUrlBuffer <- goUrl -} diff --git a/v2/internal/frontend/desktop/darwin/inspector.go b/v2/internal/frontend/desktop/darwin/inspector.go deleted file mode 100644 index dc3f08969..000000000 --- a/v2/internal/frontend/desktop/darwin/inspector.go +++ /dev/null @@ -1,10 +0,0 @@ -//go:build darwin && !(dev || debug || devtools) - -package darwin - -import ( - "unsafe" -) - -func showInspector(_ unsafe.Pointer) { -} diff --git a/v2/internal/frontend/desktop/darwin/inspector_dev.go b/v2/internal/frontend/desktop/darwin/inspector_dev.go deleted file mode 100644 index e79b9c3e7..000000000 --- a/v2/internal/frontend/desktop/darwin/inspector_dev.go +++ /dev/null @@ -1,78 +0,0 @@ -//go:build darwin && (dev || debug || devtools) - -package darwin - -// We are using private APIs here, make sure this is only included in a dev/debug build and not in a production build. -// Otherwise the binary might get rejected by the AppReview-Team when pushing it to the AppStore. - -/* -#cgo CFLAGS: -x objective-c -#cgo LDFLAGS: -framework Foundation -framework Cocoa -framework WebKit -#import -#import "WailsContext.h" - -extern void processMessage(const char *message); - -@interface _WKInspector : NSObject -- (void)show; -- (void)detach; -@end - -@interface WKWebView () -- (_WKInspector *)_inspector; -@end - -void showInspector(void *inctx) { -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 120000 - ON_MAIN_THREAD( - if (@available(macOS 12.0, *)) { - WailsContext *ctx = (__bridge WailsContext*) inctx; - - @try { - [ctx.webview._inspector show]; - } @catch (NSException *exception) { - NSLog(@"Opening the inspector failed: %@", exception.reason); - return; - } - - dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC); - dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ - // Detach must be deferred a little bit and is ignored directly after a show. - @try { - [ctx.webview._inspector detach]; - } @catch (NSException *exception) { - NSLog(@"Detaching the inspector failed: %@", exception.reason); - } - }); - } else { - NSLog(@"Opening the inspector needs at least MacOS 12"); - } - ); -#endif -} - -void setupF12hotkey() { - [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyDown handler:^NSEvent * _Nullable(NSEvent * _Nonnull event) { - if (event.keyCode == 111 && - event.modifierFlags & NSEventModifierFlagFunction && - event.modifierFlags & NSEventModifierFlagCommand && - event.modifierFlags & NSEventModifierFlagShift) { - processMessage("wails:openInspector"); - return nil; - } - return event; - }]; -} -*/ -import "C" -import ( - "unsafe" -) - -func init() { - C.setupF12hotkey() -} - -func showInspector(context unsafe.Pointer) { - C.showInspector(context) -} diff --git a/v2/internal/frontend/desktop/darwin/main.m b/v2/internal/frontend/desktop/darwin/main.m index 75a84dc76..d605d8282 100644 --- a/v2/internal/frontend/desktop/darwin/main.m +++ b/v2/internal/frontend/desktop/darwin/main.m @@ -12,6 +12,7 @@ void processMessage(const char*t) { NSLog(@"processMessage called"); + } void processMessageDialogResponse(int t) { @@ -21,221 +22,33 @@ void processMessageDialogResponse(int t) { void processOpenFileDialogResponse(const char *t) { NSLog(@"processMessage called %s", t); } -void processSaveFileDialogResponse(const char *t) { - NSLog(@"processMessage called %s", t); -} - -void processCallback(int callbackID) { - NSLog(@"Process callback %d", callbackID); -} -void processURLRequest(void *ctx, unsigned long long requestId, const char* url, const char *method, const char *headers, const void *body, int bodyLen) { +void processURLRequest(void *ctx, const char* url) { NSLog(@"processURLRequest called"); const char myByteArray[] = { 0x3c,0x68,0x31,0x3e,0x48,0x65,0x6c,0x6c,0x6f,0x20,0x57,0x6f,0x72,0x6c,0x64,0x21,0x3c,0x2f,0x68,0x31,0x3e }; - // void *inctx, const char *url, int statusCode, const char *headers, void* data, int datalength - ProcessURLResponse(ctx, requestId, 200, "{\"Content-Type\": \"text/html\"}", (void*)myByteArray, 21); + ProcessURLResponse(ctx, url, "text/html", myByteArray, 21); } -unsigned char _Users_username_Pictures_SaltBae_png[] = { - -0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, -0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14, -0x08, 0x06, 0x00, 0x00, 0x00, 0x8d, 0x89, 0x1d, 0x0d, 0x00, 0x00, 0x00, -0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, -0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, -0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, -0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, -0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, -0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, -0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x01, 0xd5, 0x69, 0x54, -0x58, 0x74, 0x58, 0x4d, 0x4c, 0x3a, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x64, -0x6f, 0x62, 0x65, 0x2e, 0x78, 0x6d, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, -0x3c, 0x78, 0x3a, 0x78, 0x6d, 0x70, 0x6d, 0x65, 0x74, 0x61, 0x20, 0x78, -0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x78, 0x3d, 0x22, 0x61, 0x64, 0x6f, 0x62, -0x65, 0x3a, 0x6e, 0x73, 0x3a, 0x6d, 0x65, 0x74, 0x61, 0x2f, 0x22, 0x20, -0x78, 0x3a, 0x78, 0x6d, 0x70, 0x74, 0x6b, 0x3d, 0x22, 0x58, 0x4d, 0x50, -0x20, 0x43, 0x6f, 0x72, 0x65, 0x20, 0x35, 0x2e, 0x34, 0x2e, 0x30, 0x22, -0x3e, 0x0a, 0x20, 0x20, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x52, 0x44, -0x46, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x72, 0x64, 0x66, 0x3d, -0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, -0x77, 0x33, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x31, 0x39, 0x39, 0x39, 0x2f, -0x30, 0x32, 0x2f, 0x32, 0x32, 0x2d, 0x72, 0x64, 0x66, 0x2d, 0x73, 0x79, -0x6e, 0x74, 0x61, 0x78, 0x2d, 0x6e, 0x73, 0x23, 0x22, 0x3e, 0x0a, 0x20, -0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, -0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72, 0x64, -0x66, 0x3a, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x3d, 0x22, 0x22, 0x0a, 0x20, -0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x78, -0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x74, 0x69, 0x66, 0x66, 0x3d, 0x22, 0x68, -0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f, -0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x69, 0x66, 0x66, 0x2f, -0x31, 0x2e, 0x30, 0x2f, 0x22, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x69, 0x66, 0x66, 0x3a, 0x43, 0x6f, -0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x3e, 0x31, 0x3c, -0x2f, 0x74, 0x69, 0x66, 0x66, 0x3a, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, -0x73, 0x73, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x69, 0x66, 0x66, 0x3a, 0x4f, 0x72, -0x69, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x31, 0x3c, -0x2f, 0x74, 0x69, 0x66, 0x66, 0x3a, 0x4f, 0x72, 0x69, 0x65, 0x6e, 0x74, -0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x69, 0x66, 0x66, 0x3a, 0x50, 0x68, -0x6f, 0x74, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x49, 0x6e, 0x74, -0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3e, -0x32, 0x3c, 0x2f, 0x74, 0x69, 0x66, 0x66, 0x3a, 0x50, 0x68, 0x6f, 0x74, -0x6f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x49, 0x6e, 0x74, 0x65, 0x72, -0x70, 0x72, 0x65, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x20, -0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x44, -0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, -0x20, 0x20, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x52, 0x44, 0x46, -0x3e, 0x0a, 0x3c, 0x2f, 0x78, 0x3a, 0x78, 0x6d, 0x70, 0x6d, 0x65, 0x74, -0x61, 0x3e, 0x0a, 0x02, 0xd8, 0x80, 0x05, 0x00, 0x00, 0x04, 0xdc, 0x49, -0x44, 0x41, 0x54, 0x38, 0x11, 0x1d, 0x94, 0x49, 0x6c, 0x1b, 0x65, 0x18, -0x86, 0x9f, 0x99, 0xf9, 0x67, 0xc6, 0x6b, 0xbc, 0x26, 0xce, 0xda, 0xa4, -0x25, 0x69, 0x0b, 0x2d, 0x28, 0x34, 0x2c, 0x95, 0x00, 0x89, 0x45, 0x08, -0x5a, 0x95, 0x03, 0x08, 0x09, 0x21, 0xe0, 0x80, 0x38, 0xc3, 0x85, 0x03, -0xe2, 0x00, 0x47, 0xc4, 0x1d, 0x38, 0x70, 0xe3, 0xc6, 0x01, 0x01, 0x42, -0x20, 0x54, 0x7a, 0x2a, 0x6b, 0x0b, 0x94, 0xd2, 0xd2, 0x25, 0x69, 0x9b, -0xa4, 0x0d, 0x2d, 0xa9, 0xb3, 0x78, 0x89, 0x9d, 0xf1, 0x2c, 0x9e, 0x85, -0x2f, 0xb5, 0x35, 0xb6, 0x35, 0x96, 0xde, 0x79, 0xdf, 0xef, 0x7f, 0x9f, -0x4f, 0xfb, 0xe0, 0xad, 0x37, 0x12, 0xfd, 0xf0, 0xb3, 0x9c, 0xfb, 0xb7, -0xc5, 0x8d, 0x46, 0x9b, 0x71, 0x5b, 0xf1, 0xd0, 0xf4, 0x18, 0xdb, 0xeb, -0x4b, 0x1c, 0xff, 0xf1, 0x57, 0x98, 0xdc, 0x87, 0x72, 0x3a, 0x8c, 0x3a, -0xcb, 0x8c, 0xea, 0x31, 0x35, 0xb7, 0xc3, 0x99, 0xba, 0xc3, 0xd7, 0xab, -0x3e, 0x87, 0x2a, 0x8a, 0xb3, 0xff, 0xdc, 0xe0, 0x9b, 0x8f, 0x5f, 0xa2, -0x1c, 0xc5, 0xfc, 0x72, 0xc9, 0x41, 0x99, 0x71, 0x48, 0xca, 0x84, 0x3c, -0x3e, 0xda, 0xd2, 0x05, 0x9a, 0xb1, 0xc7, 0x35, 0x67, 0x1c, 0xdd, 0x4c, -0x68, 0xeb, 0x26, 0xd9, 0x30, 0x26, 0x09, 0x23, 0x5c, 0x3f, 0xc2, 0xd3, -0x43, 0xc2, 0x24, 0x21, 0x4e, 0x34, 0x40, 0x27, 0x89, 0x13, 0xf9, 0x1e, -0x22, 0x6e, 0xd5, 0x45, 0x43, 0x63, 0xc6, 0xd2, 0x50, 0xa9, 0xc4, 0x67, -0x24, 0x15, 0x72, 0xa9, 0x7e, 0x95, 0xfa, 0x4f, 0x27, 0x78, 0x64, 0x76, -0x86, 0x23, 0x61, 0xc0, 0xf0, 0x58, 0x15, 0xc3, 0x29, 0x71, 0x06, 0x45, -0x2e, 0xa5, 0x48, 0xbb, 0x0a, 0x3d, 0x89, 0xa0, 0x8f, 0x08, 0x8a, 0x8e, -0x08, 0xbb, 0xc1, 0x8e, 0xb0, 0x8d, 0xdd, 0x0f, 0xc9, 0x84, 0x06, 0x65, -0x34, 0xf4, 0xed, 0x8d, 0xff, 0x58, 0xbd, 0xfc, 0x27, 0x17, 0x2f, 0x9e, -0xe3, 0xf0, 0x81, 0x49, 0x5e, 0xde, 0x5f, 0xe1, 0x9e, 0x82, 0xcd, 0xdc, -0x78, 0x8d, 0xd9, 0xb2, 0xc9, 0x56, 0x12, 0x32, 0x94, 0x4f, 0x91, 0xcb, -0x88, 0x68, 0xda, 0x42, 0x13, 0x77, 0x11, 0xa2, 0xa8, 0xc3, 0x5a, 0x5f, -0x46, 0x30, 0x65, 0x52, 0x29, 0xe4, 0x24, 0x4d, 0x8e, 0xcc, 0x68, 0x19, -0xe5, 0x76, 0xbb, 0xac, 0x5c, 0x98, 0xa7, 0xb3, 0xed, 0xd0, 0x37, 0x62, -0xa2, 0xb0, 0xc7, 0x89, 0xe5, 0x2e, 0x03, 0x0d, 0x97, 0x95, 0x46, 0x8f, -0x31, 0xd7, 0xa6, 0x63, 0x81, 0x65, 0x25, 0x84, 0xba, 0x45, 0x5f, 0x65, -0x31, 0x2c, 0x71, 0x6b, 0x77, 0x69, 0xf5, 0x7a, 0xbc, 0xb0, 0x3b, 0xcd, -0xf9, 0xa5, 0x90, 0xd1, 0xb0, 0xcd, 0xd4, 0xb0, 0xdc, 0xd7, 0xc4, 0xfa, -0xf0, 0x78, 0x95, 0x7b, 0x27, 0xab, 0x5c, 0x5e, 0x6e, 0xd2, 0xee, 0x05, -0xdc, 0xd8, 0xea, 0xf1, 0xf7, 0xe2, 0x1a, 0xc7, 0xee, 0x1a, 0x62, 0x2e, -0x1f, 0xe3, 0xe8, 0xb6, 0xc4, 0x4c, 0xd3, 0x6d, 0x6e, 0xd0, 0x6b, 0xfc, -0x4c, 0xe3, 0xd4, 0x1f, 0xc4, 0x4b, 0xf3, 0x1c, 0x2c, 0x65, 0x29, 0x67, -0x4d, 0xbe, 0xfb, 0xad, 0x45, 0x65, 0x0c, 0xea, 0x7e, 0x1f, 0x15, 0x6b, -0x09, 0x0b, 0x8b, 0xb7, 0x19, 0xc9, 0xa5, 0x78, 0x75, 0x6e, 0x18, 0xdf, -0xf5, 0x79, 0x72, 0xd0, 0xa2, 0x2d, 0xb3, 0x3a, 0xbb, 0xb4, 0x41, 0x3e, -0x53, 0xe6, 0xf4, 0xca, 0x3c, 0xa5, 0x7c, 0x86, 0xe9, 0xfd, 0x47, 0x18, -0x2e, 0xbd, 0xce, 0xd1, 0x97, 0x26, 0x78, 0xbc, 0x7e, 0x1d, 0xff, 0xcc, -0xa7, 0x5c, 0x71, 0x74, 0x16, 0xe3, 0x18, 0xd7, 0x1e, 0x23, 0xe8, 0xac, -0xa3, 0x0c, 0xcd, 0x60, 0x22, 0x6f, 0x43, 0x36, 0x43, 0x3b, 0x19, 0xc6, -0x08, 0x7a, 0xe0, 0x6c, 0xe3, 0x27, 0x8a, 0xdb, 0x4e, 0xc0, 0xd4, 0xa0, -0xcd, 0x27, 0xaf, 0xbd, 0xcb, 0x86, 0x36, 0xc6, 0xcc, 0xfe, 0x59, 0xd2, -0xca, 0x90, 0x93, 0x36, 0x70, 0xaf, 0x9c, 0xe4, 0xcb, 0x6f, 0x65, 0x54, -0xd9, 0x47, 0x59, 0x70, 0xbb, 0x74, 0x1b, 0x0e, 0x89, 0xe7, 0xa3, 0xc7, -0x12, 0x39, 0x63, 0xea, 0x68, 0x12, 0x6b, 0x53, 0x5c, 0x9e, 0xef, 0x76, -0xf0, 0x55, 0x86, 0x0d, 0x17, 0x56, 0x9a, 0x4d, 0x94, 0x95, 0x65, 0xe6, -0xbe, 0x67, 0x98, 0xbe, 0xfb, 0x21, 0x52, 0xd2, 0x43, 0xaf, 0x5d, 0x47, -0x6b, 0x5c, 0xa3, 0x59, 0xbf, 0xc2, 0x62, 0xdd, 0x26, 0xa5, 0x12, 0x6a, -0x41, 0x44, 0xdf, 0xbd, 0xcd, 0x92, 0x17, 0xa0, 0xb6, 0x03, 0x43, 0xba, -0x66, 0x91, 0xe9, 0xdc, 0xc2, 0xce, 0xed, 0xa1, 0xfc, 0xc0, 0x2b, 0x14, -0xff, 0xfd, 0x1e, 0x4b, 0xb3, 0xa9, 0x29, 0x87, 0x81, 0xd2, 0x04, 0x8e, -0x66, 0x89, 0x58, 0x00, 0x7e, 0x07, 0xaf, 0xdb, 0xa4, 0xbb, 0xb5, 0x49, -0xb9, 0xaa, 0x18, 0xb9, 0x77, 0x8e, 0xcd, 0xdb, 0x6d, 0x1e, 0x1c, 0xb5, -0x38, 0x7d, 0xa5, 0xcf, 0xaa, 0x08, 0xeb, 0x77, 0x3f, 0x35, 0xc7, 0xda, -0xfc, 0x02, 0xaa, 0xf6, 0x1c, 0xbb, 0x9f, 0x78, 0x9f, 0x89, 0x43, 0x47, -0xa4, 0x6f, 0x3d, 0x06, 0xed, 0x90, 0x92, 0x79, 0x95, 0xd4, 0xe4, 0xfd, -0x98, 0x66, 0x4a, 0x6a, 0xd7, 0xc7, 0x0b, 0x62, 0xa4, 0xe3, 0x8c, 0x4d, -0xc4, 0xe8, 0x85, 0x98, 0xe5, 0x46, 0x44, 0x26, 0x97, 0x21, 0xe9, 0xf7, -0xf9, 0x61, 0xc5, 0xe3, 0xd4, 0x66, 0x84, 0xd2, 0x70, 0xc9, 0xee, 0x79, -0x98, 0x43, 0xc7, 0x5e, 0x27, 0xb6, 0x8a, 0xd2, 0x5a, 0x1f, 0xf3, 0xa9, -0xf7, 0x88, 0xce, 0x7d, 0x85, 0x71, 0xe0, 0x79, 0x98, 0x7a, 0x90, 0x9e, -0x1b, 0xd0, 0x13, 0x52, 0x4a, 0x66, 0x97, 0x7d, 0x33, 0x1e, 0xed, 0xae, -0xc7, 0x87, 0x1f, 0x7d, 0xce, 0xc2, 0xd5, 0x3a, 0xe6, 0xde, 0x02, 0xcb, -0xdb, 0x3e, 0xbe, 0xa6, 0x91, 0x95, 0x62, 0x6b, 0x2f, 0xce, 0x90, 0x3c, -0xfd, 0xce, 0x71, 0x0e, 0xcc, 0x3e, 0x82, 0x13, 0xf4, 0x09, 0xd5, 0x00, -0x16, 0x82, 0x98, 0xb3, 0x49, 0x24, 0xb1, 0x83, 0xc8, 0xc0, 0xd6, 0x3a, -0x54, 0x33, 0xab, 0x14, 0x8c, 0x16, 0x4e, 0x38, 0xcc, 0xe5, 0xeb, 0x4d, -0x5e, 0x7b, 0xfb, 0x4d, 0xaa, 0x79, 0xa1, 0x45, 0x1c, 0x9b, 0xd2, 0x94, -0xcc, 0x0e, 0x8c, 0x52, 0x7a, 0x65, 0x17, 0xc7, 0xa9, 0x0c, 0x8e, 0xe2, -0xf7, 0xba, 0xa8, 0xc8, 0x13, 0x87, 0x32, 0x87, 0x0b, 0x27, 0x30, 0x36, -0x57, 0xe8, 0xea, 0x15, 0xce, 0x06, 0x65, 0x5e, 0x3d, 0x5a, 0x94, 0x53, -0xb7, 0x59, 0x58, 0xdf, 0x25, 0xc4, 0xe4, 0xc9, 0x65, 0x3d, 0xb4, 0xb4, -0x4e, 0x37, 0x0c, 0x29, 0x98, 0x4a, 0xe8, 0x11, 0xde, 0x85, 0x42, 0x43, -0x1c, 0xaa, 0x38, 0x55, 0xc4, 0xb4, 0x2c, 0x22, 0x3d, 0xcd, 0xfa, 0xea, -0x0d, 0xf4, 0x8d, 0x1f, 0xc9, 0x5f, 0xfa, 0x82, 0x6d, 0xc7, 0xe1, 0xa6, -0x57, 0xe3, 0x56, 0x6e, 0x96, 0xbf, 0x16, 0x1f, 0xa3, 0x54, 0xaa, 0x91, -0x16, 0x5a, 0xb2, 0xa9, 0x04, 0xaf, 0x67, 0xc9, 0xac, 0x6c, 0xfa, 0x32, -0x9e, 0x48, 0xea, 0xa5, 0x0b, 0x89, 0x3b, 0x54, 0x47, 0xf2, 0xa1, 0xf2, -0x2a, 0x4d, 0xeb, 0xf4, 0x17, 0xdc, 0xd4, 0x72, 0x6c, 0xb5, 0x36, 0x28, -0xb6, 0x7e, 0x17, 0x04, 0xd3, 0xac, 0x7a, 0x42, 0xc1, 0xf4, 0x6e, 0x9e, -0xbf, 0x6b, 0xb7, 0x3c, 0x3a, 0x21, 0x67, 0xcb, 0x41, 0x48, 0x07, 0x91, -0xde, 0x1a, 0xe2, 0xaa, 0x9c, 0xb1, 0x59, 0xdb, 0x12, 0x25, 0xc1, 0x32, -0x92, 0xea, 0xc9, 0xaf, 0x3b, 0x97, 0xca, 0xca, 0xfe, 0x5b, 0xfe, 0xe5, -0x33, 0x29, 0xeb, 0x16, 0x95, 0xd2, 0x24, 0xeb, 0xda, 0x30, 0xeb, 0x95, -0x1a, 0xd3, 0xf7, 0x0f, 0x51, 0x1c, 0xd9, 0x0b, 0x99, 0x12, 0x7a, 0x4a, -0xd0, 0xd3, 0x25, 0x9a, 0x88, 0x45, 0xb1, 0x04, 0x33, 0x2c, 0x8a, 0x99, -0x34, 0x6b, 0x75, 0x19, 0x91, 0x9d, 0x92, 0x29, 0x89, 0xa0, 0x2c, 0x8b, -0x9d, 0xd8, 0x7a, 0x5e, 0x04, 0x07, 0x87, 0x66, 0x28, 0x56, 0x67, 0xb9, -0xd6, 0xd2, 0x39, 0xd9, 0xec, 0x33, 0x30, 0xb2, 0x8b, 0xea, 0xae, 0x83, -0x18, 0xb9, 0x31, 0x34, 0xbb, 0x42, 0x22, 0x0b, 0x21, 0x96, 0x3c, 0x61, -0xac, 0xcb, 0x95, 0x60, 0x2a, 0xe9, 0x68, 0x79, 0x08, 0x36, 0x56, 0x65, -0x27, 0x4a, 0xd9, 0x83, 0x00, 0xcf, 0x0b, 0xf1, 0xfc, 0x10, 0x15, 0x0a, -0x6a, 0x75, 0x77, 0x8b, 0x86, 0xdc, 0x58, 0x57, 0x45, 0x52, 0xe9, 0x84, -0x81, 0x7c, 0x91, 0x28, 0x55, 0x23, 0x96, 0x13, 0xd7, 0x24, 0xbe, 0xac, -0x17, 0xfa, 0xf2, 0x78, 0x63, 0xc7, 0x82, 0x08, 0xda, 0xa6, 0xc5, 0x50, -0x55, 0x04, 0xe5, 0x65, 0x5b, 0x06, 0xde, 0xce, 0xf0, 0x24, 0xf3, 0x4e, -0x70, 0xb5, 0x15, 0x6a, 0x34, 0x7b, 0x11, 0x9d, 0xbe, 0x10, 0x53, 0xd0, -0xa8, 0x86, 0x2e, 0x76, 0xb6, 0x2a, 0x9d, 0x2c, 0x48, 0x3c, 0x5b, 0xa2, -0xc8, 0x3a, 0x37, 0xd4, 0x9d, 0xed, 0x6c, 0x4a, 0xab, 0x95, 0x6e, 0x08, -0x66, 0x3d, 0x5a, 0xad, 0x4d, 0x18, 0xc8, 0xca, 0xfa, 0xd5, 0x85, 0x6f, -0xf9, 0x5f, 0xde, 0x02, 0x30, 0xff, 0x03, 0x8c, 0x47, 0x35, 0xad, 0xbc, -0xbf, 0x26, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, -0x42, 0x60, 0x82 - -}; - -unsigned int _Users_username_Pictures_SaltBae_png_len = 1863; - int main(int argc, const char * argv[]) { // insert code here... int frameless = 0; int resizable = 1; - int zoomable = 0; - int fullscreen = 1; + int fullscreen = 0; int fullSizeContent = 1; int hideTitleBar = 0; - int titlebarAppearsTransparent = 0; + int titlebarAppearsTransparent = 1; int hideTitle = 0; - int useToolbar = 0; - int hideToolbarSeparator = 0; - int webviewIsTransparent = 1; - int alwaysOnTop = 0; + int useToolbar = 1; + int hideToolbarSeparator = 1; + int webviewIsTransparent = 0; + int alwaysOnTop = 1; int hideWindowOnClose = 0; const char* appearance = "NSAppearanceNameDarkAqua"; int windowIsTranslucent = 1; - int devtoolsEnabled = 1; - int defaultContextMenuEnabled = 1; - int windowStartState = 0; - int startsHidden = 0; - WailsContext *result = Create("OI OI!",400,400, frameless, resizable, zoomable, fullscreen, fullSizeContent, hideTitleBar, titlebarAppearsTransparent, hideTitle, useToolbar, hideToolbarSeparator, webviewIsTransparent, alwaysOnTop, hideWindowOnClose, appearance, windowIsTranslucent, devtoolsEnabled, defaultContextMenuEnabled, windowStartState, - startsHidden, 400, 400, 600, 600, false); - SetBackgroundColour(result, 255, 0, 0, 255); - void *m = NewMenu(""); - SetAbout(result, "Fake title", "I am a description", _Users_username_Pictures_SaltBae_png, _Users_username_Pictures_SaltBae_png_len); -// AddMenuByRole(result, 1); + int debug = 1; + WailsContext *result = Create("OI OI!",400,400, frameless, resizable, fullscreen, fullSizeContent, hideTitleBar, titlebarAppearsTransparent, hideTitle, useToolbar, hideToolbarSeparator, webviewIsTransparent, alwaysOnTop, hideWindowOnClose, appearance, windowIsTranslucent, debug); + SetRGBA(result, 255, 0, 0, 255); - AppendRole(result, m, 1); - AppendRole(result, m, 2); - void* submenu = NewMenu("test"); - void* menuITem = AppendMenuItem(result, submenu, "Woohoo", "p", 0, 0, 0, 470); - AppendSubmenu(m, submenu); - UpdateMenuItem(menuITem, 1); - SetAsApplicationMenu(result, m); -// SetPosition(result, 100, 100); - Run((void*)CFBridgingRetain(result)); diff --git a/v2/internal/frontend/desktop/darwin/menu.go b/v2/internal/frontend/desktop/darwin/menu.go index 24dbe3201..3ccb156cf 100644 --- a/v2/internal/frontend/desktop/darwin/menu.go +++ b/v2/internal/frontend/desktop/darwin/menu.go @@ -3,132 +3,96 @@ package darwin -/* -#cgo CFLAGS: -x objective-c -#cgo LDFLAGS: -framework Foundation -framework Cocoa -framework WebKit -#import -#import "Application.h" -#import "WailsContext.h" - -#include -*/ -import "C" - import ( - "unsafe" - "github.com/wailsapp/wails/v2/pkg/menu" - "github.com/wailsapp/wails/v2/pkg/menu/keys" ) -type NSMenu struct { - context unsafe.Pointer - nsmenu unsafe.Pointer -} - -func NewNSMenu(context unsafe.Pointer, name string) *NSMenu { - c := NewCalloc() - defer c.Free() - title := c.String(name) - nsmenu := C.NewMenu(title) - return &NSMenu{ - context: context, - nsmenu: nsmenu, - } -} - -func (m *NSMenu) AddSubMenu(label string) *NSMenu { - result := NewNSMenu(m.context, label) - C.AppendSubmenu(m.nsmenu, result.nsmenu) - return result -} - -func (m *NSMenu) AppendRole(role menu.Role) { - C.AppendRole(m.context, m.nsmenu, C.int(role)) -} - -type MenuItem struct { - id uint - nsmenuitem unsafe.Pointer - wailsMenuItem *menu.MenuItem - radioGroupMembers []*MenuItem -} - -func (m *NSMenu) AddMenuItem(menuItem *menu.MenuItem) *MenuItem { - c := NewCalloc() - defer c.Free() - var modifier C.int - var key *C.char - if menuItem.Accelerator != nil { - modifier = C.int(keys.ToMacModifier(menuItem.Accelerator)) - key = c.String(menuItem.Accelerator.Key) - } - - result := &MenuItem{ - wailsMenuItem: menuItem, - } - - result.id = createMenuItemID(result) - result.nsmenuitem = C.AppendMenuItem(m.context, m.nsmenu, c.String(menuItem.Label), key, modifier, bool2Cint(menuItem.Disabled), bool2Cint(menuItem.Checked), C.int(result.id)) - return result -} - //func (w *Window) SetApplicationMenu(menu *menu.Menu) { //w.applicationMenu = menu //processMenu(w, menu) //} -func processMenu(parent *NSMenu, wailsMenu *menu.Menu) { - var radioGroups []*MenuItem +//func processMenu(window *Window, menu *menu.Menu) { +//mainMenu := window.NewMenu() +//for _, menuItem := range menu.Items { +// submenu := mainMenu.AddSubMenu(menuItem.Label) +// for _, menuItem := range menuItem.SubMenu.Items { +// processMenuItem(submenu, menuItem) +// } +//} +//mainMenu.Show() +//} - for _, menuItem := range wailsMenu.Items { - if menuItem.SubMenu != nil { - if len(radioGroups) > 0 { - processRadioGroups(radioGroups) - radioGroups = []*MenuItem{} - } - submenu := parent.AddSubMenu(menuItem.Label) - processMenu(submenu, menuItem.SubMenu) - } else { - lastMenuItem := processMenuItem(parent, menuItem) - if menuItem.Type == menu.RadioType { - radioGroups = append(radioGroups, lastMenuItem) - } else { - if len(radioGroups) > 0 { - processRadioGroups(radioGroups) - radioGroups = []*MenuItem{} - } - } - } - } -} - -func processRadioGroups(groups []*MenuItem) { - for _, item := range groups { - item.radioGroupMembers = groups - } -} - -func processMenuItem(parent *NSMenu, menuItem *menu.MenuItem) *MenuItem { - if menuItem.Hidden { - return nil - } - if menuItem.Role != 0 { - parent.AppendRole(menuItem.Role) - return nil - } - if menuItem.Type == menu.SeparatorType { - C.AppendSeparator(parent.nsmenu) - return nil - } - - return parent.AddMenuItem(menuItem) -} +//func processMenuItem(parent *winc.MenuItem, menuItem *menu.MenuItem) { +// if menuItem.Hidden { +// return +// } +// switch menuItem.Type { +// case menu.SeparatorType: +// parent.AddSeparator() +// case menu.TextType: +// shortcut := acceleratorToWincShortcut(menuItem.Accelerator) +// newItem := parent.AddItem(menuItem.Label, shortcut) +// if menuItem.Tooltip != "" { +// newItem.SetToolTip(menuItem.Tooltip) +// } +// if menuItem.Click != nil { +// newItem.OnClick().Bind(func(e *winc.Event) { +// menuItem.Click(&menu.CallbackData{ +// MenuItem: menuItem, +// }) +// }) +// } +// newItem.SetEnabled(!menuItem.Disabled) +// +// case menu.CheckboxType: +// shortcut := acceleratorToWincShortcut(menuItem.Accelerator) +// newItem := parent.AddItem(menuItem.Label, shortcut) +// newItem.SetCheckable(true) +// newItem.SetChecked(menuItem.Checked) +// if menuItem.Tooltip != "" { +// newItem.SetToolTip(menuItem.Tooltip) +// } +// if menuItem.Click != nil { +// newItem.OnClick().Bind(func(e *winc.Event) { +// toggleCheckBox(menuItem) +// menuItem.Click(&menu.CallbackData{ +// MenuItem: menuItem, +// }) +// }) +// } +// newItem.SetEnabled(!menuItem.Disabled) +// addCheckBoxToMap(menuItem, newItem) +// case menu.RadioType: +// shortcut := acceleratorToWincShortcut(menuItem.Accelerator) +// newItem := parent.AddItemRadio(menuItem.Label, shortcut) +// newItem.SetCheckable(true) +// newItem.SetChecked(menuItem.Checked) +// if menuItem.Tooltip != "" { +// newItem.SetToolTip(menuItem.Tooltip) +// } +// if menuItem.Click != nil { +// newItem.OnClick().Bind(func(e *winc.Event) { +// toggleRadioItem(menuItem) +// menuItem.Click(&menu.CallbackData{ +// MenuItem: menuItem, +// }) +// }) +// } +// newItem.SetEnabled(!menuItem.Disabled) +// addRadioItemToMap(menuItem, newItem) +// case menu.SubmenuType: +// submenu := parent.AddSubMenu(menuItem.Label) +// for _, menuItem := range menuItem.SubMenu.Items { +// processMenuItem(submenu, menuItem) +// } +// } +//} func (f *Frontend) MenuSetApplicationMenu(menu *menu.Menu) { - f.mainWindow.SetApplicationMenu(menu) + //f.mainWindow.SetApplicationMenu(menu) } func (f *Frontend) MenuUpdateApplicationMenu() { - f.mainWindow.UpdateApplicationMenu() + //processMenu(f.mainWindow, f.mainWindow.applicationMenu) } diff --git a/v2/internal/frontend/desktop/darwin/menuitem.go b/v2/internal/frontend/desktop/darwin/menuitem.go deleted file mode 100644 index 64aab84a9..000000000 --- a/v2/internal/frontend/desktop/darwin/menuitem.go +++ /dev/null @@ -1,54 +0,0 @@ -//go:build darwin -// +build darwin - -package darwin - -/* -#cgo CFLAGS: -x objective-c -#cgo LDFLAGS: -framework Foundation -framework Cocoa -framework WebKit -#import -#import "Application.h" -#import "WailsContext.h" - -#include -*/ -import "C" - -import ( - "log" - "math" - "sync" -) - -var ( - menuItemToID = make(map[*MenuItem]uint) - idToMenuItem = make(map[uint]*MenuItem) - menuItemLock sync.Mutex - menuItemIDCounter uint = 0 -) - -func createMenuItemID(item *MenuItem) uint { - menuItemLock.Lock() - defer menuItemLock.Unlock() - counter := 0 - for { - menuItemIDCounter++ - value := idToMenuItem[menuItemIDCounter] - if value == nil { - break - } - counter++ - if counter == math.MaxInt { - log.Fatal("insane amounts of menuitems detected! Aborting before the collapse of the world!") - } - } - idToMenuItem[menuItemIDCounter] = item - menuItemToID[item] = menuItemIDCounter - return menuItemIDCounter -} - -func getMenuItemForID(id uint) *MenuItem { - menuItemLock.Lock() - defer menuItemLock.Unlock() - return idToMenuItem[id] -} diff --git a/v2/internal/frontend/desktop/darwin/message.h b/v2/internal/frontend/desktop/darwin/message.h index 86506f868..51f242ccc 100644 --- a/v2/internal/frontend/desktop/darwin/message.h +++ b/v2/internal/frontend/desktop/darwin/message.h @@ -15,12 +15,10 @@ extern "C" #endif void processMessage(const char *); -void processBindingMessage(const char *, const char *, bool); -void processURLRequest(void *, void*); +void processURLRequest(void*, const char *); void processMessageDialogResponse(int); void processOpenFileDialogResponse(const char*); void processSaveFileDialogResponse(const char*); -void processCallback(int); #ifdef __cplusplus } diff --git a/v2/internal/frontend/desktop/darwin/screen.go b/v2/internal/frontend/desktop/darwin/screen.go deleted file mode 100644 index bd64a31f9..000000000 --- a/v2/internal/frontend/desktop/darwin/screen.go +++ /dev/null @@ -1,118 +0,0 @@ -//go:build darwin -// +build darwin - -package darwin - -/* -#cgo CFLAGS: -x objective-c -#cgo LDFLAGS: -framework Foundation -framework Cocoa -framework WebKit -framework AppKit -#import -#include -#include - -#import "Application.h" -#import "WailsContext.h" - -typedef struct Screen { - int isCurrent; - int isPrimary; - int height; - int width; - int pHeight; - int pWidth; -} Screen; - - -int GetNumScreens(){ - return [[NSScreen screens] count]; -} - -int screenUniqueID(NSScreen *screen){ - // adapted from https://stackoverflow.com/a/1237490/4188138 - NSDictionary* screenDictionary = [screen deviceDescription]; - NSNumber* screenID = [screenDictionary objectForKey:@"NSScreenNumber"]; - CGDirectDisplayID aID = [screenID unsignedIntValue]; - return aID; -} - -Screen GetNthScreen(int nth, void *inctx){ - WailsContext *ctx = (__bridge WailsContext*) inctx; - NSArray *screens = [NSScreen screens]; - NSScreen* nthScreen = [screens objectAtIndex:nth]; - NSScreen* currentScreen = [ctx getCurrentScreen]; - - Screen returnScreen; - returnScreen.isCurrent = (int)(screenUniqueID(currentScreen)==screenUniqueID(nthScreen)); - // TODO properly handle screen mirroring - // from apple documentation: - // https://developer.apple.com/documentation/appkit/nsscreen/1388393-screens?language=objc - // The screen at index 0 in the returned array corresponds to the primary screen of the user’s system. This is the screen that contains the menu bar and whose origin is at the point (0, 0). In the case of mirroring, the first screen is the largest drawable display; if all screens are the same size, it is the screen with the highest pixel depth. This primary screen may not be the same as the one returned by the mainScreen method, which returns the screen with the active window. - returnScreen.isPrimary = nth==0; - returnScreen.height = (int) nthScreen.frame.size.height; - returnScreen.width = (int) nthScreen.frame.size.width; - - returnScreen.pWidth = 0; - returnScreen.pHeight = 0; - - // https://stackoverflow.com/questions/13859109/how-to-programmatically-determine-native-pixel-resolution-of-retina-macbook-pro - CGDirectDisplayID sid = ((NSNumber *)[nthScreen.deviceDescription - objectForKey:@"NSScreenNumber"]).unsignedIntegerValue; - - CFArrayRef ms = CGDisplayCopyAllDisplayModes(sid, NULL); - CFIndex n = CFArrayGetCount(ms); - for (int i = 0; i < n; i++) { - CGDisplayModeRef m = (CGDisplayModeRef) CFArrayGetValueAtIndex(ms, i); - if (CGDisplayModeGetIOFlags(m) & kDisplayModeNativeFlag) { - // This corresponds with "System Settings" -> General -> About -> Displays - returnScreen.pWidth = CGDisplayModeGetPixelWidth(m); - returnScreen.pHeight = CGDisplayModeGetPixelHeight(m); - break; - } - } - CFRelease(ms); - - if (returnScreen.pWidth == 0 || returnScreen.pHeight == 0) { - // If there was no native resolution take a best fit approach and use the backing pixel size. - NSRect pSize = [nthScreen convertRectToBacking:nthScreen.frame]; - returnScreen.pHeight = (int) pSize.size.height; - returnScreen.pWidth = (int) pSize.size.width; - } - return returnScreen; -} - -*/ -import "C" - -import ( - "unsafe" - - "github.com/wailsapp/wails/v2/internal/frontend" -) - -func GetAllScreens(wailsContext unsafe.Pointer) ([]frontend.Screen, error) { - err := error(nil) - screens := []frontend.Screen{} - numScreens := int(C.GetNumScreens()) - for screeNum := 0; screeNum < numScreens; screeNum++ { - screenNumC := C.int(screeNum) - cScreen := C.GetNthScreen(screenNumC, wailsContext) - - screen := frontend.Screen{ - Height: int(cScreen.height), - Width: int(cScreen.width), - IsCurrent: cScreen.isCurrent == C.int(1), - IsPrimary: cScreen.isPrimary == C.int(1), - - Size: frontend.ScreenSize{ - Height: int(cScreen.height), - Width: int(cScreen.width), - }, - PhysicalSize: frontend.ScreenSize{ - Height: int(cScreen.pHeight), - Width: int(cScreen.pWidth), - }, - } - screens = append(screens, screen) - } - return screens, err -} diff --git a/v2/internal/frontend/desktop/darwin/single_instance.go b/v2/internal/frontend/desktop/darwin/single_instance.go deleted file mode 100644 index 27b34045b..000000000 --- a/v2/internal/frontend/desktop/darwin/single_instance.go +++ /dev/null @@ -1,95 +0,0 @@ -//go:build darwin -// +build darwin - -package darwin - -/* -#cgo CFLAGS: -x objective-c -#cgo LDFLAGS: -framework Foundation -framework Cocoa -#import "AppDelegate.h" - -*/ -import "C" - -import ( - "encoding/json" - "fmt" - "os" - "strings" - "syscall" - "unsafe" - - "github.com/wailsapp/wails/v2/pkg/options" -) - -func SetupSingleInstance(uniqueID string) *os.File { - lockFilePath := getTempDir() - lockFileName := uniqueID + ".lock" - file, err := createLockFile(lockFilePath + "/" + lockFileName) - // if lockFile exist – send notification to second instance - if err != nil { - c := NewCalloc() - defer c.Free() - singleInstanceUniqueId := c.String(uniqueID) - - data, err := options.NewSecondInstanceData() - if err != nil { - return nil - } - - serialized, err := json.Marshal(data) - if err != nil { - return nil - } - - C.SendDataToFirstInstance(singleInstanceUniqueId, c.String(string(serialized))) - - os.Exit(0) - } - - return file -} - -//export HandleSecondInstanceData -func HandleSecondInstanceData(secondInstanceMessage *C.char) { - message := C.GoString(secondInstanceMessage) - - var secondInstanceData options.SecondInstanceData - - err := json.Unmarshal([]byte(message), &secondInstanceData) - if err == nil { - secondInstanceBuffer <- secondInstanceData - } -} - -// createLockFile tries to create a file with given name and acquire an -// exclusive lock on it. If the file already exists AND is still locked, it will -// fail. -func createLockFile(filename string) (*os.File, error) { - file, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE, 0o600) - if err != nil { - fmt.Printf("Failed to open lockfile %s: %s", filename, err) - return nil, err - } - - err = syscall.Flock(int(file.Fd()), syscall.LOCK_EX|syscall.LOCK_NB) - if err != nil { - // Flock failed for some other reason than other instance already lock it. Print it in logs for possible debugging. - if !strings.Contains(err.Error(), "resource temporarily unavailable") { - fmt.Printf("Failed to lock lockfile %s: %s", filename, err) - } - file.Close() - return nil, err - } - - return file, nil -} - -// If app is sandboxed, golang os.TempDir() will return path that will not be accessible. So use native macOS temp dir function. -func getTempDir() string { - cstring := C.GetMacOsNativeTempDir() - path := C.GoString(cstring) - C.free(unsafe.Pointer(cstring)) - - return path -} diff --git a/v2/internal/frontend/desktop/darwin/window.go b/v2/internal/frontend/desktop/darwin/window.go index 87d4213d9..b12937d42 100644 --- a/v2/internal/frontend/desktop/darwin/window.go +++ b/v2/internal/frontend/desktop/darwin/window.go @@ -1,6 +1,3 @@ -//go:build darwin -// +build darwin - package darwin /* @@ -13,7 +10,6 @@ package darwin #include */ import "C" - import ( "log" "runtime" @@ -21,8 +17,6 @@ import ( "strings" "unsafe" - "github.com/wailsapp/wails/v2/pkg/menu" - "github.com/wailsapp/wails/v2/pkg/options" ) @@ -32,8 +26,6 @@ func init() { type Window struct { context unsafe.Pointer - - applicationMenu *menu.Menu } func bool2Cint(value bool) C.int { @@ -43,12 +35,8 @@ func bool2Cint(value bool) C.int { return C.int(0) } -func bool2CboolPtr(value bool) *C.bool { - v := C.bool(value) - return &v -} +func NewWindow(frontendOptions *options.App, debugMode bool) *Window { -func NewWindow(frontendOptions *options.App, debug bool, devtools bool) *Window { c := NewCalloc() defer c.Free() @@ -57,37 +45,21 @@ func NewWindow(frontendOptions *options.App, debug bool, devtools bool) *Window fullscreen := bool2Cint(frontendOptions.Fullscreen) alwaysOnTop := bool2Cint(frontendOptions.AlwaysOnTop) hideWindowOnClose := bool2Cint(frontendOptions.HideWindowOnClose) - startsHidden := bool2Cint(frontendOptions.StartHidden) - devtoolsEnabled := bool2Cint(devtools) - defaultContextMenuEnabled := bool2Cint(debug || frontendOptions.EnableDefaultContextMenu) - singleInstanceEnabled := bool2Cint(frontendOptions.SingleInstanceLock != nil) + debug := bool2Cint(debugMode) + alpha := C.int(frontendOptions.RGBA.A) + red := C.int(frontendOptions.RGBA.R) + green := C.int(frontendOptions.RGBA.G) + blue := C.int(frontendOptions.RGBA.B) - var fullSizeContent, hideTitleBar, zoomable, hideTitle, useToolbar, webviewIsTransparent C.int - var titlebarAppearsTransparent, hideToolbarSeparator, windowIsTranslucent, contentProtection C.int + var fullSizeContent, hideTitleBar, hideTitle, useToolbar, webviewIsTransparent C.int + var titlebarAppearsTransparent, hideToolbarSeparator, windowIsTranslucent C.int var appearance, title *C.char - var preferences C.struct_Preferences width := C.int(frontendOptions.Width) height := C.int(frontendOptions.Height) - minWidth := C.int(frontendOptions.MinWidth) - minHeight := C.int(frontendOptions.MinHeight) - maxWidth := C.int(frontendOptions.MaxWidth) - maxHeight := C.int(frontendOptions.MaxHeight) - windowStartState := C.int(int(frontendOptions.WindowStartState)) title = c.String(frontendOptions.Title) - singleInstanceUniqueIdStr := "" - if frontendOptions.SingleInstanceLock != nil { - singleInstanceUniqueIdStr = frontendOptions.SingleInstanceLock.UniqueId - } - singleInstanceUniqueId := c.String(singleInstanceUniqueIdStr) - - enableFraudulentWebsiteWarnings := C.bool(frontendOptions.EnableFraudulentWebsiteDetection) - - enableDragAndDrop := C.bool(frontendOptions.DragAndDrop != nil && frontendOptions.DragAndDrop.EnableFileDrop) - disableWebViewDragAndDrop := C.bool(frontendOptions.DragAndDrop != nil && frontendOptions.DragAndDrop.DisableWebViewDrop) - if frontendOptions.Mac != nil { mac := frontendOptions.Mac if mac.TitleBar != nil { @@ -98,83 +70,35 @@ func NewWindow(frontendOptions *options.App, debug bool, devtools bool) *Window titlebarAppearsTransparent = bool2Cint(mac.TitleBar.TitlebarAppearsTransparent) hideToolbarSeparator = bool2Cint(mac.TitleBar.HideToolbarSeparator) } - - if mac.Preferences != nil { - if mac.Preferences.TabFocusesLinks.IsSet() { - preferences.tabFocusesLinks = bool2CboolPtr(mac.Preferences.TabFocusesLinks.Get()) - } - - if mac.Preferences.TextInteractionEnabled.IsSet() { - preferences.textInteractionEnabled = bool2CboolPtr(mac.Preferences.TextInteractionEnabled.Get()) - } - - if mac.Preferences.FullscreenEnabled.IsSet() { - preferences.fullscreenEnabled = bool2CboolPtr(mac.Preferences.FullscreenEnabled.Get()) - } - } - - zoomable = bool2Cint(!frontendOptions.Mac.DisableZoom) - windowIsTranslucent = bool2Cint(mac.WindowIsTranslucent) webviewIsTransparent = bool2Cint(mac.WebviewIsTransparent) - contentProtection = bool2Cint(mac.ContentProtection) appearance = c.String(string(mac.Appearance)) } - var context *C.WailsContext = C.Create(title, width, height, frameless, resizable, zoomable, fullscreen, fullSizeContent, - hideTitleBar, titlebarAppearsTransparent, hideTitle, useToolbar, hideToolbarSeparator, webviewIsTransparent, - alwaysOnTop, hideWindowOnClose, appearance, windowIsTranslucent, contentProtection, devtoolsEnabled, defaultContextMenuEnabled, - windowStartState, startsHidden, minWidth, minHeight, maxWidth, maxHeight, enableFraudulentWebsiteWarnings, - preferences, singleInstanceEnabled, singleInstanceUniqueId, enableDragAndDrop, disableWebViewDragAndDrop, - ) + var context *C.WailsContext = C.Create(title, width, height, frameless, resizable, fullscreen, fullSizeContent, hideTitleBar, titlebarAppearsTransparent, hideTitle, useToolbar, hideToolbarSeparator, webviewIsTransparent, alwaysOnTop, hideWindowOnClose, appearance, windowIsTranslucent, debug) - // Create menu - result := &Window{ + C.SetRGBA(unsafe.Pointer(context), red, green, blue, alpha) + + return &Window{ context: unsafe.Pointer(context), } - - if frontendOptions.BackgroundColour != nil { - result.SetBackgroundColour(frontendOptions.BackgroundColour.R, frontendOptions.BackgroundColour.G, frontendOptions.BackgroundColour.B, frontendOptions.BackgroundColour.A) - } - - if frontendOptions.Mac != nil && frontendOptions.Mac.About != nil { - title := c.String(frontendOptions.Mac.About.Title) - description := c.String(frontendOptions.Mac.About.Message) - var icon unsafe.Pointer - var length C.int - if frontendOptions.Mac.About.Icon != nil { - icon = unsafe.Pointer(&frontendOptions.Mac.About.Icon[0]) - length = C.int(len(frontendOptions.Mac.About.Icon)) - } - C.SetAbout(result.context, title, description, icon, length) - } - - if frontendOptions.Menu != nil { - result.SetApplicationMenu(frontendOptions.Menu) - } - - if debug && frontendOptions.Debug.OpenInspectorOnStartup { - showInspector(result.context) - } - return result } func (w *Window) Center() { C.Center(w.context) } -func (w *Window) Run(url string) { - _url := C.CString(url) - C.Run(w.context, _url) - C.free(unsafe.Pointer(_url)) +func (w *Window) Run() { + C.Run(w.context) + println("I exited!") } func (w *Window) Quit() { C.Quit(w.context) } -func (w *Window) SetBackgroundColour(r uint8, g uint8, b uint8, a uint8) { - C.SetBackgroundColour(w.context, C.int(r), C.int(g), C.int(b), C.int(a)) +func (w *Window) SetRGBA(r uint8, g uint8, b uint8, a uint8) { + C.SetRGBA(w.context, C.int(r), C.int(g), C.int(b), C.int(a)) } func (w *Window) ExecJS(js string) { @@ -183,7 +107,7 @@ func (w *Window) ExecJS(js string) { C.free(unsafe.Pointer(_js)) } -func (w *Window) SetPosition(x int, y int) { +func (w *Window) SetPos(x int, y int) { C.SetPosition(w.context, C.int(x), C.int(y)) } @@ -191,10 +115,6 @@ func (w *Window) SetSize(width int, height int) { C.SetSize(w.context, C.int(width), C.int(height)) } -func (w *Window) SetAlwaysOnTop(onTop bool) { - C.SetAlwaysOnTop(w.context, bool2Cint(onTop)) -} - func (w *Window) SetTitle(title string) { t := C.CString(title) C.SetTitle(w.context, t) @@ -205,18 +125,10 @@ func (w *Window) Maximise() { C.Maximise(w.context) } -func (w *Window) ToggleMaximise() { - C.ToggleMaximise(w.context) -} - func (w *Window) UnMaximise() { C.UnMaximise(w.context) } -func (w *Window) IsMaximised() bool { - return (bool)(C.IsMaximised(w.context)) -} - func (w *Window) Minimise() { C.Minimise(w.context) } @@ -225,14 +137,6 @@ func (w *Window) UnMinimise() { C.UnMinimise(w.context) } -func (w *Window) IsMinimised() bool { - return (bool)(C.IsMinimised(w.context)) -} - -func (w *Window) IsNormal() bool { - return !w.IsMaximised() && !w.IsMinimised() && !w.IsFullScreen() -} - func (w *Window) SetMinSize(width int, height int) { C.SetMinSize(w.context, C.int(width), C.int(height)) } @@ -249,10 +153,6 @@ func (w *Window) UnFullscreen() { C.UnFullscreen(w.context) } -func (w *Window) IsFullScreen() bool { - return (bool)(C.IsFullScreen(w.context)) -} - func (w *Window) Show() { C.Show(w.context) } @@ -261,14 +161,6 @@ func (w *Window) Hide() { C.Hide(w.context) } -func (w *Window) ShowApplication() { - C.ShowApplication(w.context) -} - -func (w *Window) HideApplication() { - C.HideApplication(w.context) -} - func parseIntDuo(temp string) (int, int) { split := strings.Split(temp, ",") x, err := strconv.Atoi(split[0]) @@ -282,8 +174,8 @@ func parseIntDuo(temp string) (int, int) { return x, y } -func (w *Window) GetPosition() (int, int) { - var _result *C.char = C.GetPosition(w.context) +func (w *Window) Pos() (int, int) { + var _result *C.char = C.GetPos(w.context) temp := C.GoString(_result) return parseIntDuo(temp) } @@ -293,21 +185,3 @@ func (w *Window) Size() (int, int) { temp := C.GoString(_result) return parseIntDuo(temp) } - -func (w *Window) SetApplicationMenu(inMenu *menu.Menu) { - w.applicationMenu = inMenu - w.UpdateApplicationMenu() -} - -func (w *Window) UpdateApplicationMenu() { - mainMenu := NewNSMenu(w.context, "") - if w.applicationMenu != nil { - processMenu(mainMenu, w.applicationMenu) - } - C.SetAsApplicationMenu(w.context, mainMenu.nsmenu) - C.UpdateApplicationMenu(w.context) -} - -func (w Window) Print() { - C.WindowPrint(w.context) -} diff --git a/v2/internal/frontend/desktop/desktop_darwin.go b/v2/internal/frontend/desktop/desktop_darwin.go index c02c0cdbd..fbf977fd5 100644 --- a/v2/internal/frontend/desktop/desktop_darwin.go +++ b/v2/internal/frontend/desktop/desktop_darwin.go @@ -1,5 +1,4 @@ //go:build darwin -// +build darwin package desktop diff --git a/v2/internal/frontend/desktop/desktop_linux.go b/v2/internal/frontend/desktop/desktop_linux.go deleted file mode 100644 index e057a9e18..000000000 --- a/v2/internal/frontend/desktop/desktop_linux.go +++ /dev/null @@ -1,17 +0,0 @@ -//go:build linux -// +build linux - -package desktop - -import ( - "context" - "github.com/wailsapp/wails/v2/internal/binding" - "github.com/wailsapp/wails/v2/internal/frontend" - "github.com/wailsapp/wails/v2/internal/frontend/desktop/linux" - "github.com/wailsapp/wails/v2/internal/logger" - "github.com/wailsapp/wails/v2/pkg/options" -) - -func NewFrontend(ctx context.Context, appoptions *options.App, logger *logger.Logger, appBindings *binding.Bindings, dispatcher frontend.Dispatcher) frontend.Frontend { - return linux.NewFrontend(ctx, appoptions, logger, appBindings, dispatcher) -} diff --git a/v2/internal/frontend/desktop/desktop_windows.go b/v2/internal/frontend/desktop/desktop_windows.go index f9a680aac..f3c8e05d9 100644 --- a/v2/internal/frontend/desktop/desktop_windows.go +++ b/v2/internal/frontend/desktop/desktop_windows.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package desktop diff --git a/v2/internal/frontend/desktop/linux/browser.go b/v2/internal/frontend/desktop/linux/browser.go deleted file mode 100644 index 962e3b28a..000000000 --- a/v2/internal/frontend/desktop/linux/browser.go +++ /dev/null @@ -1,23 +0,0 @@ -//go:build linux -// +build linux - -package linux - -import ( - "fmt" - "github.com/pkg/browser" - "github.com/wailsapp/wails/v2/internal/frontend/utils" -) - -// BrowserOpenURL Use the default browser to open the url -func (f *Frontend) BrowserOpenURL(rawURL string) { - url, err := utils.ValidateAndSanitizeURL(rawURL) - if err != nil { - f.logger.Error(fmt.Sprintf("Invalid URL %s", err.Error())) - return - } - // Specific method implementation - if err := browser.OpenURL(url); err != nil { - f.logger.Error("Unable to open default system browser") - } -} diff --git a/v2/internal/frontend/desktop/linux/calloc.go b/v2/internal/frontend/desktop/linux/calloc.go deleted file mode 100644 index 27e5ad18d..000000000 --- a/v2/internal/frontend/desktop/linux/calloc.go +++ /dev/null @@ -1,35 +0,0 @@ -//go:build linux -// +build linux - -package linux - -/* -#include -*/ -import "C" -import "unsafe" - -// Calloc handles alloc/dealloc of C data -type Calloc struct { - pool []unsafe.Pointer -} - -// NewCalloc creates a new allocator -func NewCalloc() Calloc { - return Calloc{} -} - -// String creates a new C string and retains a reference to it -func (c Calloc) String(in string) *C.char { - result := C.CString(in) - c.pool = append(c.pool, unsafe.Pointer(result)) - return result -} - -// Free frees all allocated C memory -func (c Calloc) Free() { - for _, str := range c.pool { - C.free(str) - } - c.pool = []unsafe.Pointer{} -} diff --git a/v2/internal/frontend/desktop/linux/clipboard.go b/v2/internal/frontend/desktop/linux/clipboard.go deleted file mode 100644 index a2a46dacc..000000000 --- a/v2/internal/frontend/desktop/linux/clipboard.go +++ /dev/null @@ -1,51 +0,0 @@ -//go:build linux -// +build linux - -package linux - -/* -#cgo linux pkg-config: gtk+-3.0 -#cgo !webkit2_41 pkg-config: webkit2gtk-4.0 -#cgo webkit2_41 pkg-config: webkit2gtk-4.1 - -#include "gtk/gtk.h" -#include "webkit2/webkit2.h" - -static gchar* GetClipboardText() { - GtkClipboard *clip = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); - return gtk_clipboard_wait_for_text(clip); -} - -static void SetClipboardText(gchar* text) { - GtkClipboard *clip = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); - gtk_clipboard_set_text(clip, text, -1); - - clip = gtk_clipboard_get(GDK_SELECTION_PRIMARY); - gtk_clipboard_set_text(clip, text, -1); -} -*/ -import "C" -import "sync" - -func (f *Frontend) ClipboardGetText() (string, error) { - var text string - var wg sync.WaitGroup - wg.Add(1) - invokeOnMainThread(func() { - ctxt := C.GetClipboardText() - defer C.g_free(C.gpointer(ctxt)) - text = C.GoString(ctxt) - wg.Done() - }) - wg.Wait() - return text, nil -} - -func (f *Frontend) ClipboardSetText(text string) error { - invokeOnMainThread(func() { - ctxt := (*C.gchar)(C.CString(text)) - defer C.g_free(C.gpointer(ctxt)) - C.SetClipboardText(ctxt) - }) - return nil -} diff --git a/v2/internal/frontend/desktop/linux/dialog.go b/v2/internal/frontend/desktop/linux/dialog.go deleted file mode 100644 index c0d9158e5..000000000 --- a/v2/internal/frontend/desktop/linux/dialog.go +++ /dev/null @@ -1,89 +0,0 @@ -//go:build linux -// +build linux - -package linux - -import ( - "github.com/wailsapp/wails/v2/internal/frontend" - "unsafe" -) - -/* -#include -#include "gtk/gtk.h" -*/ -import "C" - -const ( - GTK_FILE_CHOOSER_ACTION_OPEN C.GtkFileChooserAction = C.GTK_FILE_CHOOSER_ACTION_OPEN - GTK_FILE_CHOOSER_ACTION_SAVE C.GtkFileChooserAction = C.GTK_FILE_CHOOSER_ACTION_SAVE - GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER C.GtkFileChooserAction = C.GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER -) - -var openFileResults = make(chan []string) -var messageDialogResult = make(chan string) - -func (f *Frontend) OpenFileDialog(dialogOptions frontend.OpenDialogOptions) (result string, err error) { - f.mainWindow.OpenFileDialog(dialogOptions, 0, GTK_FILE_CHOOSER_ACTION_OPEN) - results := <-openFileResults - if len(results) == 1 { - return results[0], nil - } - return "", nil -} - -func (f *Frontend) OpenMultipleFilesDialog(dialogOptions frontend.OpenDialogOptions) ([]string, error) { - f.mainWindow.OpenFileDialog(dialogOptions, 1, GTK_FILE_CHOOSER_ACTION_OPEN) - result := <-openFileResults - return result, nil -} - -func (f *Frontend) OpenDirectoryDialog(dialogOptions frontend.OpenDialogOptions) (string, error) { - f.mainWindow.OpenFileDialog(dialogOptions, 0, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER) - result := <-openFileResults - if len(result) == 1 { - return result[0], nil - } - return "", nil -} - -func (f *Frontend) SaveFileDialog(dialogOptions frontend.SaveDialogOptions) (string, error) { - options := frontend.OpenDialogOptions{ - DefaultDirectory: dialogOptions.DefaultDirectory, - DefaultFilename: dialogOptions.DefaultFilename, - Title: dialogOptions.Title, - Filters: dialogOptions.Filters, - ShowHiddenFiles: dialogOptions.ShowHiddenFiles, - CanCreateDirectories: dialogOptions.CanCreateDirectories, - } - f.mainWindow.OpenFileDialog(options, 0, GTK_FILE_CHOOSER_ACTION_SAVE) - results := <-openFileResults - if len(results) == 1 { - return results[0], nil - } - return "", nil -} - -func (f *Frontend) MessageDialog(dialogOptions frontend.MessageDialogOptions) (string, error) { - f.mainWindow.MessageDialog(dialogOptions) - return <-messageDialogResult, nil -} - -//export processOpenFileResult -func processOpenFileResult(carray **C.char) { - // Create a Go slice from the C array - var result []string - goArray := (*[1024]*C.char)(unsafe.Pointer(carray))[:1024:1024] - for _, s := range goArray { - if s == nil { - break - } - result = append(result, C.GoString(s)) - } - openFileResults <- result -} - -//export processMessageDialogResult -func processMessageDialogResult(result *C.char) { - messageDialogResult <- C.GoString(result) -} diff --git a/v2/internal/frontend/desktop/linux/frontend.go b/v2/internal/frontend/desktop/linux/frontend.go deleted file mode 100644 index 2942a112e..000000000 --- a/v2/internal/frontend/desktop/linux/frontend.go +++ /dev/null @@ -1,589 +0,0 @@ -//go:build linux -// +build linux - -package linux - -/* -#cgo linux pkg-config: gtk+-3.0 -#cgo !webkit2_41 pkg-config: webkit2gtk-4.0 -#cgo webkit2_41 pkg-config: webkit2gtk-4.1 - -#include "gtk/gtk.h" -#include "webkit2/webkit2.h" - -// CREDIT: https://github.com/rainycape/magick -#include -#include -#include -#include - -static void fix_signal(int signum) -{ - struct sigaction st; - - if (sigaction(signum, NULL, &st) < 0) { - goto fix_signal_error; - } - st.sa_flags |= SA_ONSTACK; - if (sigaction(signum, &st, NULL) < 0) { - goto fix_signal_error; - } - return; -fix_signal_error: - fprintf(stderr, "error fixing handler for signal %d, please " - "report this issue to " - "https://github.com/wailsapp/wails: %s\n", - signum, strerror(errno)); -} - -static void install_signal_handlers() -{ -#if defined(SIGCHLD) - fix_signal(SIGCHLD); -#endif -#if defined(SIGHUP) - fix_signal(SIGHUP); -#endif -#if defined(SIGINT) - fix_signal(SIGINT); -#endif -#if defined(SIGQUIT) - fix_signal(SIGQUIT); -#endif -#if defined(SIGABRT) - fix_signal(SIGABRT); -#endif -#if defined(SIGFPE) - fix_signal(SIGFPE); -#endif -#if defined(SIGTERM) - fix_signal(SIGTERM); -#endif -#if defined(SIGBUS) - fix_signal(SIGBUS); -#endif -#if defined(SIGSEGV) - fix_signal(SIGSEGV); -#endif -#if defined(SIGXCPU) - fix_signal(SIGXCPU); -#endif -#if defined(SIGXFSZ) - fix_signal(SIGXFSZ); -#endif -} - -static gboolean install_signal_handlers_idle(gpointer data) { - (void)data; - install_signal_handlers(); - return G_SOURCE_REMOVE; -} - -static void fix_signal_handlers_after_gtk_init() { - g_idle_add(install_signal_handlers_idle, NULL); -} - -*/ -import "C" -import ( - "context" - "encoding/json" - "errors" - "fmt" - "log" - "net" - "net/url" - "os" - "runtime" - "strings" - "sync" - "text/template" - "unsafe" - - "github.com/wailsapp/wails/v2/pkg/assetserver" - "github.com/wailsapp/wails/v2/pkg/assetserver/webview" - - "github.com/wailsapp/wails/v2/internal/binding" - "github.com/wailsapp/wails/v2/internal/frontend" - "github.com/wailsapp/wails/v2/internal/frontend/originvalidator" - wailsruntime "github.com/wailsapp/wails/v2/internal/frontend/runtime" - "github.com/wailsapp/wails/v2/internal/logger" - "github.com/wailsapp/wails/v2/pkg/options" -) - -var initOnce = sync.Once{} - -const startURL = "wails://wails/" - -var secondInstanceBuffer = make(chan options.SecondInstanceData, 1) - -type Frontend struct { - - // Context - ctx context.Context - - frontendOptions *options.App - logger *logger.Logger - debug bool - devtoolsEnabled bool - - // Assets - assets *assetserver.AssetServer - startURL *url.URL - - // main window handle - mainWindow *Window - bindings *binding.Bindings - dispatcher frontend.Dispatcher - - originValidator *originvalidator.OriginValidator -} - -func (f *Frontend) RunMainLoop() { - C.gtk_main() -} - -func (f *Frontend) WindowClose() { - f.mainWindow.Destroy() -} - -func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.Logger, appBindings *binding.Bindings, dispatcher frontend.Dispatcher) *Frontend { - initOnce.Do(func() { - runtime.LockOSThread() - - // Set GDK_BACKEND=x11 if currently unset and XDG_SESSION_TYPE is unset, unspecified or x11 to prevent warnings - if os.Getenv("GDK_BACKEND") == "" && (os.Getenv("XDG_SESSION_TYPE") == "" || os.Getenv("XDG_SESSION_TYPE") == "unspecified" || os.Getenv("XDG_SESSION_TYPE") == "x11") { - _ = os.Setenv("GDK_BACKEND", "x11") - } - - if ok := C.gtk_init_check(nil, nil); ok != 1 { - panic(errors.New("failed to init GTK")) - } - }) - - result := &Frontend{ - frontendOptions: appoptions, - logger: myLogger, - bindings: appBindings, - dispatcher: dispatcher, - ctx: ctx, - } - result.startURL, _ = url.Parse(startURL) - result.originValidator = originvalidator.NewOriginValidator(result.startURL, appoptions.BindingsAllowedOrigins) - - if _starturl, _ := ctx.Value("starturl").(*url.URL); _starturl != nil { - result.startURL = _starturl - result.originValidator = originvalidator.NewOriginValidator(result.startURL, appoptions.BindingsAllowedOrigins) - } else { - if port, _ := ctx.Value("assetserverport").(string); port != "" { - result.startURL.Host = net.JoinHostPort(result.startURL.Host+".localhost", port) - result.originValidator = originvalidator.NewOriginValidator(result.startURL, appoptions.BindingsAllowedOrigins) - } - - var bindings string - var err error - if _obfuscated, _ := ctx.Value("obfuscated").(bool); !_obfuscated { - bindings, err = appBindings.ToJSON() - if err != nil { - log.Fatal(err) - } - } else { - appBindings.DB().UpdateObfuscatedCallMap() - } - assets, err := assetserver.NewAssetServerMainPage(bindings, appoptions, ctx.Value("assetdir") != nil, myLogger, wailsruntime.RuntimeAssetsBundle) - if err != nil { - log.Fatal(err) - } - result.assets = assets - - go result.startRequestProcessor() - } - - go result.startMessageProcessor() - go result.startBindingsMessageProcessor() - - var _debug = ctx.Value("debug") - var _devtoolsEnabled = ctx.Value("devtoolsEnabled") - - if _debug != nil { - result.debug = _debug.(bool) - } - if _devtoolsEnabled != nil { - result.devtoolsEnabled = _devtoolsEnabled.(bool) - } - - result.mainWindow = NewWindow(appoptions, result.debug, result.devtoolsEnabled) - - C.fix_signal_handlers_after_gtk_init() - - if appoptions.Linux != nil && appoptions.Linux.ProgramName != "" { - prgname := C.CString(appoptions.Linux.ProgramName) - C.g_set_prgname(prgname) - C.free(unsafe.Pointer(prgname)) - } - - go result.startSecondInstanceProcessor() - - return result -} - -func (f *Frontend) startMessageProcessor() { - for message := range messageBuffer { - f.processMessage(message) - } -} - -func (f *Frontend) startBindingsMessageProcessor() { - for msg := range bindingsMessageBuffer { - origin, err := f.originValidator.GetOriginFromURL(msg.source) - if err != nil { - f.logger.Error(fmt.Sprintf("failed to get origin for URL %q: %v", msg.source, err)) - continue - } - - allowed := f.originValidator.IsOriginAllowed(origin) - if !allowed { - f.logger.Error("Blocked request from unauthorized origin: %s", origin) - continue - } - - f.processMessage(msg.message) - } -} - -func (f *Frontend) WindowReload() { - f.ExecJS("runtime.WindowReload();") -} - -func (f *Frontend) WindowSetSystemDefaultTheme() { - return -} - -func (f *Frontend) WindowSetLightTheme() { - return -} - -func (f *Frontend) WindowSetDarkTheme() { - return -} - -func (f *Frontend) Run(ctx context.Context) error { - f.ctx = ctx - - go func() { - if f.frontendOptions.OnStartup != nil { - f.frontendOptions.OnStartup(f.ctx) - } - }() - - if f.frontendOptions.SingleInstanceLock != nil { - SetupSingleInstance(f.frontendOptions.SingleInstanceLock.UniqueId) - } - - f.mainWindow.Run(f.startURL.String()) - - return nil -} - -func (f *Frontend) WindowCenter() { - f.mainWindow.Center() -} - -func (f *Frontend) WindowSetAlwaysOnTop(b bool) { - f.mainWindow.SetKeepAbove(b) -} - -func (f *Frontend) WindowSetPosition(x, y int) { - f.mainWindow.SetPosition(x, y) -} -func (f *Frontend) WindowGetPosition() (int, int) { - return f.mainWindow.GetPosition() -} - -func (f *Frontend) WindowSetSize(width, height int) { - f.mainWindow.SetSize(width, height) -} - -func (f *Frontend) WindowGetSize() (int, int) { - return f.mainWindow.Size() -} - -func (f *Frontend) WindowSetTitle(title string) { - f.mainWindow.SetTitle(title) -} - -func (f *Frontend) WindowFullscreen() { - if f.frontendOptions.Frameless && f.frontendOptions.DisableResize == false { - f.ExecJS("window.wails.flags.enableResize = false;") - } - f.mainWindow.Fullscreen() -} - -func (f *Frontend) WindowUnfullscreen() { - if f.frontendOptions.Frameless && f.frontendOptions.DisableResize == false { - f.ExecJS("window.wails.flags.enableResize = true;") - } - f.mainWindow.UnFullscreen() -} - -func (f *Frontend) WindowReloadApp() { - f.ExecJS(fmt.Sprintf("window.location.href = '%s';", f.startURL)) -} - -func (f *Frontend) WindowShow() { - f.mainWindow.Show() -} - -func (f *Frontend) WindowHide() { - f.mainWindow.Hide() -} - -func (f *Frontend) Show() { - f.mainWindow.Show() -} - -func (f *Frontend) Hide() { - f.mainWindow.Hide() -} -func (f *Frontend) WindowMaximise() { - f.mainWindow.Maximise() -} -func (f *Frontend) WindowToggleMaximise() { - f.mainWindow.ToggleMaximise() -} -func (f *Frontend) WindowUnmaximise() { - f.mainWindow.UnMaximise() -} -func (f *Frontend) WindowMinimise() { - f.mainWindow.Minimise() -} -func (f *Frontend) WindowUnminimise() { - f.mainWindow.UnMinimise() -} - -func (f *Frontend) WindowSetMinSize(width int, height int) { - f.mainWindow.SetMinSize(width, height) -} -func (f *Frontend) WindowSetMaxSize(width int, height int) { - f.mainWindow.SetMaxSize(width, height) -} - -func (f *Frontend) WindowSetBackgroundColour(col *options.RGBA) { - if col == nil { - return - } - f.mainWindow.SetBackgroundColour(col.R, col.G, col.B, col.A) -} - -func (f *Frontend) ScreenGetAll() ([]Screen, error) { - return GetAllScreens(f.mainWindow.asGTKWindow()) -} - -func (f *Frontend) WindowIsMaximised() bool { - return f.mainWindow.IsMaximised() -} - -func (f *Frontend) WindowIsMinimised() bool { - return f.mainWindow.IsMinimised() -} - -func (f *Frontend) WindowIsNormal() bool { - return f.mainWindow.IsNormal() -} - -func (f *Frontend) WindowIsFullscreen() bool { - return f.mainWindow.IsFullScreen() -} - -func (f *Frontend) Quit() { - if f.frontendOptions.OnBeforeClose != nil { - go func() { - if !f.frontendOptions.OnBeforeClose(f.ctx) { - f.mainWindow.Quit() - } - }() - return - } - f.mainWindow.Quit() -} - -func (f *Frontend) WindowPrint() { - f.ExecJS("window.print();") -} - -type EventNotify struct { - Name string `json:"name"` - Data []interface{} `json:"data"` -} - -func (f *Frontend) Notify(name string, data ...interface{}) { - notification := EventNotify{ - Name: name, - Data: data, - } - payload, err := json.Marshal(notification) - if err != nil { - f.logger.Error(err.Error()) - return - } - f.mainWindow.ExecJS(`window.wails.EventsNotify('` + template.JSEscapeString(string(payload)) + `');`) -} - -var edgeMap = map[string]uintptr{ - "n-resize": C.GDK_WINDOW_EDGE_NORTH, - "ne-resize": C.GDK_WINDOW_EDGE_NORTH_EAST, - "e-resize": C.GDK_WINDOW_EDGE_EAST, - "se-resize": C.GDK_WINDOW_EDGE_SOUTH_EAST, - "s-resize": C.GDK_WINDOW_EDGE_SOUTH, - "sw-resize": C.GDK_WINDOW_EDGE_SOUTH_WEST, - "w-resize": C.GDK_WINDOW_EDGE_WEST, - "nw-resize": C.GDK_WINDOW_EDGE_NORTH_WEST, -} - -func (f *Frontend) processMessage(message string) { - if message == "DomReady" { - if f.frontendOptions.OnDomReady != nil { - f.frontendOptions.OnDomReady(f.ctx) - } - return - } - - if message == "drag" { - if !f.mainWindow.IsFullScreen() { - f.startDrag() - } - return - } - - if message == "wails:showInspector" { - f.mainWindow.ShowInspector() - return - } - - if strings.HasPrefix(message, "resize:") { - if !f.mainWindow.IsFullScreen() { - sl := strings.Split(message, ":") - if len(sl) != 2 { - f.logger.Info("Unknown message returned from dispatcher: %+v", message) - return - } - edge := edgeMap[sl[1]] - err := f.startResize(edge) - if err != nil { - f.logger.Error(err.Error()) - } - } - return - } - - if message == "runtime:ready" { - cmd := fmt.Sprintf( - "window.wails.setCSSDragProperties('%s', '%s');\n"+ - "window.wails.setCSSDropProperties('%s', '%s');\n"+ - "window.wails.flags.deferDragToMouseMove = true;", - f.frontendOptions.CSSDragProperty, - f.frontendOptions.CSSDragValue, - f.frontendOptions.DragAndDrop.CSSDropProperty, - f.frontendOptions.DragAndDrop.CSSDropValue, - ) - - f.ExecJS(cmd) - - if f.frontendOptions.Frameless && f.frontendOptions.DisableResize == false { - f.ExecJS("window.wails.flags.enableResize = true;") - } - - if f.frontendOptions.DragAndDrop.EnableFileDrop { - f.ExecJS("window.wails.flags.enableWailsDragAndDrop = true;") - } - - return - } - - go func() { - result, err := f.dispatcher.ProcessMessage(message, f) - if err != nil { - f.logger.Error(err.Error()) - f.Callback(result) - return - } - if result == "" { - return - } - - switch result[0] { - case 'c': - // Callback from a method call - f.Callback(result[1:]) - default: - f.logger.Info("Unknown message returned from dispatcher: %+v", result) - } - }() -} - -func (f *Frontend) Callback(message string) { - escaped, err := json.Marshal(message) - if err != nil { - panic(err) - } - f.ExecJS(`window.wails.Callback(` + string(escaped) + `);`) -} - -func (f *Frontend) startDrag() { - f.mainWindow.StartDrag() -} - -func (f *Frontend) startResize(edge uintptr) error { - f.mainWindow.StartResize(edge) - return nil -} - -func (f *Frontend) ExecJS(js string) { - f.mainWindow.ExecJS(js) -} - -type bindingsMessage struct { - message string - source string -} - -var messageBuffer = make(chan string, 100) -var bindingsMessageBuffer = make(chan *bindingsMessage, 100) - -//export processMessage -func processMessage(message *C.char) { - goMessage := C.GoString(message) - messageBuffer <- goMessage -} - -//export processBindingMessage -func processBindingMessage(message *C.char, source *C.char) { - goMessage := C.GoString(message) - goSource := C.GoString(source) - bindingsMessageBuffer <- &bindingsMessage{ - message: goMessage, - source: goSource, - } -} - -var requestBuffer = make(chan webview.Request, 100) - -func (f *Frontend) startRequestProcessor() { - for request := range requestBuffer { - f.assets.ServeWebViewRequest(request) - } -} - -//export processURLRequest -func processURLRequest(request unsafe.Pointer) { - requestBuffer <- webview.NewRequest(request) -} - -func (f *Frontend) startSecondInstanceProcessor() { - for secondInstanceData := range secondInstanceBuffer { - if f.frontendOptions.SingleInstanceLock != nil && - f.frontendOptions.SingleInstanceLock.OnSecondInstanceLaunch != nil { - f.frontendOptions.SingleInstanceLock.OnSecondInstanceLaunch(secondInstanceData) - } - } -} diff --git a/v2/internal/frontend/desktop/linux/gtk.go b/v2/internal/frontend/desktop/linux/gtk.go deleted file mode 100644 index 67a38c7a0..000000000 --- a/v2/internal/frontend/desktop/linux/gtk.go +++ /dev/null @@ -1,85 +0,0 @@ -//go:build linux -// +build linux - -package linux - -/* -#cgo linux pkg-config: gtk+-3.0 -#cgo !webkit2_41 pkg-config: webkit2gtk-4.0 -#cgo webkit2_41 pkg-config: webkit2gtk-4.1 - -#include "gtk/gtk.h" - -static GtkCheckMenuItem *toGtkCheckMenuItem(void *pointer) { return (GTK_CHECK_MENU_ITEM(pointer)); } - -extern void blockClick(GtkWidget* menuItem, gulong handler_id); -extern void unblockClick(GtkWidget* menuItem, gulong handler_id); -*/ -import "C" -import ( - "unsafe" - - "github.com/wailsapp/wails/v2/pkg/menu" -) - -func GtkMenuItemWithLabel(label string) *C.GtkWidget { - cLabel := C.CString(label) - result := C.gtk_menu_item_new_with_label(cLabel) - C.free(unsafe.Pointer(cLabel)) - return result -} - -func GtkCheckMenuItemWithLabel(label string) *C.GtkWidget { - cLabel := C.CString(label) - result := C.gtk_check_menu_item_new_with_label(cLabel) - C.free(unsafe.Pointer(cLabel)) - return result -} - -func GtkRadioMenuItemWithLabel(label string, group *C.GSList) *C.GtkWidget { - cLabel := C.CString(label) - result := C.gtk_radio_menu_item_new_with_label(group, cLabel) - C.free(unsafe.Pointer(cLabel)) - return result -} - -//export handleMenuItemClick -func handleMenuItemClick(gtkWidget unsafe.Pointer) { - // Make sure to execute the final callback on a new goroutine otherwise if the callback e.g. tries to open a dialog, the - // main thread will get blocked and so the message loop blocks. As a result the app will block and shows a - // "not responding" dialog. - - item := gtkSignalToMenuItem[(*C.GtkWidget)(gtkWidget)] - switch item.Type { - case menu.CheckboxType: - item.Checked = !item.Checked - checked := C.int(0) - if item.Checked { - checked = C.int(1) - } - for _, gtkCheckbox := range gtkCheckboxCache[item] { - handler := gtkSignalHandlers[gtkCheckbox] - C.blockClick(gtkCheckbox, handler) - C.gtk_check_menu_item_set_active(C.toGtkCheckMenuItem(unsafe.Pointer(gtkCheckbox)), checked) - C.unblockClick(gtkCheckbox, handler) - } - go item.Click(&menu.CallbackData{MenuItem: item}) - case menu.RadioType: - gtkRadioItems := gtkRadioMenuCache[item] - active := C.gtk_check_menu_item_get_active(C.toGtkCheckMenuItem(gtkWidget)) - if int(active) == 1 { - for _, gtkRadioItem := range gtkRadioItems { - handler := gtkSignalHandlers[gtkRadioItem] - C.blockClick(gtkRadioItem, handler) - C.gtk_check_menu_item_set_active(C.toGtkCheckMenuItem(unsafe.Pointer(gtkRadioItem)), 1) - C.unblockClick(gtkRadioItem, handler) - } - item.Checked = true - go item.Click(&menu.CallbackData{MenuItem: item}) - } else { - item.Checked = false - } - default: - go item.Click(&menu.CallbackData{MenuItem: item}) - } -} diff --git a/v2/internal/frontend/desktop/linux/invoke.go b/v2/internal/frontend/desktop/linux/invoke.go deleted file mode 100644 index 16d5e73d2..000000000 --- a/v2/internal/frontend/desktop/linux/invoke.go +++ /dev/null @@ -1,78 +0,0 @@ -//go:build linux -// +build linux - -package linux - -/* -#cgo linux pkg-config: gtk+-3.0 - -#include -#include "gtk/gtk.h" - -extern gboolean invokeCallbacks(void *); - -static inline void triggerInvokesOnMainThread() { - g_idle_add((GSourceFunc)invokeCallbacks, NULL); -} -*/ -import "C" -import ( - "runtime" - "sync" - "unsafe" - - "golang.org/x/sys/unix" -) - -var ( - m sync.Mutex - mainTid int - dispatchq []func() -) - -func invokeOnMainThread(f func()) { - if tryInvokeOnCurrentGoRoutine(f) { - return - } - - m.Lock() - dispatchq = append(dispatchq, f) - m.Unlock() - - C.triggerInvokesOnMainThread() -} - -func tryInvokeOnCurrentGoRoutine(f func()) bool { - m.Lock() - mainThreadID := mainTid - m.Unlock() - - runtime.LockOSThread() - defer runtime.UnlockOSThread() - - if mainThreadID != unix.Gettid() { - return false - } - f() - return true -} - -//export invokeCallbacks -func invokeCallbacks(_ unsafe.Pointer) C.gboolean { - runtime.LockOSThread() - defer runtime.UnlockOSThread() - - m.Lock() - if mainTid == 0 { - mainTid = unix.Gettid() - } - - q := append([]func(){}, dispatchq...) - dispatchq = []func(){} - m.Unlock() - - for _, v := range q { - v() - } - return C.G_SOURCE_REMOVE -} diff --git a/v2/internal/frontend/desktop/linux/keys.go b/v2/internal/frontend/desktop/linux/keys.go deleted file mode 100644 index e5a127dbd..000000000 --- a/v2/internal/frontend/desktop/linux/keys.go +++ /dev/null @@ -1,110 +0,0 @@ -//go:build linux -// +build linux - -package linux - -/* -#cgo linux pkg-config: gtk+-3.0 -#cgo !webkit2_41 pkg-config: webkit2gtk-4.0 -#cgo webkit2_41 pkg-config: webkit2gtk-4.1 - - -#include "gtk/gtk.h" - -*/ -import "C" -import ( - "github.com/wailsapp/wails/v2/pkg/menu/keys" -) - -var namedKeysToGTK = map[string]C.guint{ - "backspace": C.guint(0xff08), - "tab": C.guint(0xff09), - "return": C.guint(0xff0d), - "enter": C.guint(0xff0d), - "escape": C.guint(0xff1b), - "left": C.guint(0xff51), - "right": C.guint(0xff53), - "up": C.guint(0xff52), - "down": C.guint(0xff54), - "space": C.guint(0xff80), - "delete": C.guint(0xff9f), - "home": C.guint(0xff95), - "end": C.guint(0xff9c), - "page up": C.guint(0xff9a), - "page down": C.guint(0xff9b), - "f1": C.guint(0xffbe), - "f2": C.guint(0xffbf), - "f3": C.guint(0xffc0), - "f4": C.guint(0xffc1), - "f5": C.guint(0xffc2), - "f6": C.guint(0xffc3), - "f7": C.guint(0xffc4), - "f8": C.guint(0xffc5), - "f9": C.guint(0xffc6), - "f10": C.guint(0xffc7), - "f11": C.guint(0xffc8), - "f12": C.guint(0xffc9), - "f13": C.guint(0xffca), - "f14": C.guint(0xffcb), - "f15": C.guint(0xffcc), - "f16": C.guint(0xffcd), - "f17": C.guint(0xffce), - "f18": C.guint(0xffcf), - "f19": C.guint(0xffd0), - "f20": C.guint(0xffd1), - "f21": C.guint(0xffd2), - "f22": C.guint(0xffd3), - "f23": C.guint(0xffd4), - "f24": C.guint(0xffd5), - "f25": C.guint(0xffd6), - "f26": C.guint(0xffd7), - "f27": C.guint(0xffd8), - "f28": C.guint(0xffd9), - "f29": C.guint(0xffda), - "f30": C.guint(0xffdb), - "f31": C.guint(0xffdc), - "f32": C.guint(0xffdd), - "f33": C.guint(0xffde), - "f34": C.guint(0xffdf), - "f35": C.guint(0xffe0), - "numlock": C.guint(0xff7f), -} - -func acceleratorToGTK(accelerator *keys.Accelerator) (C.guint, C.GdkModifierType) { - key := parseKey(accelerator.Key) - mods := parseModifiers(accelerator.Modifiers) - return key, mods -} - -func parseKey(key string) C.guint { - var result C.guint - result, found := namedKeysToGTK[key] - if found { - return result - } - // Check for unknown namedkeys - // Check if we only have a single character - if len(key) != 1 { - return C.guint(0) - } - keyval := rune(key[0]) - return C.gdk_unicode_to_keyval(C.guint(keyval)) -} - -func parseModifiers(modifiers []keys.Modifier) C.GdkModifierType { - - var result C.GdkModifierType - - for _, modifier := range modifiers { - switch modifier { - case keys.ShiftKey: - result |= C.GDK_SHIFT_MASK - case keys.ControlKey, keys.CmdOrCtrlKey: - result |= C.GDK_CONTROL_MASK - case keys.OptionOrAltKey: - result |= C.GDK_MOD1_MASK - } - } - return result -} diff --git a/v2/internal/frontend/desktop/linux/menu.go b/v2/internal/frontend/desktop/linux/menu.go deleted file mode 100644 index a61d190bd..000000000 --- a/v2/internal/frontend/desktop/linux/menu.go +++ /dev/null @@ -1,169 +0,0 @@ -//go:build linux -// +build linux - -package linux - -/* -#cgo linux pkg-config: gtk+-3.0 -#cgo !webkit2_41 pkg-config: webkit2gtk-4.0 -#cgo webkit2_41 pkg-config: webkit2gtk-4.1 - -#include "gtk/gtk.h" - -static GtkMenuItem *toGtkMenuItem(void *pointer) { return (GTK_MENU_ITEM(pointer)); } -static GtkMenuShell *toGtkMenuShell(void *pointer) { return (GTK_MENU_SHELL(pointer)); } -static GtkCheckMenuItem *toGtkCheckMenuItem(void *pointer) { return (GTK_CHECK_MENU_ITEM(pointer)); } -static GtkRadioMenuItem *toGtkRadioMenuItem(void *pointer) { return (GTK_RADIO_MENU_ITEM(pointer)); } - -extern void handleMenuItemClick(void*); - -void blockClick(GtkWidget* menuItem, gulong handler_id) { - g_signal_handler_block (menuItem, handler_id); -} - -void unblockClick(GtkWidget* menuItem, gulong handler_id) { - g_signal_handler_unblock (menuItem, handler_id); -} - -gulong connectClick(GtkWidget* menuItem) { - return g_signal_connect(menuItem, "activate", G_CALLBACK(handleMenuItemClick), (void*)menuItem); -} - -void addAccelerator(GtkWidget* menuItem, GtkAccelGroup* group, guint key, GdkModifierType mods) { - gtk_widget_add_accelerator(menuItem, "activate", group, key, mods, GTK_ACCEL_VISIBLE); -} -*/ -import "C" -import ( - "unsafe" - - "github.com/wailsapp/wails/v2/pkg/menu" -) - -var menuIdCounter int -var menuItemToId map[*menu.MenuItem]int -var menuIdToItem map[int]*menu.MenuItem -var gtkCheckboxCache map[*menu.MenuItem][]*C.GtkWidget -var gtkMenuCache map[*menu.MenuItem]*C.GtkWidget -var gtkRadioMenuCache map[*menu.MenuItem][]*C.GtkWidget -var gtkSignalHandlers map[*C.GtkWidget]C.gulong -var gtkSignalToMenuItem map[*C.GtkWidget]*menu.MenuItem - -func (f *Frontend) MenuSetApplicationMenu(menu *menu.Menu) { - f.mainWindow.SetApplicationMenu(menu) -} - -func (f *Frontend) MenuUpdateApplicationMenu() { - f.mainWindow.SetApplicationMenu(f.mainWindow.applicationMenu) -} - -func (w *Window) SetApplicationMenu(inmenu *menu.Menu) { - if inmenu == nil { - return - } - - // Setup accelerator group - w.accels = C.gtk_accel_group_new() - C.gtk_window_add_accel_group(w.asGTKWindow(), w.accels) - - menuItemToId = make(map[*menu.MenuItem]int) - menuIdToItem = make(map[int]*menu.MenuItem) - gtkCheckboxCache = make(map[*menu.MenuItem][]*C.GtkWidget) - gtkMenuCache = make(map[*menu.MenuItem]*C.GtkWidget) - gtkRadioMenuCache = make(map[*menu.MenuItem][]*C.GtkWidget) - gtkSignalHandlers = make(map[*C.GtkWidget]C.gulong) - gtkSignalToMenuItem = make(map[*C.GtkWidget]*menu.MenuItem) - - // Increase ref count? - w.menubar = C.gtk_menu_bar_new() - - processMenu(w, inmenu) - - C.gtk_widget_show(w.menubar) -} - -func processMenu(window *Window, menu *menu.Menu) { - for _, menuItem := range menu.Items { - if menuItem.SubMenu != nil { - submenu := processSubmenu(menuItem, window.accels) - C.gtk_menu_shell_append(C.toGtkMenuShell(unsafe.Pointer(window.menubar)), submenu) - } - } -} - -func processSubmenu(menuItem *menu.MenuItem, group *C.GtkAccelGroup) *C.GtkWidget { - existingMenu := gtkMenuCache[menuItem] - if existingMenu != nil { - return existingMenu - } - gtkMenu := C.gtk_menu_new() - submenu := GtkMenuItemWithLabel(menuItem.Label) - for _, menuItem := range menuItem.SubMenu.Items { - menuID := menuIdCounter - menuIdToItem[menuID] = menuItem - menuItemToId[menuItem] = menuID - menuIdCounter++ - processMenuItem(gtkMenu, menuItem, group) - } - C.gtk_menu_item_set_submenu(C.toGtkMenuItem(unsafe.Pointer(submenu)), gtkMenu) - gtkMenuCache[menuItem] = existingMenu - return submenu -} - -var currentRadioGroup *C.GSList - -func processMenuItem(parent *C.GtkWidget, menuItem *menu.MenuItem, group *C.GtkAccelGroup) { - if menuItem.Hidden { - return - } - - if menuItem.Type != menu.RadioType { - currentRadioGroup = nil - } - - if menuItem.Type == menu.SeparatorType { - result := C.gtk_separator_menu_item_new() - C.gtk_menu_shell_append(C.toGtkMenuShell(unsafe.Pointer(parent)), result) - return - } - - var result *C.GtkWidget - - switch menuItem.Type { - case menu.TextType: - result = GtkMenuItemWithLabel(menuItem.Label) - case menu.CheckboxType: - result = GtkCheckMenuItemWithLabel(menuItem.Label) - if menuItem.Checked { - C.gtk_check_menu_item_set_active(C.toGtkCheckMenuItem(unsafe.Pointer(result)), 1) - } - gtkCheckboxCache[menuItem] = append(gtkCheckboxCache[menuItem], result) - - case menu.RadioType: - result = GtkRadioMenuItemWithLabel(menuItem.Label, currentRadioGroup) - currentRadioGroup = C.gtk_radio_menu_item_get_group(C.toGtkRadioMenuItem(unsafe.Pointer(result))) - if menuItem.Checked { - C.gtk_check_menu_item_set_active(C.toGtkCheckMenuItem(unsafe.Pointer(result)), 1) - } - gtkRadioMenuCache[menuItem] = append(gtkRadioMenuCache[menuItem], result) - case menu.SubmenuType: - result = processSubmenu(menuItem, group) - } - C.gtk_menu_shell_append(C.toGtkMenuShell(unsafe.Pointer(parent)), result) - C.gtk_widget_show(result) - - if menuItem.Click != nil { - handler := C.connectClick(result) - gtkSignalHandlers[result] = handler - gtkSignalToMenuItem[result] = menuItem - } - - if menuItem.Disabled { - C.gtk_widget_set_sensitive(result, 0) - } - - if menuItem.Accelerator != nil { - key, mods := acceleratorToGTK(menuItem.Accelerator) - C.addAccelerator(result, group, key, mods) - } -} diff --git a/v2/internal/frontend/desktop/linux/screen.go b/v2/internal/frontend/desktop/linux/screen.go deleted file mode 100644 index 0a0507425..000000000 --- a/v2/internal/frontend/desktop/linux/screen.go +++ /dev/null @@ -1,91 +0,0 @@ -//go:build linux -// +build linux - -package linux - -/* -#cgo linux pkg-config: gtk+-3.0 -#cgo !webkit2_41 pkg-config: webkit2gtk-4.0 -#cgo webkit2_41 pkg-config: webkit2gtk-4.1 - -#cgo CFLAGS: -w -#include -#include "webkit2/webkit2.h" -#include "gtk/gtk.h" -#include "gdk/gdk.h" - -typedef struct Screen { - int isCurrent; - int isPrimary; - int height; - int width; - int scale; -} Screen; - -int GetNMonitors(GtkWindow *window){ - GdkWindow *gdk_window = gtk_widget_get_window(GTK_WIDGET(window)); - GdkDisplay *display = gdk_window_get_display(gdk_window); - return gdk_display_get_n_monitors(display); -} - -Screen GetNThMonitor(int monitor_num, GtkWindow *window){ - GdkWindow *gdk_window = gtk_widget_get_window(GTK_WIDGET(window)); - GdkDisplay *display = gdk_window_get_display(gdk_window); - GdkMonitor *monitor = gdk_display_get_monitor(display,monitor_num); - GdkMonitor *currentMonitor = gdk_display_get_monitor_at_window(display,gdk_window); - Screen screen; - GdkRectangle geometry; - gdk_monitor_get_geometry(monitor,&geometry); - screen.isCurrent = currentMonitor==monitor; - screen.isPrimary = gdk_monitor_is_primary(monitor); - screen.height = geometry.height; - screen.width = geometry.width; - screen.scale = gdk_monitor_get_scale_factor(monitor); - return screen; -} -*/ -import "C" -import ( - "sync" - - "github.com/pkg/errors" - "github.com/wailsapp/wails/v2/internal/frontend" -) - -type Screen = frontend.Screen - -func GetAllScreens(window *C.GtkWindow) ([]Screen, error) { - if window == nil { - return nil, errors.New("window is nil, cannot perform screen operations") - } - var wg sync.WaitGroup - var screens []Screen - wg.Add(1) - invokeOnMainThread(func() { - numMonitors := C.GetNMonitors(window) - for i := 0; i < int(numMonitors); i++ { - cMonitor := C.GetNThMonitor(C.int(i), window) - - screen := Screen{ - IsCurrent: cMonitor.isCurrent == 1, - IsPrimary: cMonitor.isPrimary == 1, - Width: int(cMonitor.width), - Height: int(cMonitor.height), - - Size: frontend.ScreenSize{ - Width: int(cMonitor.width), - Height: int(cMonitor.height), - }, - PhysicalSize: frontend.ScreenSize{ - Width: int(cMonitor.width * cMonitor.scale), - Height: int(cMonitor.height * cMonitor.scale), - }, - } - screens = append(screens, screen) - } - - wg.Done() - }) - wg.Wait() - return screens, nil -} diff --git a/v2/internal/frontend/desktop/linux/single_instance.go b/v2/internal/frontend/desktop/linux/single_instance.go deleted file mode 100644 index 0317dee49..000000000 --- a/v2/internal/frontend/desktop/linux/single_instance.go +++ /dev/null @@ -1,77 +0,0 @@ -//go:build linux -// +build linux - -package linux - -import ( - "encoding/json" - "github.com/godbus/dbus/v5" - "github.com/wailsapp/wails/v2/pkg/options" - "log" - "os" - "strings" -) - -type dbusHandler func(string) - -func (f dbusHandler) SendMessage(message string) *dbus.Error { - f(message) - return nil -} - -func SetupSingleInstance(uniqueID string) { - id := "wails_app_" + strings.ReplaceAll(strings.ReplaceAll(uniqueID, "-", "_"), ".", "_") - - dbusName := "org." + id + ".SingleInstance" - dbusPath := "/org/" + id + "/SingleInstance" - - conn, err := dbus.ConnectSessionBus() - // if we will reach any error during establishing connection or sending message we will just continue. - // It should not be the case that such thing will happen actually, but just in case. - if err != nil { - return - } - - f := dbusHandler(func(message string) { - var secondInstanceData options.SecondInstanceData - - err := json.Unmarshal([]byte(message), &secondInstanceData) - if err == nil { - secondInstanceBuffer <- secondInstanceData - } - }) - - err = conn.Export(f, dbus.ObjectPath(dbusPath), dbusName) - if err != nil { - return - } - - reply, err := conn.RequestName(dbusName, dbus.NameFlagDoNotQueue) - if err != nil { - return - } - - // if name already taken, try to send args to existing instance, if no success just launch new instance - if reply == dbus.RequestNameReplyExists { - data := options.SecondInstanceData{ - Args: os.Args[1:], - } - data.WorkingDirectory, err = os.Getwd() - if err != nil { - log.Printf("Failed to get working directory: %v", err) - return - } - - serialized, err := json.Marshal(data) - if err != nil { - log.Printf("Failed to marshal data: %v", err) - return - } - - err = conn.Object(dbusName, dbus.ObjectPath(dbusPath)).Call(dbusName+".SendMessage", 0, string(serialized)).Store() - if err != nil { - return - } - os.Exit(1) - } -} diff --git a/v2/internal/frontend/desktop/linux/webkit2.go b/v2/internal/frontend/desktop/linux/webkit2.go deleted file mode 100644 index 06e0c7824..000000000 --- a/v2/internal/frontend/desktop/linux/webkit2.go +++ /dev/null @@ -1,32 +0,0 @@ -//go:build linux - -package linux - -/* -#cgo !webkit2_41 pkg-config: webkit2gtk-4.0 -#cgo webkit2_41 pkg-config: webkit2gtk-4.1 -#include "webkit2/webkit2.h" -*/ -import "C" -import ( - "fmt" - - "github.com/wailsapp/wails/v2/pkg/options" - "github.com/wailsapp/wails/v2/pkg/options/linux" - - "github.com/wailsapp/wails/v2/pkg/assetserver/webview" -) - -func validateWebKit2Version(options *options.App) { - if C.webkit_get_major_version() == 2 && C.webkit_get_minor_version() >= webview.Webkit2MinMinorVersion { - return - } - - msg := linux.DefaultMessages() - if options.Linux != nil && options.Linux.Messages != nil { - msg = options.Linux.Messages - } - - v := fmt.Sprintf("2.%d.0", webview.Webkit2MinMinorVersion) - showModalDialogAndExit("WebKit2GTK", fmt.Sprintf(msg.WebKit2GTKMinRequired, v)) -} diff --git a/v2/internal/frontend/desktop/linux/window.c b/v2/internal/frontend/desktop/linux/window.c deleted file mode 100644 index 5441db022..000000000 --- a/v2/internal/frontend/desktop/linux/window.c +++ /dev/null @@ -1,891 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include "window.h" - -// These are the x,y,time & button of the last mouse down event -// It's used for window dragging -static float xroot = 0.0f; -static float yroot = 0.0f; -static int dragTime = -1; -static uint mouseButton = 0; -static int wmIsWayland = -1; -static int decoratorWidth = -1; -static int decoratorHeight = -1; - -// casts -void ExecuteOnMainThread(void *f, gpointer jscallback) -{ - g_idle_add((GSourceFunc)f, (gpointer)jscallback); -} - -GtkWidget *GTKWIDGET(void *pointer) -{ - return GTK_WIDGET(pointer); -} - -GtkWindow *GTKWINDOW(void *pointer) -{ - return GTK_WINDOW(pointer); -} - -GtkContainer *GTKCONTAINER(void *pointer) -{ - return GTK_CONTAINER(pointer); -} - -GtkBox *GTKBOX(void *pointer) -{ - return GTK_BOX(pointer); -} - -extern void processMessage(char *); -extern void processBindingMessage(char *, char *); - -static void sendMessageToBackend(WebKitUserContentManager *contentManager, - WebKitJavascriptResult *result, - void *data) -{ - // Retrieve webview from content manager - WebKitWebView *webview = WEBKIT_WEB_VIEW(g_object_get_data(G_OBJECT(contentManager), "webview")); - const char *current_uri = webview ? webkit_web_view_get_uri(webview) : NULL; - char *uri = current_uri ? g_strdup(current_uri) : NULL; - -#if WEBKIT_MAJOR_VERSION >= 2 && WEBKIT_MINOR_VERSION >= 22 - JSCValue *value = webkit_javascript_result_get_js_value(result); - char *message = jsc_value_to_string(value); -#else - JSGlobalContextRef context = webkit_javascript_result_get_global_context(result); - JSValueRef value = webkit_javascript_result_get_value(result); - JSStringRef js = JSValueToStringCopy(context, value, NULL); - size_t messageSize = JSStringGetMaximumUTF8CStringSize(js); - char *message = g_new(char, messageSize); - JSStringGetUTF8CString(js, message, messageSize); - JSStringRelease(js); -#endif - processBindingMessage(message, uri); - g_free(message); - if (uri) { - g_free(uri); - } -} - -static bool isNULLRectangle(GdkRectangle input) -{ - return input.x == -1 && input.y == -1 && input.width == -1 && input.height == -1; -} - -static gboolean onWayland() -{ - switch (wmIsWayland) - { - case -1: - { - char *gdkBackend = getenv("XDG_SESSION_TYPE"); - if(gdkBackend != NULL && strcmp(gdkBackend, "wayland") == 0) - { - wmIsWayland = 1; - return TRUE; - } - - wmIsWayland = 0; - return FALSE; - } - case 1: - return TRUE; - default: - return FALSE; - } -} - -static GdkMonitor *getCurrentMonitor(GtkWindow *window) -{ - // Get the monitor that the window is currently on - GdkDisplay *display = gtk_widget_get_display(GTK_WIDGET(window)); - GdkWindow *gdk_window = gtk_widget_get_window(GTK_WIDGET(window)); - if (gdk_window == NULL) - { - return NULL; - } - GdkMonitor *monitor = gdk_display_get_monitor_at_window(display, gdk_window); - - return GDK_MONITOR(monitor); -} - -static GdkRectangle getCurrentMonitorGeometry(GtkWindow *window) -{ - GdkMonitor *monitor = getCurrentMonitor(window); - GdkRectangle result; - if (monitor == NULL) - { - result.x = result.y = result.height = result.width = -1; - return result; - } - - // Get the geometry of the monitor - gdk_monitor_get_geometry(monitor, &result); - return result; -} - -static int getCurrentMonitorScaleFactor(GtkWindow *window) -{ - GdkMonitor *monitor = getCurrentMonitor(window); - - return gdk_monitor_get_scale_factor(monitor); -} - -// window - -ulong SetupInvokeSignal(void *contentManager) -{ - return g_signal_connect((WebKitUserContentManager *)contentManager, "script-message-received::external", G_CALLBACK(sendMessageToBackend), NULL); -} - -void SetWindowIcon(GtkWindow *window, const guchar *buf, gsize len) -{ - GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); - if (!loader) - { - return; - } - if (gdk_pixbuf_loader_write(loader, buf, len, NULL) && gdk_pixbuf_loader_close(loader, NULL)) - { - GdkPixbuf *pixbuf = gdk_pixbuf_loader_get_pixbuf(loader); - if (pixbuf) - { - gtk_window_set_icon(window, pixbuf); - } - } - g_object_unref(loader); -} - -void SetWindowTransparency(GtkWidget *widget) -{ - GdkScreen *screen = gtk_widget_get_screen(widget); - GdkVisual *visual = gdk_screen_get_rgba_visual(screen); - - if (visual != NULL && gdk_screen_is_composited(screen)) - { - gtk_widget_set_app_paintable(widget, true); - gtk_widget_set_visual(widget, visual); - } -} - -static GtkCssProvider *windowCssProvider = NULL; - -void SetBackgroundColour(void *data) -{ - // set webview's background color - RGBAOptions *options = (RGBAOptions *)data; - - GdkRGBA colour = {options->r / 255.0, options->g / 255.0, options->b / 255.0, options->a / 255.0}; - if (options->windowIsTranslucent != NULL && options->windowIsTranslucent == TRUE) - { - colour.alpha = 0.0; - } - webkit_web_view_set_background_color(WEBKIT_WEB_VIEW(options->webview), &colour); - - // set window's background color - // Get the name of the current locale - char *old_locale, *saved_locale; - old_locale = setlocale(LC_ALL, NULL); - - // Copy the name so it won’t be clobbered by setlocale. - saved_locale = strdup(old_locale); - if (saved_locale == NULL) - return; - - //Now change the locale to english for so printf always converts floats with a dot decimal separator - setlocale(LC_ALL, "en_US.UTF-8"); - gchar *str = g_strdup_printf("#webview-box {background-color: rgba(%d, %d, %d, %1.1f);}", options->r, options->g, options->b, options->a / 255.0); - - //Restore the original locale. - setlocale(LC_ALL, saved_locale); - free(saved_locale); - - if (windowCssProvider == NULL) - { - windowCssProvider = gtk_css_provider_new(); - gtk_style_context_add_provider( - gtk_widget_get_style_context(GTK_WIDGET(options->webviewBox)), - GTK_STYLE_PROVIDER(windowCssProvider), - GTK_STYLE_PROVIDER_PRIORITY_USER); - g_object_unref(windowCssProvider); - } - - gtk_css_provider_load_from_data(windowCssProvider, str, -1, NULL); - g_free(str); -} - -static gboolean setTitle(gpointer data) -{ - SetTitleArgs *args = (SetTitleArgs *)data; - gtk_window_set_title(args->window, args->title); - free((void *)args->title); - free((void *)data); - - return G_SOURCE_REMOVE; -} - -void SetTitle(GtkWindow *window, char *title) -{ - SetTitleArgs *args = malloc(sizeof(SetTitleArgs)); - args->window = window; - args->title = title; - ExecuteOnMainThread(setTitle, (gpointer)args); -} - -static gboolean setPosition(gpointer data) -{ - SetPositionArgs *args = (SetPositionArgs *)data; - gtk_window_move((GtkWindow *)args->window, args->x, args->y); - free(args); - - return G_SOURCE_REMOVE; -} - -void SetPosition(void *window, int x, int y) -{ - GdkRectangle monitorDimensions = getCurrentMonitorGeometry(window); - if (isNULLRectangle(monitorDimensions)) - { - return; - } - SetPositionArgs *args = malloc(sizeof(SetPositionArgs)); - args->window = window; - args->x = monitorDimensions.x + x; - args->y = monitorDimensions.y + y; - ExecuteOnMainThread(setPosition, (gpointer)args); -} - -void SetMinMaxSize(GtkWindow *window, int min_width, int min_height, int max_width, int max_height) -{ - GdkGeometry size; - size.min_width = size.min_height = size.max_width = size.max_height = 0; - - GdkRectangle monitorSize = getCurrentMonitorGeometry(window); - if (isNULLRectangle(monitorSize)) - { - return; - } - - int flags = GDK_HINT_MAX_SIZE | GDK_HINT_MIN_SIZE; - - size.max_height = (max_height == 0 ? monitorSize.height : max_height); - size.max_width = (max_width == 0 ? monitorSize.width : max_width); - size.min_height = min_height; - size.min_width = min_width; - - // On Wayland window manager get the decorators and calculate the differences from the windows' size. - if(onWayland()) - { - if(decoratorWidth == -1 && decoratorHeight == -1) - { - int windowWidth, windowHeight; - gtk_window_get_size(window, &windowWidth, &windowHeight); - - GtkAllocation windowAllocation; - gtk_widget_get_allocation(GTK_WIDGET(window), &windowAllocation); - - decoratorWidth = (windowAllocation.width-windowWidth); - decoratorHeight = (windowAllocation.height-windowHeight); - } - - // Add the decorator difference to the window so fullscreen and maximise can fill the window. - size.max_height = decoratorHeight+size.max_height; - size.max_width = decoratorWidth+size.max_width; - } - - gtk_window_set_geometry_hints(window, NULL, &size, flags); -} - -// function to disable the context menu but propagate the event -static gboolean disableContextMenu(GtkWidget *widget, WebKitContextMenu *context_menu, GdkEvent *event, WebKitHitTestResult *hit_test_result, gpointer data) -{ - // return true to disable the context menu - return TRUE; -} - -void DisableContextMenu(void *webview) -{ - // Disable the context menu but propagate the event - g_signal_connect(WEBKIT_WEB_VIEW(webview), "context-menu", G_CALLBACK(disableContextMenu), NULL); -} - -static gboolean buttonPress(GtkWidget *widget, GdkEventButton *event, void *dummy) -{ - if (event == NULL) - { - xroot = yroot = 0.0f; - dragTime = -1; - return FALSE; - } - mouseButton = event->button; - if (event->button == 3) - { - return FALSE; - } - - if (event->type == GDK_BUTTON_PRESS && event->button == 1) - { - xroot = event->x_root; - yroot = event->y_root; - dragTime = event->time; - } - - return FALSE; -} - -static gboolean buttonRelease(GtkWidget *widget, GdkEventButton *event, void *dummy) -{ - if (event == NULL || (event->type == GDK_BUTTON_RELEASE && event->button == 1)) - { - xroot = yroot = 0.0f; - dragTime = -1; - } - return FALSE; -} - -void ConnectButtons(void *webview) -{ - g_signal_connect(WEBKIT_WEB_VIEW(webview), "button-press-event", G_CALLBACK(buttonPress), NULL); - g_signal_connect(WEBKIT_WEB_VIEW(webview), "button-release-event", G_CALLBACK(buttonRelease), NULL); -} - -int IsFullscreen(GtkWidget *widget) -{ - GdkWindow *gdkwindow = gtk_widget_get_window(widget); - GdkWindowState state = gdk_window_get_state(GDK_WINDOW(gdkwindow)); - return state & GDK_WINDOW_STATE_FULLSCREEN; -} - -int IsMaximised(GtkWidget *widget) -{ - GdkWindow *gdkwindow = gtk_widget_get_window(widget); - GdkWindowState state = gdk_window_get_state(GDK_WINDOW(gdkwindow)); - return state & GDK_WINDOW_STATE_MAXIMIZED && !(state & GDK_WINDOW_STATE_FULLSCREEN); -} - -int IsMinimised(GtkWidget *widget) -{ - GdkWindow *gdkwindow = gtk_widget_get_window(widget); - GdkWindowState state = gdk_window_get_state(GDK_WINDOW(gdkwindow)); - return state & GDK_WINDOW_STATE_ICONIFIED; -} - -gboolean Center(gpointer data) -{ - GtkWindow *window = (GtkWindow *)data; - - // Get the geometry of the monitor - GdkRectangle m = getCurrentMonitorGeometry(window); - if (isNULLRectangle(m)) - { - return G_SOURCE_REMOVE; - } - - // Get the window width/height - int windowWidth, windowHeight; - gtk_window_get_size(window, &windowWidth, &windowHeight); - - int newX = ((m.width - windowWidth) / 2) + m.x; - int newY = ((m.height - windowHeight) / 2) + m.y; - - // Place the window at the center of the monitor - gtk_window_move(window, newX, newY); - - return G_SOURCE_REMOVE; -} - -gboolean Show(gpointer data) -{ - gtk_widget_show((GtkWidget *)data); - - return G_SOURCE_REMOVE; -} - -gboolean Hide(gpointer data) -{ - gtk_widget_hide((GtkWidget *)data); - - return G_SOURCE_REMOVE; -} - -gboolean Maximise(gpointer data) -{ - gtk_window_maximize((GtkWindow *)data); - - return G_SOURCE_REMOVE; -} - -gboolean UnMaximise(gpointer data) -{ - gtk_window_unmaximize((GtkWindow *)data); - - return G_SOURCE_REMOVE; -} - -gboolean Minimise(gpointer data) -{ - gtk_window_iconify((GtkWindow *)data); - - return G_SOURCE_REMOVE; -} - -gboolean UnMinimise(gpointer data) -{ - gtk_window_present((GtkWindow *)data); - - return G_SOURCE_REMOVE; -} - -gboolean Fullscreen(gpointer data) -{ - GtkWindow *window = (GtkWindow *)data; - - // Get the geometry of the monitor. - GdkRectangle m = getCurrentMonitorGeometry(window); - if (isNULLRectangle(m)) - { - return G_SOURCE_REMOVE; - } - int scale = getCurrentMonitorScaleFactor(window); - SetMinMaxSize(window, 0, 0, m.width * scale, m.height * scale); - - gtk_window_fullscreen(window); - - return G_SOURCE_REMOVE; -} - -gboolean UnFullscreen(gpointer data) -{ - gtk_window_unfullscreen((GtkWindow *)data); - - return G_SOURCE_REMOVE; -} - -static void webviewLoadChanged(WebKitWebView *web_view, WebKitLoadEvent load_event, gpointer data) -{ - if (load_event == WEBKIT_LOAD_FINISHED) - { - processMessage("DomReady"); - } -} - -extern void processURLRequest(void *request); - -// This is called when the close button on the window is pressed -gboolean close_button_pressed(GtkWidget *widget, GdkEvent *event, void *data) -{ - processMessage("Q"); - // since we handle the close in processMessage tell GTK to not invoke additional handlers - see: - // https://docs.gtk.org/gtk3/signal.Widget.delete-event.html - return TRUE; -} - -char *droppedFiles = NULL; - -static void onDragDataReceived(GtkWidget *self, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint target_type, guint time, gpointer data) -{ - if(selection_data == NULL || (gtk_selection_data_get_length(selection_data) <= 0) || target_type != 2) - { - return; - } - - if(droppedFiles != NULL) { - free(droppedFiles); - droppedFiles = NULL; - } - - gchar **filenames = NULL; - filenames = g_uri_list_extract_uris((const gchar *)gtk_selection_data_get_data(selection_data)); - if (filenames == NULL) // If unable to retrieve filenames: - { - g_strfreev(filenames); - return; - } - - droppedFiles = calloc((size_t)gtk_selection_data_get_length(selection_data), 1); - - int iter = 0; - while(filenames[iter] != NULL) // The last URI list element is NULL. - { - if(iter != 0) - { - strncat(droppedFiles, "\n", 1); - } - char *filename = g_filename_from_uri(filenames[iter], NULL, NULL); - if (filename == NULL) - { - break; - } - strncat(droppedFiles, filename, strlen(filename)); - - free(filename); - iter++; - } - - g_strfreev(filenames); -} - -static gboolean onDragDrop(GtkWidget* self, GdkDragContext* context, gint x, gint y, guint time, gpointer user_data) -{ - if(droppedFiles == NULL) - { - return FALSE; - } - - size_t resLen = strlen(droppedFiles)+(sizeof(gint)*2)+6; - char *res = calloc(resLen, 1); - - snprintf(res, resLen, "DD:%d:%d:%s", x, y, droppedFiles); - - if(droppedFiles != NULL) { - free(droppedFiles); - droppedFiles = NULL; - } - - processMessage(res); - return FALSE; -} - -// WebView -GtkWidget *SetupWebview(void *contentManager, GtkWindow *window, int hideWindowOnClose, int gpuPolicy, int disableWebViewDragAndDrop, int enableDragAndDrop) -{ - GtkWidget *webview = webkit_web_view_new_with_user_content_manager((WebKitUserContentManager *)contentManager); - - // Store webview reference in the content manager - g_object_set_data(G_OBJECT((WebKitUserContentManager *)contentManager), "webview", webview); - // gtk_container_add(GTK_CONTAINER(window), webview); - WebKitWebContext *context = webkit_web_context_get_default(); - webkit_web_context_register_uri_scheme(context, "wails", (WebKitURISchemeRequestCallback)processURLRequest, NULL, NULL); - g_signal_connect(G_OBJECT(webview), "load-changed", G_CALLBACK(webviewLoadChanged), NULL); - - if(disableWebViewDragAndDrop) - { - gtk_drag_dest_unset(webview); - } - - if(enableDragAndDrop) - { - g_signal_connect(G_OBJECT(webview), "drag-data-received", G_CALLBACK(onDragDataReceived), NULL); - g_signal_connect(G_OBJECT(webview), "drag-drop", G_CALLBACK(onDragDrop), NULL); - } - - if (hideWindowOnClose) - { - g_signal_connect(GTK_WIDGET(window), "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL); - } - else - { - g_signal_connect(GTK_WIDGET(window), "delete-event", G_CALLBACK(close_button_pressed), NULL); - } - - WebKitSettings *settings = webkit_web_view_get_settings(WEBKIT_WEB_VIEW(webview)); - webkit_settings_set_user_agent_with_application_details(settings, "wails.io", ""); - - switch (gpuPolicy) - { - case 0: - webkit_settings_set_hardware_acceleration_policy(settings, WEBKIT_HARDWARE_ACCELERATION_POLICY_ALWAYS); - break; - case 1: - webkit_settings_set_hardware_acceleration_policy(settings, WEBKIT_HARDWARE_ACCELERATION_POLICY_ON_DEMAND); - break; - case 2: - webkit_settings_set_hardware_acceleration_policy(settings, WEBKIT_HARDWARE_ACCELERATION_POLICY_NEVER); - break; - default: - webkit_settings_set_hardware_acceleration_policy(settings, WEBKIT_HARDWARE_ACCELERATION_POLICY_ON_DEMAND); - } - return webview; -} - -void DevtoolsEnabled(void *webview, int enabled, bool showInspector) -{ - WebKitSettings *settings = webkit_web_view_get_settings(WEBKIT_WEB_VIEW(webview)); - gboolean genabled = enabled == 1 ? true : false; - webkit_settings_set_enable_developer_extras(settings, genabled); - - if (genabled && showInspector) - { - ShowInspector(webview); - } -} - -void LoadIndex(void *webview, char *url) -{ - webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview), url); -} - -static gboolean startDrag(gpointer data) -{ - DragOptions *options = (DragOptions *)data; - - // Ignore non-toplevel widgets - GtkWidget *window = gtk_widget_get_toplevel(GTK_WIDGET(options->webview)); - if (!GTK_IS_WINDOW(window)) - { - free(data); - return G_SOURCE_REMOVE; - } - - gtk_window_begin_move_drag(options->mainwindow, mouseButton, xroot, yroot, dragTime); - free(data); - - return G_SOURCE_REMOVE; -} - -void StartDrag(void *webview, GtkWindow *mainwindow) -{ - DragOptions *data = malloc(sizeof(DragOptions)); - data->webview = webview; - data->mainwindow = mainwindow; - ExecuteOnMainThread(startDrag, (gpointer)data); -} - -static gboolean startResize(gpointer data) -{ - ResizeOptions *options = (ResizeOptions *)data; - - // Ignore non-toplevel widgets - GtkWidget *window = gtk_widget_get_toplevel(GTK_WIDGET(options->webview)); - if (!GTK_IS_WINDOW(window)) - { - free(data); - return G_SOURCE_REMOVE; - } - - gtk_window_begin_resize_drag(options->mainwindow, options->edge, mouseButton, xroot, yroot, dragTime); - free(data); - - return G_SOURCE_REMOVE; -} - -void StartResize(void *webview, GtkWindow *mainwindow, GdkWindowEdge edge) -{ - ResizeOptions *data = malloc(sizeof(ResizeOptions)); - data->webview = webview; - data->mainwindow = mainwindow; - data->edge = edge; - ExecuteOnMainThread(startResize, (gpointer)data); -} - -void ExecuteJS(void *data) -{ - struct JSCallback *js = data; - webkit_web_view_run_javascript(js->webview, js->script, NULL, NULL, NULL); - free(js->script); -} - -void extern processMessageDialogResult(char *); - -void MessageDialog(void *data) -{ - GtkDialogFlags flags; - GtkMessageType messageType; - MessageDialogOptions *options = (MessageDialogOptions *)data; - if (options->messageType == 0) - { - messageType = GTK_MESSAGE_INFO; - flags = GTK_BUTTONS_OK; - } - else if (options->messageType == 1) - { - messageType = GTK_MESSAGE_ERROR; - flags = GTK_BUTTONS_OK; - } - else if (options->messageType == 2) - { - messageType = GTK_MESSAGE_QUESTION; - flags = GTK_BUTTONS_YES_NO; - } - else - { - messageType = GTK_MESSAGE_WARNING; - flags = GTK_BUTTONS_OK; - } - - GtkWidget *dialog; - dialog = gtk_message_dialog_new(GTK_WINDOW(options->window), - GTK_DIALOG_DESTROY_WITH_PARENT, - messageType, - flags, - options->message, NULL); - gtk_window_set_title(GTK_WINDOW(dialog), options->title); - GtkResponseType result = gtk_dialog_run(GTK_DIALOG(dialog)); - if (result == GTK_RESPONSE_YES) - { - processMessageDialogResult("Yes"); - } - else if (result == GTK_RESPONSE_NO) - { - processMessageDialogResult("No"); - } - else if (result == GTK_RESPONSE_OK) - { - processMessageDialogResult("OK"); - } - else if (result == GTK_RESPONSE_CANCEL) - { - processMessageDialogResult("Cancel"); - } - else - { - processMessageDialogResult(""); - } - - gtk_widget_destroy(dialog); - free(options->title); - free(options->message); -} - -void extern processOpenFileResult(void *); - -GtkFileFilter **AllocFileFilterArray(size_t ln) -{ - return (GtkFileFilter **)malloc(ln * sizeof(GtkFileFilter *)); -} - -void freeFileFilterArray(GtkFileFilter **filters) -{ - free(filters); -} - -void Opendialog(void *data) -{ - struct OpenFileDialogOptions *options = data; - char *label = "_Open"; - if (options->action == GTK_FILE_CHOOSER_ACTION_SAVE) - { - label = "_Save"; - } - GtkWidget *dlgWidget = gtk_file_chooser_dialog_new(options->title, options->window, options->action, - "_Cancel", GTK_RESPONSE_CANCEL, - label, GTK_RESPONSE_ACCEPT, - NULL); - - GtkFileChooser *fc = GTK_FILE_CHOOSER(dlgWidget); - // filters - if (options->filters != 0) - { - int index = 0; - GtkFileFilter *thisFilter; - while (options->filters[index] != NULL) - { - thisFilter = options->filters[index]; - gtk_file_chooser_add_filter(fc, thisFilter); - index++; - } - } - - gtk_file_chooser_set_local_only(fc, FALSE); - - if (options->multipleFiles == 1) - { - gtk_file_chooser_set_select_multiple(fc, TRUE); - } - gtk_file_chooser_set_do_overwrite_confirmation(fc, TRUE); - if (options->createDirectories == 1) - { - gtk_file_chooser_set_create_folders(fc, TRUE); - } - if (options->showHiddenFiles == 1) - { - gtk_file_chooser_set_show_hidden(fc, TRUE); - } - - if (options->defaultDirectory != NULL) - { - gtk_file_chooser_set_current_folder(fc, options->defaultDirectory); - free(options->defaultDirectory); - } - - if (options->action == GTK_FILE_CHOOSER_ACTION_SAVE) - { - if (options->defaultFilename != NULL) - { - gtk_file_chooser_set_current_name(fc, options->defaultFilename); - free(options->defaultFilename); - } - } - - gint response = gtk_dialog_run(GTK_DIALOG(dlgWidget)); - - // Max 1024 files to select - char **result = calloc(1024, sizeof(char *)); - int resultIndex = 0; - - if (response == GTK_RESPONSE_ACCEPT) - { - GSList *filenames = gtk_file_chooser_get_filenames(fc); - GSList *iter = filenames; - while (iter) - { - result[resultIndex++] = (char *)iter->data; - iter = g_slist_next(iter); - if (resultIndex == 1024) - { - break; - } - } - processOpenFileResult(result); - iter = filenames; - while (iter) - { - g_free(iter->data); - iter = g_slist_next(iter); - } - } - else - { - processOpenFileResult(result); - } - free(result); - - // Release filters - if (options->filters != NULL) - { - int index = 0; - GtkFileFilter *thisFilter; - while (options->filters[index] != 0) - { - thisFilter = options->filters[index]; - g_object_unref(thisFilter); - index++; - } - freeFileFilterArray(options->filters); - } - gtk_widget_destroy(dlgWidget); - free(options->title); -} - -GtkFileFilter *newFileFilter() -{ - GtkFileFilter *result = gtk_file_filter_new(); - g_object_ref(result); - return result; -} - -void ShowInspector(void *webview) { - WebKitWebInspector *inspector = webkit_web_view_get_inspector(WEBKIT_WEB_VIEW(webview)); - webkit_web_inspector_show(WEBKIT_WEB_INSPECTOR(inspector)); -} - -void sendShowInspectorMessage() { - processMessage("wails:showInspector"); -} - -void InstallF12Hotkey(void *window) -{ - // When the user presses Ctrl+Shift+F12, call ShowInspector - GtkAccelGroup *accel_group = gtk_accel_group_new(); - gtk_window_add_accel_group(GTK_WINDOW(window), accel_group); - GClosure *closure = g_cclosure_new(G_CALLBACK(sendShowInspectorMessage), window, NULL); - gtk_accel_group_connect(accel_group, GDK_KEY_F12, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_ACCEL_VISIBLE, closure); -} diff --git a/v2/internal/frontend/desktop/linux/window.go b/v2/internal/frontend/desktop/linux/window.go deleted file mode 100644 index 0bf5ac51d..000000000 --- a/v2/internal/frontend/desktop/linux/window.go +++ /dev/null @@ -1,479 +0,0 @@ -//go:build linux -// +build linux - -package linux - -/* -#cgo linux pkg-config: gtk+-3.0 -#cgo !webkit2_41 pkg-config: webkit2gtk-4.0 -#cgo webkit2_41 pkg-config: webkit2gtk-4.1 - -#include -#include -#include -#include -#include -#include -#include "window.h" - -*/ -import "C" -import ( - "log" - "strings" - "sync" - "unsafe" - - "github.com/wailsapp/wails/v2/internal/frontend" - "github.com/wailsapp/wails/v2/pkg/menu" - "github.com/wailsapp/wails/v2/pkg/options" - "github.com/wailsapp/wails/v2/pkg/options/linux" -) - -func gtkBool(input bool) C.gboolean { - if input { - return C.gboolean(1) - } - return C.gboolean(0) -} - -type Window struct { - appoptions *options.App - debug bool - devtoolsEnabled bool - gtkWindow unsafe.Pointer - contentManager unsafe.Pointer - webview unsafe.Pointer - applicationMenu *menu.Menu - menubar *C.GtkWidget - webviewBox *C.GtkWidget - vbox *C.GtkWidget - accels *C.GtkAccelGroup - minWidth, minHeight, maxWidth, maxHeight int -} - -func bool2Cint(value bool) C.int { - if value { - return C.int(1) - } - return C.int(0) -} - -func NewWindow(appoptions *options.App, debug bool, devtoolsEnabled bool) *Window { - validateWebKit2Version(appoptions) - - result := &Window{ - appoptions: appoptions, - debug: debug, - devtoolsEnabled: devtoolsEnabled, - minHeight: appoptions.MinHeight, - minWidth: appoptions.MinWidth, - maxHeight: appoptions.MaxHeight, - maxWidth: appoptions.MaxWidth, - } - - gtkWindow := C.gtk_window_new(C.GTK_WINDOW_TOPLEVEL) - C.g_object_ref_sink(C.gpointer(gtkWindow)) - result.gtkWindow = unsafe.Pointer(gtkWindow) - - webviewName := C.CString("webview-box") - defer C.free(unsafe.Pointer(webviewName)) - result.webviewBox = C.gtk_box_new(C.GTK_ORIENTATION_VERTICAL, 0) - C.gtk_widget_set_name(result.webviewBox, webviewName) - - result.vbox = C.gtk_box_new(C.GTK_ORIENTATION_VERTICAL, 0) - C.gtk_container_add(result.asGTKContainer(), result.vbox) - - result.contentManager = unsafe.Pointer(C.webkit_user_content_manager_new()) - external := C.CString("external") - defer C.free(unsafe.Pointer(external)) - C.webkit_user_content_manager_register_script_message_handler(result.cWebKitUserContentManager(), external) - C.SetupInvokeSignal(result.contentManager) - - var webviewGpuPolicy int - if appoptions.Linux != nil { - webviewGpuPolicy = int(appoptions.Linux.WebviewGpuPolicy) - } else { - // workaround for https://github.com/wailsapp/wails/issues/2977 - webviewGpuPolicy = int(linux.WebviewGpuPolicyNever) - } - - webview := C.SetupWebview( - result.contentManager, - result.asGTKWindow(), - bool2Cint(appoptions.HideWindowOnClose), - C.int(webviewGpuPolicy), - bool2Cint(appoptions.DragAndDrop != nil && appoptions.DragAndDrop.DisableWebViewDrop), - bool2Cint(appoptions.DragAndDrop != nil && appoptions.DragAndDrop.EnableFileDrop), - ) - result.webview = unsafe.Pointer(webview) - buttonPressedName := C.CString("button-press-event") - defer C.free(unsafe.Pointer(buttonPressedName)) - C.ConnectButtons(unsafe.Pointer(webview)) - - if devtoolsEnabled { - C.DevtoolsEnabled(unsafe.Pointer(webview), C.int(1), C.bool(debug && appoptions.Debug.OpenInspectorOnStartup)) - // Install Ctrl-Shift-F12 hotkey to call ShowInspector - C.InstallF12Hotkey(unsafe.Pointer(gtkWindow)) - } - - if !(debug || appoptions.EnableDefaultContextMenu) { - C.DisableContextMenu(unsafe.Pointer(webview)) - } - - // Set background colour - RGBA := appoptions.BackgroundColour - result.SetBackgroundColour(RGBA.R, RGBA.G, RGBA.B, RGBA.A) - - // Setup window - result.SetKeepAbove(appoptions.AlwaysOnTop) - result.SetResizable(!appoptions.DisableResize) - result.SetDefaultSize(appoptions.Width, appoptions.Height) - result.SetDecorated(!appoptions.Frameless) - result.SetTitle(appoptions.Title) - result.SetMinSize(appoptions.MinWidth, appoptions.MinHeight) - result.SetMaxSize(appoptions.MaxWidth, appoptions.MaxHeight) - if appoptions.Linux != nil { - if appoptions.Linux.Icon != nil { - result.SetWindowIcon(appoptions.Linux.Icon) - } - if appoptions.Linux.WindowIsTranslucent { - C.SetWindowTransparency(gtkWindow) - } - } - - // Menu - result.SetApplicationMenu(appoptions.Menu) - - return result -} - -func (w *Window) asGTKWidget() *C.GtkWidget { - return C.GTKWIDGET(w.gtkWindow) -} - -func (w *Window) asGTKWindow() *C.GtkWindow { - return C.GTKWINDOW(w.gtkWindow) -} - -func (w *Window) asGTKContainer() *C.GtkContainer { - return C.GTKCONTAINER(w.gtkWindow) -} - -func (w *Window) cWebKitUserContentManager() *C.WebKitUserContentManager { - return (*C.WebKitUserContentManager)(w.contentManager) -} - -func (w *Window) Fullscreen() { - C.ExecuteOnMainThread(C.Fullscreen, C.gpointer(w.asGTKWindow())) -} - -func (w *Window) UnFullscreen() { - if !w.IsFullScreen() { - return - } - C.ExecuteOnMainThread(C.UnFullscreen, C.gpointer(w.asGTKWindow())) - w.SetMinSize(w.minWidth, w.minHeight) - w.SetMaxSize(w.maxWidth, w.maxHeight) -} - -func (w *Window) Destroy() { - C.gtk_widget_destroy(w.asGTKWidget()) - C.g_object_unref(C.gpointer(w.gtkWindow)) -} - -func (w *Window) Close() { - C.gtk_window_close(w.asGTKWindow()) -} - -func (w *Window) Center() { - C.ExecuteOnMainThread(C.Center, C.gpointer(w.asGTKWindow())) -} - -func (w *Window) SetPosition(x int, y int) { - invokeOnMainThread(func() { - C.SetPosition(unsafe.Pointer(w.asGTKWindow()), C.int(x), C.int(y)) - }) -} - -func (w *Window) Size() (int, int) { - var width, height C.int - var wg sync.WaitGroup - wg.Add(1) - invokeOnMainThread(func() { - C.gtk_window_get_size(w.asGTKWindow(), &width, &height) - wg.Done() - }) - wg.Wait() - return int(width), int(height) -} - -func (w *Window) GetPosition() (int, int) { - var width, height C.int - var wg sync.WaitGroup - wg.Add(1) - invokeOnMainThread(func() { - C.gtk_window_get_position(w.asGTKWindow(), &width, &height) - wg.Done() - }) - wg.Wait() - return int(width), int(height) -} - -func (w *Window) SetMaxSize(maxWidth int, maxHeight int) { - w.maxHeight = maxHeight - w.maxWidth = maxWidth - invokeOnMainThread(func() { - C.SetMinMaxSize(w.asGTKWindow(), C.int(w.minWidth), C.int(w.minHeight), C.int(w.maxWidth), C.int(w.maxHeight)) - }) -} - -func (w *Window) SetMinSize(minWidth int, minHeight int) { - w.minHeight = minHeight - w.minWidth = minWidth - invokeOnMainThread(func() { - C.SetMinMaxSize(w.asGTKWindow(), C.int(w.minWidth), C.int(w.minHeight), C.int(w.maxWidth), C.int(w.maxHeight)) - }) -} - -func (w *Window) Show() { - C.ExecuteOnMainThread(C.Show, C.gpointer(w.asGTKWindow())) -} - -func (w *Window) Hide() { - C.ExecuteOnMainThread(C.Hide, C.gpointer(w.asGTKWindow())) -} - -func (w *Window) Maximise() { - C.ExecuteOnMainThread(C.Maximise, C.gpointer(w.asGTKWindow())) -} - -func (w *Window) UnMaximise() { - C.ExecuteOnMainThread(C.UnMaximise, C.gpointer(w.asGTKWindow())) -} - -func (w *Window) Minimise() { - C.ExecuteOnMainThread(C.Minimise, C.gpointer(w.asGTKWindow())) -} - -func (w *Window) UnMinimise() { - C.ExecuteOnMainThread(C.UnMinimise, C.gpointer(w.asGTKWindow())) -} - -func (w *Window) IsFullScreen() bool { - result := C.IsFullscreen(w.asGTKWidget()) - if result != 0 { - return true - } - return false -} - -func (w *Window) IsMaximised() bool { - result := C.IsMaximised(w.asGTKWidget()) - return result > 0 -} - -func (w *Window) IsMinimised() bool { - result := C.IsMinimised(w.asGTKWidget()) - return result > 0 -} - -func (w *Window) IsNormal() bool { - return !w.IsMaximised() && !w.IsMinimised() && !w.IsFullScreen() -} - -func (w *Window) SetBackgroundColour(r uint8, g uint8, b uint8, a uint8) { - windowIsTranslucent := false - if w.appoptions.Linux != nil && w.appoptions.Linux.WindowIsTranslucent { - windowIsTranslucent = true - } - data := C.RGBAOptions{ - r: C.uchar(r), - g: C.uchar(g), - b: C.uchar(b), - a: C.uchar(a), - webview: w.webview, - webviewBox: unsafe.Pointer(w.webviewBox), - windowIsTranslucent: gtkBool(windowIsTranslucent), - } - invokeOnMainThread(func() { C.SetBackgroundColour(unsafe.Pointer(&data)) }) - -} - -func (w *Window) SetWindowIcon(icon []byte) { - if len(icon) == 0 { - return - } - C.SetWindowIcon(w.asGTKWindow(), (*C.guchar)(&icon[0]), (C.gsize)(len(icon))) -} - -func (w *Window) Run(url string) { - if w.menubar != nil { - C.gtk_box_pack_start(C.GTKBOX(unsafe.Pointer(w.vbox)), w.menubar, 0, 0, 0) - } - - C.gtk_box_pack_start(C.GTKBOX(unsafe.Pointer(w.webviewBox)), C.GTKWIDGET(w.webview), 1, 1, 0) - C.gtk_box_pack_start(C.GTKBOX(unsafe.Pointer(w.vbox)), w.webviewBox, 1, 1, 0) - _url := C.CString(url) - C.LoadIndex(w.webview, _url) - defer C.free(unsafe.Pointer(_url)) - if w.appoptions.StartHidden { - w.Hide() - } - C.gtk_widget_show_all(w.asGTKWidget()) - w.Center() - switch w.appoptions.WindowStartState { - case options.Fullscreen: - w.Fullscreen() - case options.Minimised: - w.Minimise() - case options.Maximised: - w.Maximise() - } -} - -func (w *Window) SetKeepAbove(top bool) { - C.gtk_window_set_keep_above(w.asGTKWindow(), gtkBool(top)) -} - -func (w *Window) SetResizable(resizable bool) { - C.gtk_window_set_resizable(w.asGTKWindow(), gtkBool(resizable)) -} - -func (w *Window) SetDefaultSize(width int, height int) { - C.gtk_window_set_default_size(w.asGTKWindow(), C.int(width), C.int(height)) -} - -func (w *Window) SetSize(width int, height int) { - C.gtk_window_resize(w.asGTKWindow(), C.gint(width), C.gint(height)) -} - -func (w *Window) SetDecorated(frameless bool) { - C.gtk_window_set_decorated(w.asGTKWindow(), gtkBool(frameless)) -} - -func (w *Window) SetTitle(title string) { - C.SetTitle(w.asGTKWindow(), C.CString(title)) -} - -func (w *Window) ExecJS(js string) { - jscallback := C.JSCallback{ - webview: w.webview, - script: C.CString(js), - } - invokeOnMainThread(func() { C.ExecuteJS(unsafe.Pointer(&jscallback)) }) -} - -func (w *Window) StartDrag() { - C.StartDrag(w.webview, w.asGTKWindow()) -} - -func (w *Window) StartResize(edge uintptr) { - C.StartResize(w.webview, w.asGTKWindow(), C.GdkWindowEdge(edge)) -} - -func (w *Window) Quit() { - C.gtk_main_quit() -} - -func (w *Window) OpenFileDialog(dialogOptions frontend.OpenDialogOptions, multipleFiles int, action C.GtkFileChooserAction) { - - data := C.OpenFileDialogOptions{ - window: w.asGTKWindow(), - title: C.CString(dialogOptions.Title), - multipleFiles: C.int(multipleFiles), - action: action, - } - - if len(dialogOptions.Filters) > 0 { - // Create filter array - mem := NewCalloc() - arraySize := len(dialogOptions.Filters) + 1 - data.filters = C.AllocFileFilterArray((C.size_t)(arraySize)) - filters := unsafe.Slice((**C.struct__GtkFileFilter)(unsafe.Pointer(data.filters)), arraySize) - for index, filter := range dialogOptions.Filters { - thisFilter := C.gtk_file_filter_new() - C.g_object_ref(C.gpointer(thisFilter)) - if filter.DisplayName != "" { - cName := mem.String(filter.DisplayName) - C.gtk_file_filter_set_name(thisFilter, cName) - } - if filter.Pattern != "" { - for _, thisPattern := range strings.Split(filter.Pattern, ";") { - cThisPattern := mem.String(thisPattern) - C.gtk_file_filter_add_pattern(thisFilter, cThisPattern) - } - } - // Add filter to array - filters[index] = thisFilter - } - mem.Free() - filters[arraySize-1] = nil - } - - if dialogOptions.CanCreateDirectories { - data.createDirectories = C.int(1) - } - - if dialogOptions.ShowHiddenFiles { - data.showHiddenFiles = C.int(1) - } - - if dialogOptions.DefaultFilename != "" { - data.defaultFilename = C.CString(dialogOptions.DefaultFilename) - } - - if dialogOptions.DefaultDirectory != "" { - data.defaultDirectory = C.CString(dialogOptions.DefaultDirectory) - } - - invokeOnMainThread(func() { C.Opendialog(unsafe.Pointer(&data)) }) -} - -func (w *Window) MessageDialog(dialogOptions frontend.MessageDialogOptions) { - - data := C.MessageDialogOptions{ - window: w.gtkWindow, - title: C.CString(dialogOptions.Title), - message: C.CString(dialogOptions.Message), - } - switch dialogOptions.Type { - case frontend.InfoDialog: - data.messageType = C.int(0) - case frontend.ErrorDialog: - data.messageType = C.int(1) - case frontend.QuestionDialog: - data.messageType = C.int(2) - case frontend.WarningDialog: - data.messageType = C.int(3) - } - invokeOnMainThread(func() { C.MessageDialog(unsafe.Pointer(&data)) }) -} - -func (w *Window) ToggleMaximise() { - if w.IsMaximised() { - w.UnMaximise() - } else { - w.Maximise() - } -} - -func (w *Window) ShowInspector() { - invokeOnMainThread(func() { C.ShowInspector(w.webview) }) -} - -// showModalDialogAndExit shows a modal dialog and exits the app. -func showModalDialogAndExit(title, message string) { - go func() { - data := C.MessageDialogOptions{ - title: C.CString(title), - message: C.CString(message), - messageType: C.int(1), - } - - C.MessageDialog(unsafe.Pointer(&data)) - }() - - <-messageDialogResult - log.Fatal(message) -} diff --git a/v2/internal/frontend/desktop/linux/window.h b/v2/internal/frontend/desktop/linux/window.h deleted file mode 100644 index 04410959a..000000000 --- a/v2/internal/frontend/desktop/linux/window.h +++ /dev/null @@ -1,128 +0,0 @@ -#ifndef window_h -#define window_h - -#include -#include -#include -#include -#include -#include - -typedef struct DragOptions -{ - void *webview; - GtkWindow *mainwindow; -} DragOptions; - -typedef struct ResizeOptions -{ - void *webview; - GtkWindow *mainwindow; - GdkWindowEdge edge; -} ResizeOptions; - -typedef struct JSCallback -{ - void *webview; - char *script; -} JSCallback; - -typedef struct MessageDialogOptions -{ - void *window; - char *title; - char *message; - int messageType; -} MessageDialogOptions; - -typedef struct OpenFileDialogOptions -{ - GtkWindow *window; - char *title; - char *defaultFilename; - char *defaultDirectory; - int createDirectories; - int multipleFiles; - int showHiddenFiles; - GtkFileChooserAction action; - GtkFileFilter **filters; -} OpenFileDialogOptions; - -typedef struct RGBAOptions -{ - uint8_t r; - uint8_t g; - uint8_t b; - uint8_t a; - void *webview; - void *webviewBox; - gboolean windowIsTranslucent; -} RGBAOptions; - -typedef struct SetTitleArgs -{ - GtkWindow *window; - char *title; -} SetTitleArgs; - -typedef struct SetPositionArgs -{ - int x; - int y; - void *window; -} SetPositionArgs; - -void ExecuteOnMainThread(void *f, gpointer jscallback); - -GtkWidget *GTKWIDGET(void *pointer); -GtkWindow *GTKWINDOW(void *pointer); -GtkContainer *GTKCONTAINER(void *pointer); -GtkBox *GTKBOX(void *pointer); - -// window -ulong SetupInvokeSignal(void *contentManager); - -void SetWindowIcon(GtkWindow *window, const guchar *buf, gsize len); -void SetWindowTransparency(GtkWidget *widget); -void SetBackgroundColour(void *data); -void SetTitle(GtkWindow *window, char *title); -void SetPosition(void *window, int x, int y); -void SetMinMaxSize(GtkWindow *window, int min_width, int min_height, int max_width, int max_height); -void DisableContextMenu(void *webview); -void ConnectButtons(void *webview); - -int IsFullscreen(GtkWidget *widget); -int IsMaximised(GtkWidget *widget); -int IsMinimised(GtkWidget *widget); - -gboolean Center(gpointer data); -gboolean Show(gpointer data); -gboolean Hide(gpointer data); -gboolean Maximise(gpointer data); -gboolean UnMaximise(gpointer data); -gboolean Minimise(gpointer data); -gboolean UnMinimise(gpointer data); -gboolean Fullscreen(gpointer data); -gboolean UnFullscreen(gpointer data); - -// WebView -GtkWidget *SetupWebview(void *contentManager, GtkWindow *window, int hideWindowOnClose, int gpuPolicy, int disableWebViewDragAndDrop, int enableDragAndDrop); -void LoadIndex(void *webview, char *url); -void DevtoolsEnabled(void *webview, int enabled, bool showInspector); -void ExecuteJS(void *data); - -// Drag -void StartDrag(void *webview, GtkWindow *mainwindow); -void StartResize(void *webview, GtkWindow *mainwindow, GdkWindowEdge edge); - -// Dialog -void MessageDialog(void *data); -GtkFileFilter **AllocFileFilterArray(size_t ln); -void Opendialog(void *data); - -// Inspector -void sendShowInspectorMessage(); -void ShowInspector(void *webview); -void InstallF12Hotkey(void *window); - -#endif /* window_h */ diff --git a/v2/internal/frontend/desktop/windows/browser.go b/v2/internal/frontend/desktop/windows/browser.go index 13d037b14..f23b04dbe 100644 --- a/v2/internal/frontend/desktop/windows/browser.go +++ b/v2/internal/frontend/desktop/windows/browser.go @@ -4,40 +4,11 @@ package windows import ( - "fmt" "github.com/pkg/browser" - "github.com/wailsapp/wails/v2/internal/frontend/utils" - "golang.org/x/sys/windows" ) -var fallbackBrowserPaths = []string{ - `\Program Files (x86)\Microsoft\Edge\Application\msedge.exe`, - `\Program Files\Google\Chrome\Application\chrome.exe`, - `\Program Files (x86)\Google\Chrome\Application\chrome.exe`, - `\Program Files\Mozilla Firefox\firefox.exe`, -} - // BrowserOpenURL Use the default browser to open the url -func (f *Frontend) BrowserOpenURL(rawURL string) { - url, err := utils.ValidateAndSanitizeURL(rawURL) - if err != nil { - f.logger.Error(fmt.Sprintf("Invalid URL %s", err.Error())) - return - } - +func (f *Frontend) BrowserOpenURL(url string) { // Specific method implementation - err = browser.OpenURL(url) - if err == nil { - return - } - for _, fallback := range fallbackBrowserPaths { - if err := openBrowser(fallback, url); err == nil { - return - } - } - f.logger.Error("Unable to open default system browser") -} - -func openBrowser(path, url string) error { - return windows.ShellExecute(0, nil, windows.StringToUTF16Ptr(path), windows.StringToUTF16Ptr(url), nil, windows.SW_SHOWNORMAL) + _ = browser.OpenURL(url) } diff --git a/v2/internal/frontend/desktop/windows/clipboard.go b/v2/internal/frontend/desktop/windows/clipboard.go deleted file mode 100644 index 975fa8e7c..000000000 --- a/v2/internal/frontend/desktop/windows/clipboard.go +++ /dev/null @@ -1,16 +0,0 @@ -//go:build windows -// +build windows - -package windows - -import ( - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/win32" -) - -func (f *Frontend) ClipboardGetText() (string, error) { - return win32.GetClipboardText() -} - -func (f *Frontend) ClipboardSetText(text string) error { - return win32.SetClipboardText(text) -} diff --git a/v2/internal/frontend/desktop/windows/dialog.go b/v2/internal/frontend/desktop/windows/dialog.go index 573325886..eb7747223 100644 --- a/v2/internal/frontend/desktop/windows/dialog.go +++ b/v2/internal/frontend/desktop/windows/dialog.go @@ -1,180 +1,114 @@ //go:build windows -// +build windows package windows import ( - "path/filepath" - "strings" - "syscall" - + "github.com/leaanthony/go-common-file-dialog/cfd" "github.com/wailsapp/wails/v2/internal/frontend" - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" - "github.com/wailsapp/wails/v2/internal/go-common-file-dialog/cfd" "golang.org/x/sys/windows" + "syscall" ) -func (f *Frontend) getHandleForDialog() w32.HWND { - if f.mainWindow.IsVisible() { - return f.mainWindow.Handle() - } - return 0 -} - -func getDefaultFolder(folder string) (string, error) { - if folder == "" { - return "", nil - } - return filepath.Abs(folder) -} - // OpenDirectoryDialog prompts the user to select a directory func (f *Frontend) OpenDirectoryDialog(options frontend.OpenDialogOptions) (string, error) { - - defaultFolder, err := getDefaultFolder(options.DefaultDirectory) - if err != nil { - return "", err - } - config := cfd.DialogConfig{ Title: options.Title, Role: "PickFolder", - Folder: defaultFolder, + Folder: options.DefaultDirectory, } - - result, err := f.showCfdDialog( - func() (cfd.Dialog, error) { - return cfd.NewSelectFolderDialog(config) - }, false) - - if err != nil && err != cfd.ErrCancelled { + thisDialog, err := cfd.NewSelectFolderDialog(config) + if err != nil { return "", err } - return result.(string), nil + thisDialog.SetParentWindowHandle(f.mainWindow.Handle()) + defer func(thisDialog cfd.SelectFolderDialog) { + err := thisDialog.Release() + if err != nil { + println("ERROR: Unable to release dialog:", err.Error()) + } + }(thisDialog) + result, err := thisDialog.ShowAndGetResult() + if err != nil && err != cfd.ErrorCancelled { + return "", err + } + return result, nil } // OpenFileDialog prompts the user to select a file func (f *Frontend) OpenFileDialog(options frontend.OpenDialogOptions) (string, error) { - defaultFolder, err := getDefaultFolder(options.DefaultDirectory) - if err != nil { - return "", err - } - config := cfd.DialogConfig{ - Folder: defaultFolder, + Folder: options.DefaultDirectory, FileFilters: convertFilters(options.Filters), FileName: options.DefaultFilename, Title: options.Title, } - - result, err := f.showCfdDialog( - func() (cfd.Dialog, error) { - return cfd.NewOpenFileDialog(config) - }, false) - - if err != nil && err != cfd.ErrCancelled { + thisdialog, err := cfd.NewOpenFileDialog(config) + if err != nil { return "", err } - return result.(string), nil + thisdialog.SetParentWindowHandle(f.mainWindow.Handle()) + defer func(thisdialog cfd.OpenFileDialog) { + err := thisdialog.Release() + if err != nil { + println("ERROR: Unable to release dialog:", err.Error()) + } + }(thisdialog) + result, err := thisdialog.ShowAndGetResult() + if err != nil && err != cfd.ErrorCancelled { + return "", err + } + return result, nil } // OpenMultipleFilesDialog prompts the user to select a file -func (f *Frontend) OpenMultipleFilesDialog(options frontend.OpenDialogOptions) ([]string, error) { - - defaultFolder, err := getDefaultFolder(options.DefaultDirectory) +func (f *Frontend) OpenMultipleFilesDialog(dialogOptions frontend.OpenDialogOptions) ([]string, error) { + config := cfd.DialogConfig{ + Title: dialogOptions.Title, + Role: "OpenMultipleFiles", + FileFilters: convertFilters(dialogOptions.Filters), + FileName: dialogOptions.DefaultFilename, + Folder: dialogOptions.DefaultDirectory, + } + thisdialog, err := cfd.NewOpenMultipleFilesDialog(config) if err != nil { return nil, err } - - config := cfd.DialogConfig{ - Title: options.Title, - Role: "OpenMultipleFiles", - FileFilters: convertFilters(options.Filters), - FileName: options.DefaultFilename, - Folder: defaultFolder, - } - - result, err := f.showCfdDialog( - func() (cfd.Dialog, error) { - return cfd.NewOpenMultipleFilesDialog(config) - }, true) - - if err != nil && err != cfd.ErrCancelled { + thisdialog.SetParentWindowHandle(f.mainWindow.Handle()) + defer func(thisdialog cfd.OpenMultipleFilesDialog) { + err := thisdialog.Release() + if err != nil { + println("ERROR: Unable to release dialog:", err.Error()) + } + }(thisdialog) + result, err := thisdialog.ShowAndGetResults() + if err != nil && err != cfd.ErrorCancelled { return nil, err } - return result.([]string), nil + return result, nil } // SaveFileDialog prompts the user to select a file -func (f *Frontend) SaveFileDialog(options frontend.SaveDialogOptions) (string, error) { - - defaultFolder, err := getDefaultFolder(options.DefaultDirectory) +func (f *Frontend) SaveFileDialog(dialogOptions frontend.SaveDialogOptions) (string, error) { + saveDialog, err := cfd.NewSaveFileDialog(cfd.DialogConfig{ + Title: dialogOptions.Title, + Role: "SaveFile", + FileFilters: convertFilters(dialogOptions.Filters), + FileName: dialogOptions.DefaultFilename, + Folder: dialogOptions.DefaultDirectory, + }) if err != nil { return "", err } - - config := cfd.DialogConfig{ - Title: options.Title, - Role: "SaveFile", - FileFilters: convertFilters(options.Filters), - FileName: options.DefaultFilename, - Folder: defaultFolder, - } - - if len(options.Filters) > 0 { - config.DefaultExtension = strings.TrimPrefix(strings.Split(options.Filters[0].Pattern, ";")[0], "*") - } - - result, err := f.showCfdDialog( - func() (cfd.Dialog, error) { - return cfd.NewSaveFileDialog(config) - }, false) - - if err != nil && err != cfd.ErrCancelled { + saveDialog.SetParentWindowHandle(f.mainWindow.Handle()) + err = saveDialog.Show() + if err != nil { return "", err } - return result.(string), nil -} - -func (f *Frontend) showCfdDialog(newDlg func() (cfd.Dialog, error), isMultiSelect bool) (any, error) { - return invokeSync(f.mainWindow, func() (any, error) { - dlg, err := newDlg() - if err != nil { - return nil, err - } - defer func() { - err := dlg.Release() - if err != nil { - println("ERROR: Unable to release dialog:", err.Error()) - } - }() - - dlg.SetParentWindowHandle(f.getHandleForDialog()) - if multi, _ := dlg.(cfd.OpenMultipleFilesDialog); multi != nil && isMultiSelect { - return multi.ShowAndGetResults() - } - return dlg.ShowAndGetResult() - }) -} - -func calculateMessageDialogFlags(options frontend.MessageDialogOptions) uint32 { - var flags uint32 - - switch options.Type { - case frontend.InfoDialog: - flags = windows.MB_OK | windows.MB_ICONINFORMATION - case frontend.ErrorDialog: - flags = windows.MB_ICONERROR | windows.MB_OK - case frontend.QuestionDialog: - flags = windows.MB_YESNO - if strings.TrimSpace(strings.ToLower(options.DefaultButton)) == "no" { - flags |= windows.MB_DEFBUTTON2 - } - case frontend.WarningDialog: - flags = windows.MB_OK | windows.MB_ICONWARNING + result, err := saveDialog.GetResult() + if err != nil && err != cfd.ErrorCancelled { + return "", err } - - return flags + return result, nil } // MessageDialog show a message dialog to the user @@ -188,10 +122,19 @@ func (f *Frontend) MessageDialog(options frontend.MessageDialogOptions) (string, if err != nil { return "", err } + var flags uint32 + switch options.Type { + case frontend.InfoDialog: + flags = windows.MB_OK | windows.MB_ICONINFORMATION + case frontend.ErrorDialog: + flags = windows.MB_ICONERROR | windows.MB_OK + case frontend.QuestionDialog: + flags = windows.MB_YESNO + case frontend.WarningDialog: + flags = windows.MB_OK | windows.MB_ICONWARNING + } - flags := calculateMessageDialogFlags(options) - - button, _ := windows.MessageBox(windows.HWND(f.getHandleForDialog()), message, title, flags|windows.MB_SYSTEMMODAL) + button, _ := windows.MessageBox(windows.HWND(f.mainWindow.Handle()), message, title, flags|windows.MB_SYSTEMMODAL) // This maps MessageBox return values to strings responses := []string{"", "Ok", "Cancel", "Abort", "Retry", "Ignore", "Yes", "No", "", "", "Try Again", "Continue"} result := "Error" diff --git a/v2/internal/frontend/desktop/windows/dialog_test.go b/v2/internal/frontend/desktop/windows/dialog_test.go deleted file mode 100644 index e91058e92..000000000 --- a/v2/internal/frontend/desktop/windows/dialog_test.go +++ /dev/null @@ -1,77 +0,0 @@ -//go:build windows - -package windows - -import ( - "testing" - - "github.com/wailsapp/wails/v2/internal/frontend" - "golang.org/x/sys/windows" -) - -func Test_calculateMessageDialogFlags(t *testing.T) { - tests := []struct { - name string - options frontend.MessageDialogOptions - want uint32 - }{ - { - name: "Test Info Dialog", - options: frontend.MessageDialogOptions{ - Type: frontend.InfoDialog, - }, - want: windows.MB_OK | windows.MB_ICONINFORMATION, - }, - { - name: "Test Error Dialog", - options: frontend.MessageDialogOptions{ - Type: frontend.ErrorDialog, - }, - want: windows.MB_ICONERROR | windows.MB_OK, - }, - { - name: "Test Question Dialog", - options: frontend.MessageDialogOptions{ - Type: frontend.QuestionDialog, - }, - want: windows.MB_YESNO, - }, - { - name: "Test Question Dialog with default cancel", - options: frontend.MessageDialogOptions{ - Type: frontend.QuestionDialog, - DefaultButton: "No", - }, - want: windows.MB_YESNO | windows.MB_DEFBUTTON2, - }, - { - name: "Test Question Dialog with default cancel (lowercase)", - options: frontend.MessageDialogOptions{ - Type: frontend.QuestionDialog, - DefaultButton: "no", - }, - want: windows.MB_YESNO | windows.MB_DEFBUTTON2, - }, - { - name: "Test Warning Dialog", - options: frontend.MessageDialogOptions{ - Type: frontend.WarningDialog, - }, - want: windows.MB_OK | windows.MB_ICONWARNING, - }, - { - name: "Test Error Dialog", - options: frontend.MessageDialogOptions{ - Type: frontend.ErrorDialog, - }, - want: windows.MB_ICONERROR | windows.MB_OK, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := calculateMessageDialogFlags(tt.options); got != tt.want { - t.Errorf("calculateMessageDialogFlags() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/v2/internal/frontend/desktop/windows/frontend.go b/v2/internal/frontend/desktop/windows/frontend.go index 5df13ed98..2f551cd15 100644 --- a/v2/internal/frontend/desktop/windows/frontend.go +++ b/v2/internal/frontend/desktop/windows/frontend.go @@ -8,41 +8,21 @@ import ( "encoding/json" "fmt" "log" - "net" - "net/url" - "os" "runtime" + "strconv" "strings" - "sync" "text/template" - "time" - "unsafe" - "github.com/bep/debounce" - "github.com/wailsapp/go-webview2/pkg/edge" + "github.com/leaanthony/go-webview2/pkg/edge" + "github.com/leaanthony/winc" + "github.com/leaanthony/winc/w32" "github.com/wailsapp/wails/v2/internal/binding" "github.com/wailsapp/wails/v2/internal/frontend" - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/win32" - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc" - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" - "github.com/wailsapp/wails/v2/internal/frontend/originvalidator" - wailsruntime "github.com/wailsapp/wails/v2/internal/frontend/runtime" + "github.com/wailsapp/wails/v2/internal/frontend/assetserver" "github.com/wailsapp/wails/v2/internal/logger" - w32consts "github.com/wailsapp/wails/v2/internal/platform/win32" - "github.com/wailsapp/wails/v2/internal/system/operatingsystem" - "github.com/wailsapp/wails/v2/pkg/assetserver" - "github.com/wailsapp/wails/v2/pkg/assetserver/webview" "github.com/wailsapp/wails/v2/pkg/options" - "github.com/wailsapp/wails/v2/pkg/options/windows" - w "golang.org/x/sys/windows" ) -const startURL = "http://wails.localhost/" - -var secondInstanceBuffer = make(chan options.SecondInstanceData, 1) - -type Screen = frontend.Screen - type Frontend struct { // Context @@ -52,87 +32,64 @@ type Frontend struct { logger *logger.Logger chromium *edge.Chromium debug bool - devtoolsEnabled bool // Assets - assets *assetserver.AssetServer - startURL *url.URL + assets *assetserver.DesktopAssetServer + startURL string // main window handle - mainWindow *Window - bindings *binding.Bindings - dispatcher frontend.Dispatcher - - hasStarted bool - - originValidator *originvalidator.OriginValidator - - // Windows build number - versionInfo *operatingsystem.WindowsVersionInfo - resizeDebouncer func(f func()) + mainWindow *Window + minWidth, minHeight, maxWidth, maxHeight int + bindings *binding.Bindings + dispatcher frontend.Dispatcher + servingFromDisk bool } func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.Logger, appBindings *binding.Bindings, dispatcher frontend.Dispatcher) *Frontend { - // Get Windows build number - versionInfo, _ := operatingsystem.GetWindowsVersionInfo() - - // Apply DLL search path settings if specified - if appoptions.Windows != nil && appoptions.Windows.DLLSearchPaths != 0 { - w.SetDefaultDllDirectories(appoptions.Windows.DLLSearchPaths) - } - // Now initialize packages that load DLLs - w32.Init() - w32consts.Init() result := &Frontend{ frontendOptions: appoptions, logger: myLogger, bindings: appBindings, dispatcher: dispatcher, ctx: ctx, - versionInfo: versionInfo, + minHeight: appoptions.MinHeight, + minWidth: appoptions.MinWidth, + maxHeight: appoptions.MaxHeight, + maxWidth: appoptions.MaxWidth, + startURL: "file://wails/", } - if appoptions.Windows != nil { - if appoptions.Windows.ResizeDebounceMS > 0 { - result.resizeDebouncer = debounce.New(time.Duration(appoptions.Windows.ResizeDebounceMS) * time.Millisecond) + bindingsJSON, err := appBindings.ToJSON() + if err != nil { + log.Fatal(err) + } + + _devServerURL := ctx.Value("devserverurl") + if _devServerURL != nil { + devServerURL := _devServerURL.(string) + if len(devServerURL) > 0 && devServerURL != "http://localhost:34115" { + result.startURL = devServerURL + return result } } - // We currently can't use wails://wails/ as other platforms do, therefore we map the assets sever onto the following url. - result.startURL, _ = url.Parse(startURL) - result.originValidator = originvalidator.NewOriginValidator(result.startURL, appoptions.BindingsAllowedOrigins) + // Check if we have been given a directory to serve assets from. + // If so, this means we are in dev mode and are serving assets off disk. + // We indicate this through the `servingFromDisk` flag to ensure requests + // aren't cached by WebView2 in dev mode - if _starturl, _ := ctx.Value("starturl").(*url.URL); _starturl != nil { - result.startURL = _starturl - result.originValidator = originvalidator.NewOriginValidator(result.startURL, appoptions.BindingsAllowedOrigins) - return result + _assetdir := ctx.Value("assetdir") + if _assetdir != nil { + result.servingFromDisk = true } - if port, _ := ctx.Value("assetserverport").(string); port != "" { - result.startURL.Host = net.JoinHostPort(result.startURL.Host, port) - result.originValidator = originvalidator.NewOriginValidator(result.startURL, appoptions.BindingsAllowedOrigins) - } - - var bindings string - var err error - if _obfuscated, _ := ctx.Value("obfuscated").(bool); !_obfuscated { - bindings, err = appBindings.ToJSON() - if err != nil { - log.Fatal(err) - } - } else { - appBindings.DB().UpdateObfuscatedCallMap() - } - - assets, err := assetserver.NewAssetServerMainPage(bindings, appoptions, ctx.Value("assetdir") != nil, myLogger, wailsruntime.RuntimeAssetsBundle) + assets, err := assetserver.NewDesktopAssetServer(ctx, appoptions.Assets, bindingsJSON) if err != nil { log.Fatal(err) } result.assets = assets - go result.startSecondInstanceProcessor() - return result } @@ -140,75 +97,23 @@ func (f *Frontend) WindowReload() { f.ExecJS("runtime.WindowReload();") } -func (f *Frontend) WindowSetSystemDefaultTheme() { - f.mainWindow.SetTheme(windows.SystemDefault) -} - -func (f *Frontend) WindowSetLightTheme() { - f.mainWindow.SetTheme(windows.Light) -} - -func (f *Frontend) WindowSetDarkTheme() { - f.mainWindow.SetTheme(windows.Dark) -} - func (f *Frontend) Run(ctx context.Context) error { - f.ctx = ctx - f.chromium = edge.NewChromium() + f.ctx = context.WithValue(ctx, "frontend", f) - if f.frontendOptions.SingleInstanceLock != nil { - SetupSingleInstance(f.frontendOptions.SingleInstanceLock.UniqueId) - } - - mainWindow := NewWindow(nil, f.frontendOptions, f.versionInfo, f.chromium) + mainWindow := NewWindow(nil, f.frontendOptions) f.mainWindow = mainWindow var _debug = ctx.Value("debug") - var _devtoolsEnabled = ctx.Value("devtoolsEnabled") - if _debug != nil { f.debug = _debug.(bool) } - if _devtoolsEnabled != nil { - f.devtoolsEnabled = _devtoolsEnabled.(bool) - } f.WindowCenter() f.setupChromium() mainWindow.OnSize().Bind(func(arg *winc.Event) { - if f.frontendOptions.Frameless { - // If the window is frameless and we are minimizing, then we need to suppress the Resize on the - // WebView2. If we don't do this, restoring does not work as expected and first restores with some wrong - // size during the restore animation and only fully renders when the animation is done. This highly - // depends on the content in the WebView, see https://github.com/wailsapp/wails/issues/1319 - event, _ := arg.Data.(*winc.SizeEventData) - if event != nil && event.Type == w32.SIZE_MINIMIZED { - // Set minimizing flag to prevent unnecessary redraws during minimize/restore for frameless windows - // 设置最小化标志以防止无边框窗口在最小化/恢复过程中的不必要重绘 - // This fixes window flickering when minimizing/restoring frameless windows - // 这修复了无边框窗口在最小化/恢复时的闪烁问题 - // Reference: https://github.com/wailsapp/wails/issues/3951 - f.mainWindow.isMinimizing = true - return - } - } - - // Clear minimizing flag for all non-minimize size events - // 对于所有非最小化的尺寸变化事件,清除最小化标志 - // Reference: https://github.com/wailsapp/wails/issues/3951 - f.mainWindow.isMinimizing = false - - if f.resizeDebouncer != nil { - f.resizeDebouncer(func() { - f.mainWindow.Invoke(func() { - f.chromium.Resize() - }) - }) - } else { - f.chromium.Resize() - } + f.chromium.Resize() }) mainWindow.OnClose().Bind(func(arg *winc.Event) { @@ -224,167 +129,105 @@ func (f *Frontend) Run(ctx context.Context) error { f.frontendOptions.OnStartup(f.ctx) } }() - mainWindow.UpdateTheme() - return nil -} -func (f *Frontend) WindowClose() { - if f.mainWindow != nil { - f.mainWindow.Close() + if f.frontendOptions.Fullscreen { + mainWindow.Fullscreen() } -} -func (f *Frontend) RunMainLoop() { - _ = winc.RunMainLoop() + mainWindow.Run() + mainWindow.Close() + return nil } func (f *Frontend) WindowCenter() { runtime.LockOSThread() - defer runtime.UnlockOSThread() f.mainWindow.Center() } -func (f *Frontend) WindowSetAlwaysOnTop(b bool) { +func (f *Frontend) WindowSetPos(x, y int) { runtime.LockOSThread() - defer runtime.UnlockOSThread() - f.mainWindow.SetAlwaysOnTop(b) -} - -func (f *Frontend) WindowSetPosition(x, y int) { - runtime.LockOSThread() - defer runtime.UnlockOSThread() f.mainWindow.SetPos(x, y) } -func (f *Frontend) WindowGetPosition() (int, int) { +func (f *Frontend) WindowGetPos() (int, int) { runtime.LockOSThread() - defer runtime.UnlockOSThread() return f.mainWindow.Pos() } func (f *Frontend) WindowSetSize(width, height int) { runtime.LockOSThread() - defer runtime.UnlockOSThread() f.mainWindow.SetSize(width, height) } func (f *Frontend) WindowGetSize() (int, int) { runtime.LockOSThread() - defer runtime.UnlockOSThread() return f.mainWindow.Size() } func (f *Frontend) WindowSetTitle(title string) { runtime.LockOSThread() - defer runtime.UnlockOSThread() f.mainWindow.SetText(title) } func (f *Frontend) WindowFullscreen() { runtime.LockOSThread() - defer runtime.UnlockOSThread() - if f.frontendOptions.Frameless && f.frontendOptions.DisableResize == false { - f.ExecJS("window.wails.flags.enableResize = false;") - } + f.mainWindow.SetMaxSize(0, 0) + f.mainWindow.SetMinSize(0, 0) f.mainWindow.Fullscreen() } -func (f *Frontend) WindowReloadApp() { - f.ExecJS(fmt.Sprintf("window.location.href = '%s';", f.startURL)) -} - -func (f *Frontend) WindowUnfullscreen() { +func (f *Frontend) WindowUnFullscreen() { runtime.LockOSThread() - defer runtime.UnlockOSThread() - if f.frontendOptions.Frameless && f.frontendOptions.DisableResize == false { - f.ExecJS("window.wails.flags.enableResize = true;") - } f.mainWindow.UnFullscreen() + f.mainWindow.SetMaxSize(f.maxWidth, f.maxHeight) + f.mainWindow.SetMinSize(f.minWidth, f.minHeight) } func (f *Frontend) WindowShow() { runtime.LockOSThread() - defer runtime.UnlockOSThread() - f.ShowWindow() + f.mainWindow.Show() } func (f *Frontend) WindowHide() { runtime.LockOSThread() - defer runtime.UnlockOSThread() f.mainWindow.Hide() } - func (f *Frontend) WindowMaximise() { runtime.LockOSThread() - defer runtime.UnlockOSThread() - if f.hasStarted { - if !f.frontendOptions.DisableResize { - f.mainWindow.Maximise() - } - } else { - f.frontendOptions.WindowStartState = options.Maximised - } + f.mainWindow.Maximise() } - -func (f *Frontend) WindowToggleMaximise() { - runtime.LockOSThread() - defer runtime.UnlockOSThread() - if !f.hasStarted { - return - } - if f.mainWindow.IsMaximised() { - f.WindowUnmaximise() - } else { - f.WindowMaximise() - } -} - func (f *Frontend) WindowUnmaximise() { runtime.LockOSThread() - defer runtime.UnlockOSThread() - if f.mainWindow.Form.IsFullScreen() { - return - } f.mainWindow.Restore() } - func (f *Frontend) WindowMinimise() { runtime.LockOSThread() - defer runtime.UnlockOSThread() - if f.hasStarted { - f.mainWindow.Minimise() - } else { - f.frontendOptions.WindowStartState = options.Minimised - } + f.mainWindow.Minimise() } - func (f *Frontend) WindowUnminimise() { runtime.LockOSThread() - defer runtime.UnlockOSThread() - if f.mainWindow.Form.IsFullScreen() { - return - } f.mainWindow.Restore() } func (f *Frontend) WindowSetMinSize(width int, height int) { runtime.LockOSThread() - defer runtime.UnlockOSThread() + f.minWidth = width + f.minHeight = height f.mainWindow.SetMinSize(width, height) } func (f *Frontend) WindowSetMaxSize(width int, height int) { runtime.LockOSThread() - defer runtime.UnlockOSThread() + f.maxWidth = width + f.maxHeight = height f.mainWindow.SetMaxSize(width, height) } -func (f *Frontend) WindowSetBackgroundColour(col *options.RGBA) { +func (f *Frontend) WindowSetRGBA(col *options.RGBA) { + runtime.LockOSThread() if col == nil { return } - f.mainWindow.Invoke(func() { - win32.SetBackgroundColour(f.mainWindow.Handle(), col.R, col.G, col.B) - + f.mainWindow.Dispatch(func() { controller := f.chromium.GetController() controller2 := controller.GetICoreWebView2Controller2() @@ -395,7 +238,7 @@ func (f *Frontend) WindowSetBackgroundColour(col *options.RGBA) { B: col.B, } - // WebView2 only has 0 and 255 as valid values. + // Webview2 only has 0 and 255 as valid values. if backgroundCol.A > 0 && backgroundCol.A < 255 { backgroundCol.A = 255 } @@ -409,180 +252,40 @@ func (f *Frontend) WindowSetBackgroundColour(col *options.RGBA) { log.Fatal(err) } }) - -} - -func (f *Frontend) ScreenGetAll() ([]Screen, error) { - var wg sync.WaitGroup - wg.Add(1) - screens := []Screen{} - err := error(nil) - f.mainWindow.Invoke(func() { - screens, err = GetAllScreens(f.mainWindow.Handle()) - wg.Done() - - }) - wg.Wait() - return screens, err -} - -func (f *Frontend) Show() { - f.mainWindow.Show() -} - -func (f *Frontend) Hide() { - f.mainWindow.Hide() -} - -func (f *Frontend) WindowIsMaximised() bool { - return f.mainWindow.IsMaximised() -} - -func (f *Frontend) WindowIsMinimised() bool { - return f.mainWindow.IsMinimised() -} - -func (f *Frontend) WindowIsNormal() bool { - return f.mainWindow.IsNormal() -} - -func (f *Frontend) WindowIsFullscreen() bool { - return f.mainWindow.IsFullScreen() } func (f *Frontend) Quit() { - if f.frontendOptions.OnBeforeClose != nil && f.frontendOptions.OnBeforeClose(f.ctx) { - return - } - // Exit must be called on the Main-Thread. It calls PostQuitMessage which sends the WM_QUIT message to the thread's - // message queue and our message queue runs on the Main-Thread. - f.mainWindow.Invoke(winc.Exit) -} - -func (f *Frontend) WindowPrint() { - f.ExecJS("window.print();") + winc.Exit() } func (f *Frontend) setupChromium() { - chromium := f.chromium - - disableFeatues := []string{} - if !f.frontendOptions.EnableFraudulentWebsiteDetection { - disableFeatues = append(disableFeatues, "msSmartScreenProtection") - } - - if opts := f.frontendOptions.Windows; opts != nil { - chromium.DataPath = opts.WebviewUserDataPath - chromium.BrowserPath = opts.WebviewBrowserPath - - if opts.WebviewGpuIsDisabled { - chromium.AdditionalBrowserArgs = append(chromium.AdditionalBrowserArgs, "--disable-gpu") - } - if opts.WebviewDisableRendererCodeIntegrity { - disableFeatues = append(disableFeatues, "RendererCodeIntegrity") - } - } - - if len(disableFeatues) > 0 { - arg := fmt.Sprintf("--disable-features=%s", strings.Join(disableFeatues, ",")) - chromium.AdditionalBrowserArgs = append(chromium.AdditionalBrowserArgs, arg) - } - - if f.frontendOptions.DragAndDrop != nil && f.frontendOptions.DragAndDrop.DisableWebViewDrop { - if err := chromium.AllowExternalDrag(false); err != nil { - f.logger.Warning("WebView failed to set AllowExternalDrag to false!") - } - } - + chromium := edge.NewChromium() + f.chromium = chromium chromium.MessageCallback = f.processMessage - chromium.MessageWithAdditionalObjectsCallback = f.processMessageWithAdditionalObjects chromium.WebResourceRequestedCallback = f.processRequest chromium.NavigationCompletedCallback = f.navigationCompleted chromium.AcceleratorKeyCallback = func(vkey uint) bool { - if vkey == w32.VK_F12 && f.devtoolsEnabled { - var keyState [256]byte - if w32.GetKeyboardState(keyState[:]) { - // Check if CTRL is pressed - if keyState[w32.VK_CONTROL]&0x80 != 0 && keyState[w32.VK_SHIFT]&0x80 != 0 { - chromium.OpenDevToolsWindow() - return true - } - } else { - f.logger.Error("Call to GetKeyboardState failed") - } - } w32.PostMessage(f.mainWindow.Handle(), w32.WM_KEYDOWN, uintptr(vkey), 0) return false } - chromium.ProcessFailedCallback = func(sender *edge.ICoreWebView2, args *edge.ICoreWebView2ProcessFailedEventArgs) { - kind, err := args.GetProcessFailedKind() - if err != nil { - f.logger.Error("GetProcessFailedKind: %s", err) - return - } - - f.logger.Error("WebVie2wProcess failed with kind %d", kind) - switch kind { - case edge.COREWEBVIEW2_PROCESS_FAILED_KIND_BROWSER_PROCESS_EXITED: - // => The app has to recreate a new WebView to recover from this failure. - messages := windows.DefaultMessages() - if f.frontendOptions.Windows != nil && f.frontendOptions.Windows.Messages != nil { - messages = f.frontendOptions.Windows.Messages - } - winc.Errorf(f.mainWindow, messages.WebView2ProcessCrash) - os.Exit(-1) - case edge.COREWEBVIEW2_PROCESS_FAILED_KIND_RENDER_PROCESS_EXITED, - edge.COREWEBVIEW2_PROCESS_FAILED_KIND_FRAME_RENDER_PROCESS_EXITED: - // => A new render process is created automatically and navigated to an error page. - // => Make sure that the error page is shown. - if !f.hasStarted { - // NavgiationCompleted didn't come in, make sure the chromium is shown - chromium.Show() - } - if !f.mainWindow.hasBeenShown { - // The window has never been shown, make sure to show it - f.ShowWindow() - } - } - } - chromium.Embed(f.mainWindow.Handle()) - - if chromium.HasCapability(edge.SwipeNavigation) { - swipeGesturesEnabled := f.frontendOptions.Windows != nil && f.frontendOptions.Windows.EnableSwipeGestures - err := chromium.PutIsSwipeNavigationEnabled(swipeGesturesEnabled) - if err != nil { - log.Fatal(err) - } - } chromium.Resize() settings, err := chromium.GetSettings() if err != nil { log.Fatal(err) } - err = settings.PutAreDefaultContextMenusEnabled(f.debug || f.frontendOptions.EnableDefaultContextMenu) + err = settings.PutAreDefaultContextMenusEnabled(f.debug) if err != nil { log.Fatal(err) } - err = settings.PutAreDevToolsEnabled(f.devtoolsEnabled) + err = settings.PutAreDevToolsEnabled(f.debug) if err != nil { log.Fatal(err) } - - if opts := f.frontendOptions.Windows; opts != nil { - if opts.ZoomFactor > 0.0 { - chromium.PutZoomFactor(opts.ZoomFactor) - } - err = settings.PutIsZoomControlEnabled(opts.IsZoomControlEnabled) - if err != nil { - log.Fatal(err) - } - err = settings.PutIsPinchZoomEnabled(!opts.DisablePinchZoom) - if err != nil { - log.Fatal(err) - } + err = settings.PutIsZoomControlEnabled(false) + if err != nil { + log.Fatal(err) } - err = settings.PutIsStatusBarEnabled(false) if err != nil { log.Fatal(err) @@ -591,21 +294,17 @@ func (f *Frontend) setupChromium() { if err != nil { log.Fatal(err) } - - if f.debug && f.frontendOptions.Debug.OpenInspectorOnStartup { - chromium.OpenDevToolsWindow() + err = settings.PutIsSwipeNavigationEnabled(false) + if err != nil { + log.Fatal(err) } - // Setup focus event handler - onFocus := f.mainWindow.OnSetFocus() - onFocus.Bind(f.onFocus) - // Set background colour - f.WindowSetBackgroundColour(f.frontendOptions.BackgroundColour) + f.WindowSetRGBA(f.frontendOptions.RGBA) chromium.SetGlobalPermission(edge.CoreWebView2PermissionStateAllow) chromium.AddWebResourceRequestedFilter("*", edge.COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL) - chromium.Navigate(f.startURL.String()) + chromium.Navigate(f.startURL) } type EventNotify struct { @@ -627,92 +326,39 @@ func (f *Frontend) Notify(name string, data ...interface{}) { } func (f *Frontend) processRequest(req *edge.ICoreWebView2WebResourceRequest, args *edge.ICoreWebView2WebResourceRequestedEventArgs) { - // Setting the UserAgent on the CoreWebView2Settings clears the whole default UserAgent of the Edge browser, but - // we want to just append our ApplicationIdentifier. So we adjust the UserAgent for every request. - if reqHeaders, err := req.GetHeaders(); err == nil { - useragent, _ := reqHeaders.GetHeader(assetserver.HeaderUserAgent) - useragent = strings.Join([]string{useragent, assetserver.WailsUserAgentValue}, " ") - reqHeaders.SetHeader(assetserver.HeaderUserAgent, useragent) - reqHeaders.Release() - } - - if f.assets == nil { - // We are using the devServer let the WebView2 handle the request with its default handler - return - } - //Get the request uri, _ := req.GetUri() - reqUri, err := url.ParseRequestURI(uri) + + // Translate URI + uri = strings.TrimPrefix(uri, "file://wails") + if !strings.HasPrefix(uri, "/") { + return + } + + // Load file from asset store + content, mimeType, err := f.assets.Load(uri) if err != nil { - f.logger.Error("Unable to parse equest uri %s: %s", uri, err) return } - if reqUri.Scheme != f.startURL.Scheme { - // Let the WebView2 handle the request with its default handler - return - } else if reqUri.Host != f.startURL.Host { - // Let the WebView2 handle the request with its default handler - return + env := f.chromium.Environment() + headers := "Content-Type: " + mimeType + if f.servingFromDisk { + headers += "\nPragma: no-cache" } - - webviewRequest, err := webview.NewRequest( - f.chromium.Environment(), - args, - func(fn func()) { - runtime.LockOSThread() - defer runtime.UnlockOSThread() - if f.mainWindow.InvokeRequired() { - var wg sync.WaitGroup - wg.Add(1) - f.mainWindow.Invoke(func() { - fn() - wg.Done() - }) - wg.Wait() - } else { - fn() - } - }) - + response, err := env.CreateWebResourceResponse(content, 200, "OK", headers) if err != nil { - f.logger.Error("%s: NewRequest failed: %s", uri, err) return } - - f.assets.ServeWebViewRequest(webviewRequest) + // Send response back + err = args.PutResponse(response) + if err != nil { + return + } + return } -var edgeMap = map[string]uintptr{ - "n-resize": w32.HTTOP, - "ne-resize": w32.HTTOPRIGHT, - "e-resize": w32.HTRIGHT, - "se-resize": w32.HTBOTTOMRIGHT, - "s-resize": w32.HTBOTTOM, - "sw-resize": w32.HTBOTTOMLEFT, - "w-resize": w32.HTLEFT, - "nw-resize": w32.HTTOPLEFT, -} - -func (f *Frontend) processMessage(message string, sender *edge.ICoreWebView2, args *edge.ICoreWebView2WebMessageReceivedEventArgs) { - topSource, err := sender.GetSource() - if err != nil { - f.logger.Error(fmt.Sprintf("Unable to get source from sender: %s", err.Error())) - return - } - - senderSource, err := args.GetSource() - if err != nil { - f.logger.Error(fmt.Sprintf("Unable to get source from args: %s", err.Error())) - return - } - - // verify both topSource and sender are allowed origins - if !f.validBindingOrigin(topSource) || !f.validBindingOrigin(senderSource) { - return - } - +func (f *Frontend) processMessage(message string) { if message == "drag" { if !f.mainWindow.IsFullScreen() { err := f.startDrag() @@ -722,131 +368,6 @@ func (f *Frontend) processMessage(message string, sender *edge.ICoreWebView2, ar } return } - - if message == "runtime:ready" { - cmd := fmt.Sprintf( - "window.wails.setCSSDragProperties('%s', '%s');\n"+ - "window.wails.setCSSDropProperties('%s', '%s');", - f.frontendOptions.CSSDragProperty, - f.frontendOptions.CSSDragValue, - f.frontendOptions.DragAndDrop.CSSDropProperty, - f.frontendOptions.DragAndDrop.CSSDropValue, - ) - - f.ExecJS(cmd) - return - } - - if strings.HasPrefix(message, "resize:") { - if !f.mainWindow.IsFullScreen() { - sl := strings.Split(message, ":") - if len(sl) != 2 { - f.logger.Info("Unknown message returned from dispatcher: %+v", message) - return - } - edge := edgeMap[sl[1]] - err := f.startResize(edge) - if err != nil { - f.logger.Error(err.Error()) - } - } - return - } - - go f.dispatchMessage(message) -} - -func (f *Frontend) processMessageWithAdditionalObjects(message string, sender *edge.ICoreWebView2, args *edge.ICoreWebView2WebMessageReceivedEventArgs) { - topSource, err := sender.GetSource() - if err != nil { - f.logger.Error(fmt.Sprintf("Unable to get source from sender: %s", err.Error())) - return - } - - senderSource, err := args.GetSource() - if err != nil { - f.logger.Error(fmt.Sprintf("Unable to get source from args: %s", err.Error())) - return - } - - // verify both topSource and sender are allowed origins - if !f.validBindingOrigin(topSource) || !f.validBindingOrigin(senderSource) { - return - } - - if strings.HasPrefix(message, "file:drop") { - if !f.frontendOptions.DragAndDrop.EnableFileDrop { - return - } - objs, err := args.GetAdditionalObjects() - if err != nil { - f.logger.Error(err.Error()) - return - } - - defer objs.Release() - - count, err := objs.GetCount() - if err != nil { - f.logger.Error(err.Error()) - return - } - - files := make([]string, count) - for i := uint32(0); i < count; i++ { - _file, err := objs.GetValueAtIndex(i) - if err != nil { - f.logger.Error("cannot get value at %d : %s", i, err.Error()) - return - } - - if _file == nil { - f.logger.Warning("object at %d is not a file", i) - continue - } - - file := (*edge.ICoreWebView2File)(unsafe.Pointer(_file)) - defer file.Release() - - filepath, err := file.GetPath() - if err != nil { - f.logger.Error("cannot get path for object at %d : %s", i, err.Error()) - return - } - - files[i] = filepath - } - - var ( - x = "0" - y = "0" - ) - coords := strings.SplitN(message[10:], ":", 2) - if len(coords) == 2 { - x = coords[0] - y = coords[1] - } - - go f.dispatchMessage(fmt.Sprintf("DD:%s:%s:%s", x, y, strings.Join(files, "\n"))) - return - } -} - -func (f *Frontend) validBindingOrigin(source string) bool { - origin, err := f.originValidator.GetOriginFromURL(source) - if err != nil { - f.logger.Error(fmt.Sprintf("Error parsing source URL %s: %v", source, err.Error())) - return false - } - allowed := f.originValidator.IsOriginAllowed(origin) - if !allowed { - f.logger.Error("Blocked request from unauthorized origin: %s", origin) - return false - } - return true -} - -func (f *Frontend) dispatchMessage(message string) { result, err := f.dispatcher.ProcessMessage(message, f) if err != nil { f.logger.Error(err.Error()) @@ -867,12 +388,8 @@ func (f *Frontend) dispatchMessage(message string) { } func (f *Frontend) Callback(message string) { - escaped, err := json.Marshal(message) - if err != nil { - panic(err) - } - f.mainWindow.Invoke(func() { - f.chromium.Eval(`window.wails.Callback(` + string(escaped) + `);`) + f.mainWindow.Dispatch(func() { + f.chromium.Eval(`window.wails.Callback(` + strconv.Quote(message) + `);`) }) } @@ -880,22 +397,12 @@ func (f *Frontend) startDrag() error { if !w32.ReleaseCapture() { return fmt.Errorf("unable to release mouse capture") } - // Use PostMessage because we don't want to block the caller until dragging has been finished. - w32.PostMessage(f.mainWindow.Handle(), w32.WM_NCLBUTTONDOWN, w32.HTCAPTION, 0) - return nil -} - -func (f *Frontend) startResize(border uintptr) error { - if !w32.ReleaseCapture() { - return fmt.Errorf("unable to release mouse capture") - } - // Use PostMessage because we don't want to block the caller until resizing has been finished. - w32.PostMessage(f.mainWindow.Handle(), w32.WM_NCLBUTTONDOWN, border, 0) + w32.SendMessage(f.mainWindow.Handle(), w32.WM_NCLBUTTONDOWN, w32.HTCAPTION, 0) return nil } func (f *Frontend) ExecJS(js string) { - f.mainWindow.Invoke(func() { + f.mainWindow.Dispatch(func() { f.chromium.Eval(js) }) } @@ -905,18 +412,10 @@ func (f *Frontend) navigationCompleted(sender *edge.ICoreWebView2, args *edge.IC go f.frontendOptions.OnDomReady(f.ctx) } - if f.frontendOptions.Frameless && f.frontendOptions.DisableResize == false { - f.ExecJS("window.wails.flags.enableResize = true;") - } - - if f.frontendOptions.DragAndDrop != nil && f.frontendOptions.DragAndDrop.EnableFileDrop { - f.ExecJS("window.wails.flags.enableWailsDragAndDrop = true;") - } - - if f.hasStarted { + // If you want to start hidden, return + if f.frontendOptions.StartHidden { return } - f.hasStarted = true // Hack to make it visible: https://github.com/MicrosoftEdge/WebView2Feedback/issues/1077#issuecomment-825375026 err := f.chromium.Hide() @@ -927,78 +426,6 @@ func (f *Frontend) navigationCompleted(sender *edge.ICoreWebView2, args *edge.IC if err != nil { log.Fatal(err) } - - if f.frontendOptions.StartHidden { - return - } - - switch f.frontendOptions.WindowStartState { - case options.Maximised: - if !f.frontendOptions.DisableResize { - win32.ShowWindowMaximised(f.mainWindow.Handle()) - } else { - win32.ShowWindow(f.mainWindow.Handle()) - } - case options.Minimised: - win32.ShowWindowMinimised(f.mainWindow.Handle()) - case options.Fullscreen: - f.mainWindow.Fullscreen() - win32.ShowWindow(f.mainWindow.Handle()) - default: - if f.frontendOptions.Fullscreen { - f.mainWindow.Fullscreen() - } - win32.ShowWindow(f.mainWindow.Handle()) - } - - f.mainWindow.hasBeenShown = true + f.mainWindow.Show() } - -func (f *Frontend) ShowWindow() { - f.mainWindow.Invoke(func() { - if !f.mainWindow.hasBeenShown { - f.mainWindow.hasBeenShown = true - switch f.frontendOptions.WindowStartState { - case options.Maximised: - if !f.frontendOptions.DisableResize { - win32.ShowWindowMaximised(f.mainWindow.Handle()) - } else { - win32.ShowWindow(f.mainWindow.Handle()) - } - case options.Minimised: - win32.RestoreWindow(f.mainWindow.Handle()) - case options.Fullscreen: - f.mainWindow.Fullscreen() - win32.ShowWindow(f.mainWindow.Handle()) - default: - if f.frontendOptions.Fullscreen { - f.mainWindow.Fullscreen() - } - win32.ShowWindow(f.mainWindow.Handle()) - } - } else { - if win32.IsWindowMinimised(f.mainWindow.Handle()) { - win32.RestoreWindow(f.mainWindow.Handle()) - } else { - win32.ShowWindow(f.mainWindow.Handle()) - } - } - w32.SetForegroundWindow(f.mainWindow.Handle()) - w32.SetFocus(f.mainWindow.Handle()) - }) - -} - -func (f *Frontend) onFocus(arg *winc.Event) { - f.chromium.Focus() -} - -func (f *Frontend) startSecondInstanceProcessor() { - for secondInstanceData := range secondInstanceBuffer { - if f.frontendOptions.SingleInstanceLock != nil && - f.frontendOptions.SingleInstanceLock.OnSecondInstanceLaunch != nil { - f.frontendOptions.SingleInstanceLock.OnSecondInstanceLaunch(secondInstanceData) - } - } -} diff --git a/v2/internal/frontend/desktop/windows/keys.go b/v2/internal/frontend/desktop/windows/keys.go index 2fe5f7550..8c2c39bde 100644 --- a/v2/internal/frontend/desktop/windows/keys.go +++ b/v2/internal/frontend/desktop/windows/keys.go @@ -1,10 +1,9 @@ //go:build windows -// +build windows package windows import ( - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc" + "github.com/leaanthony/winc" "github.com/wailsapp/wails/v2/pkg/menu/keys" "strings" ) diff --git a/v2/internal/frontend/desktop/windows/menu.go b/v2/internal/frontend/desktop/windows/menu.go index b71128b45..82f5421ed 100644 --- a/v2/internal/frontend/desktop/windows/menu.go +++ b/v2/internal/frontend/desktop/windows/menu.go @@ -1,10 +1,9 @@ //go:build windows -// +build windows package windows import ( - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc" + "github.com/leaanthony/winc" "github.com/wailsapp/wails/v2/pkg/menu" ) @@ -48,10 +47,8 @@ func processMenu(window *Window, menu *menu.Menu) { mainMenu := window.NewMenu() for _, menuItem := range menu.Items { submenu := mainMenu.AddSubMenu(menuItem.Label) - if menuItem.SubMenu != nil { - for _, menuItem := range menuItem.SubMenu.Items { - processMenuItem(submenu, menuItem) - } + for _, menuItem := range menuItem.SubMenu.Items { + processMenuItem(submenu, menuItem) } } mainMenu.Show() diff --git a/v2/internal/frontend/desktop/windows/screen.go b/v2/internal/frontend/desktop/windows/screen.go deleted file mode 100644 index f6e12bcce..000000000 --- a/v2/internal/frontend/desktop/windows/screen.go +++ /dev/null @@ -1,129 +0,0 @@ -//go:build windows -// +build windows - -package windows - -import ( - "fmt" - "syscall" - "unsafe" - - "github.com/pkg/errors" - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc" - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -func MonitorsEqual(first w32.MONITORINFO, second w32.MONITORINFO) bool { - // Checks to make sure all the fields are the same. - // A cleaner way would be to check identity of devices. but I couldn't find a way of doing that using the win32 API - return first.DwFlags == second.DwFlags && - first.RcMonitor.Top == second.RcMonitor.Top && - first.RcMonitor.Bottom == second.RcMonitor.Bottom && - first.RcMonitor.Right == second.RcMonitor.Right && - first.RcMonitor.Left == second.RcMonitor.Left && - first.RcWork.Top == second.RcWork.Top && - first.RcWork.Bottom == second.RcWork.Bottom && - first.RcWork.Right == second.RcWork.Right && - first.RcWork.Left == second.RcWork.Left -} - -func GetMonitorInfo(hMonitor w32.HMONITOR) (*w32.MONITORINFO, error) { - // Adapted from winc.utils.getMonitorInfo TODO: add this to win32 - // See docs for - //https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getmonitorinfoa - - var info w32.MONITORINFO - info.CbSize = uint32(unsafe.Sizeof(info)) - succeeded := w32.GetMonitorInfo(hMonitor, &info) - if !succeeded { - return &info, errors.New("Windows call to getMonitorInfo failed") - } - return &info, nil -} - -func EnumProc(hMonitor w32.HMONITOR, hdcMonitor w32.HDC, lprcMonitor *w32.RECT, screenContainer *ScreenContainer) uintptr { - // adapted from https://stackoverflow.com/a/23492886/4188138 - - // see docs for the following pages to better understand this function - // https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enumdisplaymonitors - // https://docs.microsoft.com/en-us/windows/win32/api/winuser/nc-winuser-monitorenumproc - // https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-monitorinfo - // https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-monitorfromwindow - - ourMonitorData := Screen{} - currentMonHndl := w32.MonitorFromWindow(screenContainer.mainWinHandle, w32.MONITOR_DEFAULTTONEAREST) - currentMonInfo, currErr := GetMonitorInfo(currentMonHndl) - - if currErr != nil { - screenContainer.errors = append(screenContainer.errors, currErr) - screenContainer.monitors = append(screenContainer.monitors, Screen{}) - // not sure what the consequences of returning false are, so let's just return true and handle it ourselves - return w32.TRUE - } - - monInfo, err := GetMonitorInfo(hMonitor) - if err != nil { - screenContainer.errors = append(screenContainer.errors, err) - screenContainer.monitors = append(screenContainer.monitors, Screen{}) - return w32.TRUE - } - - width := lprcMonitor.Right - lprcMonitor.Left - height := lprcMonitor.Bottom - lprcMonitor.Top - ourMonitorData.IsPrimary = monInfo.DwFlags&w32.MONITORINFOF_PRIMARY == 1 - ourMonitorData.Height = int(height) - ourMonitorData.Width = int(width) - ourMonitorData.IsCurrent = MonitorsEqual(*currentMonInfo, *monInfo) - - ourMonitorData.PhysicalSize.Width = int(width) - ourMonitorData.PhysicalSize.Height = int(height) - - var dpiX, dpiY uint - w32.GetDPIForMonitor(hMonitor, w32.MDT_EFFECTIVE_DPI, &dpiX, &dpiY) - if dpiX == 0 || dpiY == 0 { - screenContainer.errors = append(screenContainer.errors, fmt.Errorf("unable to get DPI for screen")) - screenContainer.monitors = append(screenContainer.monitors, Screen{}) - return w32.TRUE - } - ourMonitorData.Size.Width = winc.ScaleToDefaultDPI(ourMonitorData.PhysicalSize.Width, dpiX) - ourMonitorData.Size.Height = winc.ScaleToDefaultDPI(ourMonitorData.PhysicalSize.Height, dpiY) - - // the reason we need a container is that we have don't know how many times this function will be called - // this "append" call could potentially do an allocation and rewrite the pointer to monitors. So we save the pointer in screenContainer.monitors - // and retrieve the values after all EnumProc calls - // If EnumProc is multi-threaded, this could be problematic. Although, I don't think it is. - screenContainer.monitors = append(screenContainer.monitors, ourMonitorData) - // let's keep screenContainer.errors the same size as screenContainer.monitors in case we want to match them up later if necessary - screenContainer.errors = append(screenContainer.errors, nil) - return w32.TRUE -} - -type ScreenContainer struct { - monitors []Screen - errors []error - mainWinHandle w32.HWND -} - -func GetAllScreens(mainWinHandle w32.HWND) ([]Screen, error) { - // TODO fix hack of container sharing by having a proper data sharing mechanism between windows and the runtime - monitorContainer := ScreenContainer{mainWinHandle: mainWinHandle} - returnErr := error(nil) - errorStrings := []string{} - - dc := w32.GetDC(0) - defer w32.ReleaseDC(0, dc) - succeeded := w32.EnumDisplayMonitors(dc, nil, syscall.NewCallback(EnumProc), unsafe.Pointer(&monitorContainer)) - if !succeeded { - return monitorContainer.monitors, errors.New("Windows call to EnumDisplayMonitors failed") - } - for idx, err := range monitorContainer.errors { - if err != nil { - errorStrings = append(errorStrings, fmt.Sprintf("Error from monitor #%v, %v", idx+1, err)) - } - } - - if len(errorStrings) > 0 { - returnErr = fmt.Errorf("%v errors encountered: %v", len(errorStrings), errorStrings) - } - return monitorContainer.monitors, returnErr -} diff --git a/v2/internal/frontend/desktop/windows/single_instance.go b/v2/internal/frontend/desktop/windows/single_instance.go deleted file mode 100644 index a02b7edb9..000000000 --- a/v2/internal/frontend/desktop/windows/single_instance.go +++ /dev/null @@ -1,136 +0,0 @@ -//go:build windows - -package windows - -import ( - "encoding/json" - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" - "github.com/wailsapp/wails/v2/pkg/options" - "golang.org/x/sys/windows" - "log" - "os" - "syscall" - "unsafe" -) - -type COPYDATASTRUCT struct { - dwData uintptr - cbData uint32 - lpData uintptr -} - -// WMCOPYDATA_SINGLE_INSTANCE_DATA we define our own type for WM_COPYDATA message -const WMCOPYDATA_SINGLE_INSTANCE_DATA = 1542 - -func SendMessage(hwnd w32.HWND, data string) { - arrUtf16, _ := syscall.UTF16FromString(data) - - pCopyData := new(COPYDATASTRUCT) - pCopyData.dwData = WMCOPYDATA_SINGLE_INSTANCE_DATA - pCopyData.cbData = uint32(len(arrUtf16)*2 + 1) - pCopyData.lpData = uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(data))) - - w32.SendMessage(hwnd, w32.WM_COPYDATA, 0, uintptr(unsafe.Pointer(pCopyData))) -} - -// SetupSingleInstance single instance Windows app -func SetupSingleInstance(uniqueId string) { - id := "wails-app-" + uniqueId - - className := id + "-sic" - windowName := id + "-siw" - mutexName := id + "sim" - - _, err := windows.CreateMutex(nil, false, windows.StringToUTF16Ptr(mutexName)) - - if err != nil { - if err == windows.ERROR_ALREADY_EXISTS { - // app is already running - hwnd := w32.FindWindowW(windows.StringToUTF16Ptr(className), windows.StringToUTF16Ptr(windowName)) - - if hwnd != 0 { - data := options.SecondInstanceData{ - Args: os.Args[1:], - } - data.WorkingDirectory, err = os.Getwd() - if err != nil { - log.Printf("Failed to get working directory: %v", err) - return - } - serialized, err := json.Marshal(data) - if err != nil { - log.Printf("Failed to marshal data: %v", err) - return - } - - SendMessage(hwnd, string(serialized)) - // exit second instance of app after sending message - os.Exit(0) - } - // if we got any other unknown error we will just start new application instance - } - } else { - createEventTargetWindow(className, windowName) - } -} - -func createEventTargetWindow(className string, windowName string) w32.HWND { - // callback handler in the event target window - wndProc := func( - hwnd w32.HWND, msg uint32, wparam w32.WPARAM, lparam w32.LPARAM, - ) w32.LRESULT { - if msg == w32.WM_COPYDATA { - ldata := (*COPYDATASTRUCT)(unsafe.Pointer(lparam)) - - if ldata.dwData == WMCOPYDATA_SINGLE_INSTANCE_DATA { - serialized := windows.UTF16PtrToString((*uint16)(unsafe.Pointer(ldata.lpData))) - - var secondInstanceData options.SecondInstanceData - - err := json.Unmarshal([]byte(serialized), &secondInstanceData) - - if err == nil { - secondInstanceBuffer <- secondInstanceData - } - } - - return w32.LRESULT(0) - } - - return w32.DefWindowProc(hwnd, msg, wparam, lparam) - } - - var class w32.WNDCLASSEX - class.Size = uint32(unsafe.Sizeof(class)) - class.Style = 0 - class.WndProc = syscall.NewCallback(wndProc) - class.ClsExtra = 0 - class.WndExtra = 0 - class.Instance = w32.GetModuleHandle("") - class.Icon = 0 - class.Cursor = 0 - class.Background = 0 - class.MenuName = nil - class.ClassName = windows.StringToUTF16Ptr(className) - class.IconSm = 0 - - w32.RegisterClassEx(&class) - - // create event window that will not be visible for user - hwnd := w32.CreateWindowEx( - 0, - windows.StringToUTF16Ptr(className), - windows.StringToUTF16Ptr(windowName), - 0, - 0, - 0, - 0, - 0, - w32.HWND_MESSAGE, - 0, - w32.GetModuleHandle(""), - nil, - ) - - return hwnd -} diff --git a/v2/internal/frontend/desktop/windows/theme.go b/v2/internal/frontend/desktop/windows/theme.go deleted file mode 100644 index ac975e3d0..000000000 --- a/v2/internal/frontend/desktop/windows/theme.go +++ /dev/null @@ -1,67 +0,0 @@ -//go:build windows - -package windows - -import ( - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/win32" - "github.com/wailsapp/wails/v2/pkg/options/windows" -) - -func (w *Window) UpdateTheme() { - - // Don't redraw theme if nothing has changed - if !w.themeChanged { - return - } - w.themeChanged = false - - if win32.IsCurrentlyHighContrastMode() { - return - } - - if !win32.SupportsThemes() { - return - } - - var isDarkMode bool - switch w.theme { - case windows.SystemDefault: - isDarkMode = win32.IsCurrentlyDarkMode() - case windows.Dark: - isDarkMode = true - case windows.Light: - isDarkMode = false - } - win32.SetTheme(w.Handle(), isDarkMode) - - // Custom theme processing - winOptions := w.frontendOptions.Windows - var customTheme *windows.ThemeSettings - if winOptions != nil { - customTheme = winOptions.CustomTheme - } - // Custom theme - if win32.SupportsCustomThemes() && customTheme != nil { - if w.isActive { - if isDarkMode { - win32.SetTitleBarColour(w.Handle(), customTheme.DarkModeTitleBar) - win32.SetTitleTextColour(w.Handle(), customTheme.DarkModeTitleText) - win32.SetBorderColour(w.Handle(), customTheme.DarkModeBorder) - } else { - win32.SetTitleBarColour(w.Handle(), customTheme.LightModeTitleBar) - win32.SetTitleTextColour(w.Handle(), customTheme.LightModeTitleText) - win32.SetBorderColour(w.Handle(), customTheme.LightModeBorder) - } - } else { - if isDarkMode { - win32.SetTitleBarColour(w.Handle(), customTheme.DarkModeTitleBarInactive) - win32.SetTitleTextColour(w.Handle(), customTheme.DarkModeTitleTextInactive) - win32.SetBorderColour(w.Handle(), customTheme.DarkModeBorderInactive) - } else { - win32.SetTitleBarColour(w.Handle(), customTheme.LightModeTitleBarInactive) - win32.SetTitleTextColour(w.Handle(), customTheme.LightModeTitleTextInactive) - win32.SetBorderColour(w.Handle(), customTheme.LightModeBorderInactive) - } - } - } -} diff --git a/v2/internal/frontend/desktop/windows/win32/clipboard.go b/v2/internal/frontend/desktop/windows/win32/clipboard.go deleted file mode 100644 index fa715f18c..000000000 --- a/v2/internal/frontend/desktop/windows/win32/clipboard.go +++ /dev/null @@ -1,143 +0,0 @@ -//go:build windows - -/* - * Based on code originally from https://github.com/atotto/clipboard. Copyright (c) 2013 Ato Araki. All rights reserved. - */ - -package win32 - -import ( - "runtime" - "syscall" - "time" - "unsafe" -) - -const ( - cfUnicodetext = 13 - gmemMoveable = 0x0002 -) - -// waitOpenClipboard opens the clipboard, waiting for up to a second to do so. -func waitOpenClipboard() error { - started := time.Now() - limit := started.Add(time.Second) - var r uintptr - var err error - for time.Now().Before(limit) { - r, _, err = procOpenClipboard.Call(0) - if r != 0 { - return nil - } - time.Sleep(time.Millisecond) - } - return err -} - -func GetClipboardText() (string, error) { - // LockOSThread ensure that the whole method will keep executing on the same thread from begin to end (it actually locks the goroutine thread attribution). - // Otherwise if the goroutine switch thread during execution (which is a common practice), the OpenClipboard and CloseClipboard will happen on two different threads, and it will result in a clipboard deadlock. - runtime.LockOSThread() - defer runtime.UnlockOSThread() - if formatAvailable, _, err := procIsClipboardFormatAvailable.Call(cfUnicodetext); formatAvailable == 0 { - return "", err - } - err := waitOpenClipboard() - if err != nil { - return "", err - } - - h, _, err := procGetClipboardData.Call(cfUnicodetext) - if h == 0 { - _, _, _ = procCloseClipboard.Call() - return "", err - } - - l, _, err := kernelGlobalLock.Call(h) - if l == 0 { - _, _, _ = procCloseClipboard.Call() - return "", err - } - - text := syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(l))[:]) - - r, _, err := kernelGlobalUnlock.Call(h) - if r == 0 { - _, _, _ = procCloseClipboard.Call() - return "", err - } - - closed, _, err := procCloseClipboard.Call() - if closed == 0 { - return "", err - } - return text, nil -} - -func SetClipboardText(text string) error { - // LockOSThread ensure that the whole method will keep executing on the same thread from begin to end (it actually locks the goroutine thread attribution). - // Otherwise if the goroutine switch thread during execution (which is a common practice), the OpenClipboard and CloseClipboard will happen on two different threads, and it will result in a clipboard deadlock. - runtime.LockOSThread() - defer runtime.UnlockOSThread() - - err := waitOpenClipboard() - if err != nil { - return err - } - - r, _, err := procEmptyClipboard.Call(0) - if r == 0 { - _, _, _ = procCloseClipboard.Call() - return err - } - - data, err := syscall.UTF16FromString(text) - if err != nil { - return err - } - - // "If the hMem parameter identifies a memory object, the object must have - // been allocated using the function with the GMEM_MOVEABLE flag." - h, _, err := kernelGlobalAlloc.Call(gmemMoveable, uintptr(len(data)*int(unsafe.Sizeof(data[0])))) - if h == 0 { - _, _, _ = procCloseClipboard.Call() - return err - } - defer func() { - if h != 0 { - kernelGlobalFree.Call(h) - } - }() - - l, _, err := kernelGlobalLock.Call(h) - if l == 0 { - _, _, _ = procCloseClipboard.Call() - return err - } - - r, _, err = kernelLstrcpy.Call(l, uintptr(unsafe.Pointer(&data[0]))) - if r == 0 { - _, _, _ = procCloseClipboard.Call() - return err - } - - r, _, err = kernelGlobalUnlock.Call(h) - if r == 0 { - if err.(syscall.Errno) != 0 { - _, _, _ = procCloseClipboard.Call() - return err - } - } - - r, _, err = procSetClipboardData.Call(cfUnicodetext, h) - if r == 0 { - _, _, _ = procCloseClipboard.Call() - return err - } - h = 0 // suppress deferred cleanup - closed, _, err := procCloseClipboard.Call() - if closed == 0 { - return err - } - return nil -} diff --git a/v2/internal/frontend/desktop/windows/win32/consts.go b/v2/internal/frontend/desktop/windows/win32/consts.go deleted file mode 100644 index e38ea4b92..000000000 --- a/v2/internal/frontend/desktop/windows/win32/consts.go +++ /dev/null @@ -1,57 +0,0 @@ -//go:build windows - -package win32 - -import ( - "syscall" - - "github.com/wailsapp/wails/v2/internal/system/operatingsystem" -) - -type HRESULT int32 -type HANDLE uintptr -type HMONITOR HANDLE - -var ( - moduser32 = syscall.NewLazyDLL("user32.dll") - procSystemParametersInfo = moduser32.NewProc("SystemParametersInfoW") - procGetWindowLong = moduser32.NewProc("GetWindowLongW") - procSetClassLong = moduser32.NewProc("SetClassLongW") - procSetClassLongPtr = moduser32.NewProc("SetClassLongPtrW") - procShowWindow = moduser32.NewProc("ShowWindow") - procIsWindowVisible = moduser32.NewProc("IsWindowVisible") - procGetWindowRect = moduser32.NewProc("GetWindowRect") - procGetMonitorInfo = moduser32.NewProc("GetMonitorInfoW") - procMonitorFromWindow = moduser32.NewProc("MonitorFromWindow") - procIsClipboardFormatAvailable = moduser32.NewProc("IsClipboardFormatAvailable") - procOpenClipboard = moduser32.NewProc("OpenClipboard") - procCloseClipboard = moduser32.NewProc("CloseClipboard") - procEmptyClipboard = moduser32.NewProc("EmptyClipboard") - procGetClipboardData = moduser32.NewProc("GetClipboardData") - procSetClipboardData = moduser32.NewProc("SetClipboardData") -) -var ( - moddwmapi = syscall.NewLazyDLL("dwmapi.dll") - procDwmSetWindowAttribute = moddwmapi.NewProc("DwmSetWindowAttribute") - procDwmExtendFrameIntoClientArea = moddwmapi.NewProc("DwmExtendFrameIntoClientArea") -) -var ( - modwingdi = syscall.NewLazyDLL("gdi32.dll") - procCreateSolidBrush = modwingdi.NewProc("CreateSolidBrush") -) -var ( - kernel32 = syscall.NewLazyDLL("kernel32") - kernelGlobalAlloc = kernel32.NewProc("GlobalAlloc") - kernelGlobalFree = kernel32.NewProc("GlobalFree") - kernelGlobalLock = kernel32.NewProc("GlobalLock") - kernelGlobalUnlock = kernel32.NewProc("GlobalUnlock") - kernelLstrcpy = kernel32.NewProc("lstrcpyW") -) - -var windowsVersion, _ = operatingsystem.GetWindowsVersionInfo() - -func IsWindowsVersionAtLeast(major, minor, buildNumber int) bool { - return windowsVersion.Major >= major && - windowsVersion.Minor >= minor && - windowsVersion.Build >= buildNumber -} diff --git a/v2/internal/frontend/desktop/windows/win32/theme.go b/v2/internal/frontend/desktop/windows/win32/theme.go deleted file mode 100644 index 299a4f63a..000000000 --- a/v2/internal/frontend/desktop/windows/win32/theme.go +++ /dev/null @@ -1,119 +0,0 @@ -//go:build windows - -package win32 - -import ( - "unsafe" - - "golang.org/x/sys/windows/registry" -) - -type DWMWINDOWATTRIBUTE int32 - -const DwmwaUseImmersiveDarkModeBefore20h1 DWMWINDOWATTRIBUTE = 19 -const DwmwaUseImmersiveDarkMode DWMWINDOWATTRIBUTE = 20 -const DwmwaBorderColor DWMWINDOWATTRIBUTE = 34 -const DwmwaCaptionColor DWMWINDOWATTRIBUTE = 35 -const DwmwaTextColor DWMWINDOWATTRIBUTE = 36 -const DwmwaSystemBackdropType DWMWINDOWATTRIBUTE = 38 - -const SPI_GETHIGHCONTRAST = 0x0042 -const HCF_HIGHCONTRASTON = 0x00000001 - -// BackdropType defines the type of translucency we wish to use -type BackdropType int32 - -func dwmSetWindowAttribute(hwnd uintptr, dwAttribute DWMWINDOWATTRIBUTE, pvAttribute unsafe.Pointer, cbAttribute uintptr) { - ret, _, err := procDwmSetWindowAttribute.Call( - hwnd, - uintptr(dwAttribute), - uintptr(pvAttribute), - cbAttribute) - if ret != 0 { - _ = err - // println(err.Error()) - } -} - -func SupportsThemes() bool { - // We can't support Windows versions before 17763 - return IsWindowsVersionAtLeast(10, 0, 17763) -} - -func SupportsCustomThemes() bool { - return IsWindowsVersionAtLeast(10, 0, 17763) -} - -func SupportsBackdropTypes() bool { - return IsWindowsVersionAtLeast(10, 0, 22621) -} - -func SupportsImmersiveDarkMode() bool { - return IsWindowsVersionAtLeast(10, 0, 18985) -} - -func SetTheme(hwnd uintptr, useDarkMode bool) { - if SupportsThemes() { - attr := DwmwaUseImmersiveDarkModeBefore20h1 - if SupportsImmersiveDarkMode() { - attr = DwmwaUseImmersiveDarkMode - } - var winDark int32 - if useDarkMode { - winDark = 1 - } - dwmSetWindowAttribute(hwnd, attr, unsafe.Pointer(&winDark), unsafe.Sizeof(winDark)) - } -} - -func EnableTranslucency(hwnd uintptr, backdrop BackdropType) { - if SupportsBackdropTypes() { - dwmSetWindowAttribute(hwnd, DwmwaSystemBackdropType, unsafe.Pointer(&backdrop), unsafe.Sizeof(backdrop)) - } else { - println("Warning: Translucency type unavailable on Windows < 22621") - } -} - -func SetTitleBarColour(hwnd uintptr, titleBarColour int32) { - dwmSetWindowAttribute(hwnd, DwmwaCaptionColor, unsafe.Pointer(&titleBarColour), unsafe.Sizeof(titleBarColour)) -} - -func SetTitleTextColour(hwnd uintptr, titleTextColour int32) { - dwmSetWindowAttribute(hwnd, DwmwaTextColor, unsafe.Pointer(&titleTextColour), unsafe.Sizeof(titleTextColour)) -} - -func SetBorderColour(hwnd uintptr, titleBorderColour int32) { - dwmSetWindowAttribute(hwnd, DwmwaBorderColor, unsafe.Pointer(&titleBorderColour), unsafe.Sizeof(titleBorderColour)) -} - -func IsCurrentlyDarkMode() bool { - key, err := registry.OpenKey(registry.CURRENT_USER, `SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize`, registry.QUERY_VALUE) - if err != nil { - return false - } - defer key.Close() - - AppsUseLightTheme, _, err := key.GetIntegerValue("AppsUseLightTheme") - if err != nil { - return false - } - return AppsUseLightTheme == 0 -} - -type highContrast struct { - CbSize uint32 - DwFlags uint32 - LpszDefaultScheme *int16 -} - -func IsCurrentlyHighContrastMode() bool { - var result highContrast - result.CbSize = uint32(unsafe.Sizeof(result)) - res, _, err := procSystemParametersInfo.Call(SPI_GETHIGHCONTRAST, uintptr(result.CbSize), uintptr(unsafe.Pointer(&result)), 0) - if res == 0 { - _ = err - return false - } - r := result.DwFlags&HCF_HIGHCONTRASTON == HCF_HIGHCONTRASTON - return r -} diff --git a/v2/internal/frontend/desktop/windows/win32/window.go b/v2/internal/frontend/desktop/windows/win32/window.go deleted file mode 100644 index 6028789de..000000000 --- a/v2/internal/frontend/desktop/windows/win32/window.go +++ /dev/null @@ -1,223 +0,0 @@ -//go:build windows - -package win32 - -import ( - "fmt" - "log" - "strconv" - "syscall" - "unsafe" - - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc" -) - -const ( - WS_MAXIMIZE = 0x01000000 - WS_MINIMIZE = 0x20000000 - - GWL_STYLE = -16 - - MONITOR_DEFAULTTOPRIMARY = 0x00000001 -) - -const ( - SW_HIDE = 0 - SW_NORMAL = 1 - SW_SHOWNORMAL = 1 - SW_SHOWMINIMIZED = 2 - SW_MAXIMIZE = 3 - SW_SHOWMAXIMIZED = 3 - SW_SHOWNOACTIVATE = 4 - SW_SHOW = 5 - SW_MINIMIZE = 6 - SW_SHOWMINNOACTIVE = 7 - SW_SHOWNA = 8 - SW_RESTORE = 9 - SW_SHOWDEFAULT = 10 - SW_FORCEMINIMIZE = 11 -) - -const ( - GCLP_HBRBACKGROUND int32 = -10 -) - -// Power -const ( - // WM_POWERBROADCAST - Notifies applications that a power-management event has occurred. - WM_POWERBROADCAST = 536 - - // PBT_APMPOWERSTATUSCHANGE - Power status has changed. - PBT_APMPOWERSTATUSCHANGE = 10 - - // PBT_APMRESUMEAUTOMATIC -Operation is resuming automatically from a low-power state. This message is sent every time the system resumes. - PBT_APMRESUMEAUTOMATIC = 18 - - // PBT_APMRESUMESUSPEND - Operation is resuming from a low-power state. This message is sent after PBT_APMRESUMEAUTOMATIC if the resume is triggered by user input, such as pressing a key. - PBT_APMRESUMESUSPEND = 7 - - // PBT_APMSUSPEND - System is suspending operation. - PBT_APMSUSPEND = 4 - - // PBT_POWERSETTINGCHANGE - A power setting change event has been received. - PBT_POWERSETTINGCHANGE = 32787 -) - -// http://msdn.microsoft.com/en-us/library/windows/desktop/bb773244.aspx -type MARGINS struct { - CxLeftWidth, CxRightWidth, CyTopHeight, CyBottomHeight int32 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162897.aspx -type RECT struct { - Left, Top, Right, Bottom int32 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145065.aspx -type MONITORINFO struct { - CbSize uint32 - RcMonitor RECT - RcWork RECT - DwFlags uint32 -} - -func ExtendFrameIntoClientArea(hwnd uintptr, extend bool) { - // -1: Adds the default frame styling (aero shadow and e.g. rounded corners on Windows 11) - // Also shows the caption buttons if transparent ant translucent but they don't work. - // 0: Adds the default frame styling but no aero shadow, does not show the caption buttons. - // 1: Adds the default frame styling (aero shadow and e.g. rounded corners on Windows 11) but no caption buttons - // are shown if transparent ant translucent. - var margins MARGINS - if extend { - margins = MARGINS{1, 1, 1, 1} // Only extend 1 pixel to have the default frame styling but no caption buttons - } - if err := dwmExtendFrameIntoClientArea(hwnd, &margins); err != nil { - log.Fatal(fmt.Errorf("DwmExtendFrameIntoClientArea failed: %s", err)) - } -} - -func IsVisible(hwnd uintptr) bool { - ret, _, _ := procIsWindowVisible.Call(hwnd) - return ret != 0 -} - -func IsWindowFullScreen(hwnd uintptr) bool { - wRect := GetWindowRect(hwnd) - m := MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY) - var mi MONITORINFO - mi.CbSize = uint32(unsafe.Sizeof(mi)) - if !GetMonitorInfo(m, &mi) { - return false - } - return wRect.Left == mi.RcMonitor.Left && - wRect.Top == mi.RcMonitor.Top && - wRect.Right == mi.RcMonitor.Right && - wRect.Bottom == mi.RcMonitor.Bottom -} - -func IsWindowMaximised(hwnd uintptr) bool { - style := uint32(getWindowLong(hwnd, GWL_STYLE)) - return style&WS_MAXIMIZE != 0 -} -func IsWindowMinimised(hwnd uintptr) bool { - style := uint32(getWindowLong(hwnd, GWL_STYLE)) - return style&WS_MINIMIZE != 0 -} - -func RestoreWindow(hwnd uintptr) { - showWindow(hwnd, SW_RESTORE) -} - -func ShowWindow(hwnd uintptr) { - showWindow(hwnd, SW_SHOW) -} - -func ShowWindowMaximised(hwnd uintptr) { - showWindow(hwnd, SW_MAXIMIZE) -} -func ShowWindowMinimised(hwnd uintptr) { - showWindow(hwnd, SW_MINIMIZE) -} - -func SetBackgroundColour(hwnd uintptr, r, g, b uint8) { - col := winc.RGB(r, g, b) - hbrush, _, _ := procCreateSolidBrush.Call(uintptr(col)) - setClassLongPtr(hwnd, GCLP_HBRBACKGROUND, hbrush) -} - -func IsWindowNormal(hwnd uintptr) bool { - return !IsWindowMaximised(hwnd) && !IsWindowMinimised(hwnd) && !IsWindowFullScreen(hwnd) -} - -func dwmExtendFrameIntoClientArea(hwnd uintptr, margins *MARGINS) error { - ret, _, _ := procDwmExtendFrameIntoClientArea.Call( - hwnd, - uintptr(unsafe.Pointer(margins))) - - if ret != 0 { - return syscall.GetLastError() - } - - return nil -} - -func setClassLongPtr(hwnd uintptr, param int32, val uintptr) bool { - proc := procSetClassLongPtr - if strconv.IntSize == 32 { - /* - https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setclasslongptrw - Note: To write code that is compatible with both 32-bit and 64-bit Windows, use SetClassLongPtr. - When compiling for 32-bit Windows, SetClassLongPtr is defined as a call to the SetClassLong function - - => We have to do this dynamically when directly calling the DLL procedures - */ - proc = procSetClassLong - } - - ret, _, _ := proc.Call( - hwnd, - uintptr(param), - val, - ) - return ret != 0 -} - -func getWindowLong(hwnd uintptr, index int) int32 { - ret, _, _ := procGetWindowLong.Call( - hwnd, - uintptr(index)) - - return int32(ret) -} - -func showWindow(hwnd uintptr, cmdshow int) bool { - ret, _, _ := procShowWindow.Call( - hwnd, - uintptr(cmdshow)) - return ret != 0 -} - -func GetWindowRect(hwnd uintptr) *RECT { - var rect RECT - procGetWindowRect.Call( - hwnd, - uintptr(unsafe.Pointer(&rect))) - - return &rect -} - -func MonitorFromWindow(hwnd uintptr, dwFlags uint32) HMONITOR { - ret, _, _ := procMonitorFromWindow.Call( - hwnd, - uintptr(dwFlags), - ) - return HMONITOR(ret) -} - -func GetMonitorInfo(hMonitor HMONITOR, lmpi *MONITORINFO) bool { - ret, _, _ := procGetMonitorInfo.Call( - uintptr(hMonitor), - uintptr(unsafe.Pointer(lmpi)), - ) - return ret != 0 -} diff --git a/v2/internal/frontend/desktop/windows/winc/.gitignore b/v2/internal/frontend/desktop/windows/winc/.gitignore deleted file mode 100644 index f1c181ec9..000000000 --- a/v2/internal/frontend/desktop/windows/winc/.gitignore +++ /dev/null @@ -1,12 +0,0 @@ -# Binaries for programs and plugins -*.exe -*.exe~ -*.dll -*.so -*.dylib - -# Test binary, build with `go test -c` -*.test - -# Output of the go coverage tool, specifically when used with LiteIDE -*.out diff --git a/v2/internal/frontend/desktop/windows/winc/AUTHORS b/v2/internal/frontend/desktop/windows/winc/AUTHORS deleted file mode 100644 index 85674b8d9..000000000 --- a/v2/internal/frontend/desktop/windows/winc/AUTHORS +++ /dev/null @@ -1,12 +0,0 @@ -# This is the official list of 'Winc' authors for copyright purposes. - -# Names should be added to this file as -# Name or Organization -# The email address is not required for organizations. - -# Please keep the list sorted. - -# Contributors -# ============ - -Tad Vizbaras diff --git a/v2/internal/frontend/desktop/windows/winc/LICENSE b/v2/internal/frontend/desktop/windows/winc/LICENSE deleted file mode 100644 index a063a4370..000000000 --- a/v2/internal/frontend/desktop/windows/winc/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2019 winc Authors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/v2/internal/frontend/desktop/windows/winc/README.md b/v2/internal/frontend/desktop/windows/winc/README.md deleted file mode 100644 index 4d4d467bd..000000000 --- a/v2/internal/frontend/desktop/windows/winc/README.md +++ /dev/null @@ -1,181 +0,0 @@ -# winc - -** This is a fork of [tadvi/winc](https://github.com/tadvi/winc) for the sole purpose of integration -with [Wails](https://github.com/wailsapp/wails). This repository comes with ***no support*** ** - -Common library for Go GUI apps on Windows. It is for Windows OS only. This makes library smaller than some other UI -libraries for Go. - -Design goals: minimalism and simplicity. - -## Dependencies - -No other dependencies except Go standard library. - -## Building - -If you want to package icon files and other resources into binary **rsrc** tool is recommended: - - rsrc -manifest app.manifest -ico=app.ico,application_edit.ico,application_error.ico -o rsrc.syso - -Here app.manifest is XML file in format: - -``` - - - - - - - - - -``` - -Most Windows applications do not display command prompt. Build your Go project with flag to indicate that it is Windows -GUI binary: - - go build -ldflags="-H windowsgui" - -## Samples - -Best way to learn how to use the library is to look at the included **examples** projects. - -## Setup - -1. Make sure you have a working Go installation and build environment, see more for details on page below. - http://golang.org/doc/install - -2. go get github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc - -## Icons - -When rsrc is used to pack icons into binary it displays IDs of the packed icons. - -``` -rsrc -manifest app.manifest -ico=app.ico,lightning.ico,edit.ico,application_error.ico -o rsrc.syso -Manifest ID: 1 -Icon app.ico ID: 10 -Icon lightning.ico ID: 13 -Icon edit.ico ID: 16 -Icon application_error.ico ID: 19 -``` - -Use IDs to reference packed icons. - -``` -const myIcon = 13 - -btn.SetResIcon(myIcon) // Set icon on the button. -``` - -Included source **examples** use basic building via `release.bat` files. Note that icon IDs are order dependent. So if -you change they order in -ico flag then icon IDs will be different. If you want to keep order the same, just add new -icons to the end of -ico comma separated list. - -## Layout Manager - -SimpleDock is default layout manager. - -Current design of docking and split views allows building simple apps but if you need to have multiple split views in -few different directions you might need to create your own layout manager. - -Important point is to have **one** control inside SimpleDock set to dock as **Fill**. Controls that are not set to any -docking get placed using SetPos() function. So you can have Panel set to dock at the Top and then have another dock to -arrange controls inside that Panel or have controls placed using SetPos() at fixed positions. - -![Example layout with two toolbars and status bar](dock_topbottom.png) - -This is basic layout. Instead of toolbars and status bar you can have Panel or any other control that can resize. Panel -can have its own internal Dock that will arrange other controls inside of it. - -![Example layout with two toolbars and navigation on the left](dock_topleft.png) - -This is layout with extra control(s) on the left. Left side is usually treeview or listview. - -The rule is simple: you either dock controls using SimpleDock OR use SetPos() to set them at fixed positions. That's it. - -At some point **winc** may get more sophisticated layout manager. - -## Dialog Screens - -Dialog screens are not based on Windows resource files (.rc). They are just windows with controls placed at fixed -coordinates. This works fine for dialog screens up to 10-14 controls. - -# Minimal Demo - -``` -package main - -import ( - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc" -) - -func main() { - mainWindow := winc.NewForm(nil) - mainWindow.SetSize(400, 300) // (width, height) - mainWindow.SetText("Hello World Demo") - - edt := winc.NewEdit(mainWindow) - edt.SetPos(10, 20) - // Most Controls have default size unless SetSize is called. - edt.SetText("edit text") - - btn := winc.NewPushButton(mainWindow) - btn.SetText("Show or Hide") - btn.SetPos(40, 50) // (x, y) - btn.SetSize(100, 40) // (width, height) - btn.OnClick().Bind(func(e *winc.Event) { - if edt.Visible() { - edt.Hide() - } else { - edt.Show() - } - }) - - mainWindow.Center() - mainWindow.Show() - mainWindow.OnClose().Bind(wndOnClose) - - winc.RunMainLoop() // Must call to start event loop. -} - -func wndOnClose(arg *winc.Event) { - winc.Exit() -} -``` - -![Hello World](examples/hello.png) - -Result of running sample_minimal. - -## Create Your Own - -It is good practice to create your own controls based on existing structures and event model. Library contains some of -the controls built that way: IconButton (button.go), ErrorPanel (panel.go), MultiEdit (edit.go), etc. Please look at -existing controls as examples before building your own. - -When designing your own controls keep in mind that types have to be converted from Go into Win32 API and back. This is -usually due to string UTF8 and UTF16 conversions. But there are other types of conversions too. - -When developing your own controls you might also need to: - - import "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" - -w32 has Win32 API low level constants and functions. - -Look at **sample_control** for example of custom built window. - -## Companion Package - -[Go package for Windows Systray icon, menu and notifications](https://github.com/tadvi/systray) - -## Credits - -This library is built on - -[AllenDang/gform Windows GUI framework for Go](https://github.com/AllenDang/gform) - -**winc** takes most design decisions from **gform** and adds many more controls and code samples to it. - - diff --git a/v2/internal/frontend/desktop/windows/winc/app.go b/v2/internal/frontend/desktop/windows/winc/app.go deleted file mode 100644 index 973880444..000000000 --- a/v2/internal/frontend/desktop/windows/winc/app.go +++ /dev/null @@ -1,109 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2013 Allen Dang. All Rights Reserved. - */ -package winc - -import ( - "runtime" - "unsafe" - - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -var ( - // resource compilation tool assigns app.ico ID of 3 - // rsrc -manifest app.manifest -ico app.ico -o rsrc.syso - AppIconID = 3 -) - -func init() { - runtime.LockOSThread() - - gAppInstance = w32.GetModuleHandle("") - if gAppInstance == 0 { - panic("Error occurred in App.Init") - } - - // Initialize the common controls - var initCtrls w32.INITCOMMONCONTROLSEX - initCtrls.DwSize = uint32(unsafe.Sizeof(initCtrls)) - initCtrls.DwICC = - w32.ICC_LISTVIEW_CLASSES | w32.ICC_PROGRESS_CLASS | w32.ICC_TAB_CLASSES | - w32.ICC_TREEVIEW_CLASSES | w32.ICC_BAR_CLASSES - - w32.InitCommonControlsEx(&initCtrls) -} - -// SetAppIcon sets resource icon ID for the apps windows. -func SetAppIcon(appIconID int) { - AppIconID = appIconID -} - -func GetAppInstance() w32.HINSTANCE { - return gAppInstance -} - -func PreTranslateMessage(msg *w32.MSG) bool { - // This functions is called by the MessageLoop. It processes the - // keyboard accelerator keys and calls Controller.PreTranslateMessage for - // keyboard and mouse events. - - processed := false - - if (msg.Message >= w32.WM_KEYFIRST && msg.Message <= w32.WM_KEYLAST) || - (msg.Message >= w32.WM_MOUSEFIRST && msg.Message <= w32.WM_MOUSELAST) { - - if msg.Hwnd != 0 { - if controller := GetMsgHandler(msg.Hwnd); controller != nil { - // Search the chain of parents for pretranslated messages. - for p := controller; p != nil; p = p.Parent() { - - if processed = p.PreTranslateMessage(msg); processed { - break - } - } - } - } - } - - return processed -} - -// RunMainLoop processes messages in main application loop. -func RunMainLoop() int { - m := (*w32.MSG)(unsafe.Pointer(w32.GlobalAlloc(0, uint32(unsafe.Sizeof(w32.MSG{}))))) - defer w32.GlobalFree(w32.HGLOBAL(unsafe.Pointer(m))) - - for w32.GetMessage(m, 0, 0, 0) != 0 { - - if !PreTranslateMessage(m) { - w32.TranslateMessage(m) - w32.DispatchMessage(m) - } - } - - w32.GdiplusShutdown() - return int(m.WParam) -} - -// PostMessages processes recent messages. Sometimes helpful for instant window refresh. -func PostMessages() { - m := (*w32.MSG)(unsafe.Pointer(w32.GlobalAlloc(0, uint32(unsafe.Sizeof(w32.MSG{}))))) - defer w32.GlobalFree(w32.HGLOBAL(unsafe.Pointer(m))) - - for i := 0; i < 10; i++ { - if w32.GetMessage(m, 0, 0, 0) != 0 { - if !PreTranslateMessage(m) { - w32.TranslateMessage(m) - w32.DispatchMessage(m) - } - } - } -} - -func Exit() { - w32.PostQuitMessage(0) -} diff --git a/v2/internal/frontend/desktop/windows/winc/bitmap.go b/v2/internal/frontend/desktop/windows/winc/bitmap.go deleted file mode 100644 index c19c31c26..000000000 --- a/v2/internal/frontend/desktop/windows/winc/bitmap.go +++ /dev/null @@ -1,112 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2013 Allen Dang. All Rights Reserved. - */ - -package winc - -import ( - "errors" - "unsafe" - - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -type Bitmap struct { - handle w32.HBITMAP - width, height int -} - -func assembleBitmapFromHBITMAP(hbitmap w32.HBITMAP) (*Bitmap, error) { - var dib w32.DIBSECTION - if w32.GetObject(w32.HGDIOBJ(hbitmap), unsafe.Sizeof(dib), unsafe.Pointer(&dib)) == 0 { - return nil, errors.New("GetObject for HBITMAP failed") - } - - return &Bitmap{ - handle: hbitmap, - width: int(dib.DsBmih.BiWidth), - height: int(dib.DsBmih.BiHeight), - }, nil -} - -func NewBitmapFromFile(filepath string, background Color) (*Bitmap, error) { - var gpBitmap *uintptr - var err error - - gpBitmap, err = w32.GdipCreateBitmapFromFile(filepath) - if err != nil { - return nil, err - } - defer w32.GdipDisposeImage(gpBitmap) - - var hbitmap w32.HBITMAP - // Reverse RGB to BGR to satisfy gdiplus color schema. - hbitmap, err = w32.GdipCreateHBITMAPFromBitmap(gpBitmap, uint32(RGB(background.B(), background.G(), background.R()))) - if err != nil { - return nil, err - } - - return assembleBitmapFromHBITMAP(hbitmap) -} - -func NewBitmapFromResource(instance w32.HINSTANCE, resName *uint16, resType *uint16, background Color) (*Bitmap, error) { - var gpBitmap *uintptr - var err error - var hRes w32.HRSRC - - hRes, err = w32.FindResource(w32.HMODULE(instance), resName, resType) - if err != nil { - return nil, err - } - resSize := w32.SizeofResource(w32.HMODULE(instance), hRes) - pResData := w32.LockResource(w32.LoadResource(w32.HMODULE(instance), hRes)) - resBuffer := w32.GlobalAlloc(w32.GMEM_MOVEABLE, resSize) - pResBuffer := w32.GlobalLock(resBuffer) - w32.MoveMemory(pResBuffer, pResData, resSize) - - stream := w32.CreateStreamOnHGlobal(resBuffer, false) - - gpBitmap, err = w32.GdipCreateBitmapFromStream(stream) - if err != nil { - return nil, err - } - defer stream.Release() - defer w32.GlobalUnlock(resBuffer) - defer w32.GlobalFree(resBuffer) - defer w32.GdipDisposeImage(gpBitmap) - - var hbitmap w32.HBITMAP - // Reverse gform.RGB to BGR to satisfy gdiplus color schema. - hbitmap, err = w32.GdipCreateHBITMAPFromBitmap(gpBitmap, uint32(RGB(background.B(), background.G(), background.R()))) - if err != nil { - return nil, err - } - - return assembleBitmapFromHBITMAP(hbitmap) -} - -func (bm *Bitmap) Dispose() { - if bm.handle != 0 { - w32.DeleteObject(w32.HGDIOBJ(bm.handle)) - bm.handle = 0 - } -} - -func (bm *Bitmap) GetHBITMAP() w32.HBITMAP { - return bm.handle -} - -func (bm *Bitmap) Size() (int, int) { - return bm.width, bm.height -} - -func (bm *Bitmap) Height() int { - return bm.height -} - -func (bm *Bitmap) Width() int { - return bm.width -} diff --git a/v2/internal/frontend/desktop/windows/winc/brush.go b/v2/internal/frontend/desktop/windows/winc/brush.go deleted file mode 100644 index 1126dd1b9..000000000 --- a/v2/internal/frontend/desktop/windows/winc/brush.go +++ /dev/null @@ -1,74 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2013 Allen Dang. All Rights Reserved. - */ - -package winc - -import ( - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -var DefaultBackgroundBrush = NewSystemColorBrush(w32.COLOR_BTNFACE) - -type Brush struct { - hBrush w32.HBRUSH - logBrush w32.LOGBRUSH -} - -func NewSolidColorBrush(color Color) *Brush { - lb := w32.LOGBRUSH{LbStyle: w32.BS_SOLID, LbColor: w32.COLORREF(color)} - hBrush := w32.CreateBrushIndirect(&lb) - if hBrush == 0 { - panic("Faild to create solid color brush") - } - - return &Brush{hBrush, lb} -} - -func NewSystemColorBrush(colorIndex int) *Brush { - //lb := w32.LOGBRUSH{LbStyle: w32.BS_SOLID, LbColor: w32.COLORREF(colorIndex)} - lb := w32.LOGBRUSH{LbStyle: w32.BS_NULL} - hBrush := w32.GetSysColorBrush(colorIndex) - if hBrush == 0 { - panic("GetSysColorBrush failed") - } - return &Brush{hBrush, lb} -} - -func NewHatchedColorBrush(color Color) *Brush { - lb := w32.LOGBRUSH{LbStyle: w32.BS_HATCHED, LbColor: w32.COLORREF(color)} - hBrush := w32.CreateBrushIndirect(&lb) - if hBrush == 0 { - panic("Faild to create solid color brush") - } - - return &Brush{hBrush, lb} -} - -func NewNullBrush() *Brush { - lb := w32.LOGBRUSH{LbStyle: w32.BS_NULL} - hBrush := w32.CreateBrushIndirect(&lb) - if hBrush == 0 { - panic("Failed to create null brush") - } - - return &Brush{hBrush, lb} -} - -func (br *Brush) GetHBRUSH() w32.HBRUSH { - return br.hBrush -} - -func (br *Brush) GetLOGBRUSH() *w32.LOGBRUSH { - return &br.logBrush -} - -func (br *Brush) Dispose() { - if br.hBrush != 0 { - w32.DeleteObject(w32.HGDIOBJ(br.hBrush)) - br.hBrush = 0 - } -} diff --git a/v2/internal/frontend/desktop/windows/winc/buttons.go b/v2/internal/frontend/desktop/windows/winc/buttons.go deleted file mode 100644 index 3da801435..000000000 --- a/v2/internal/frontend/desktop/windows/winc/buttons.go +++ /dev/null @@ -1,156 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2013 Allen Dang. All Rights Reserved. - */ - -package winc - -import ( - "fmt" - - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -type Button struct { - ControlBase - onClick EventManager -} - -func (bt *Button) OnClick() *EventManager { - return &bt.onClick -} - -func (bt *Button) WndProc(msg uint32, wparam, lparam uintptr) uintptr { - switch msg { - case w32.WM_COMMAND: - bt.onClick.Fire(NewEvent(bt, nil)) - /*case w32.WM_LBUTTONDOWN: - w32.SetCapture(bt.Handle()) - case w32.WM_LBUTTONUP: - w32.ReleaseCapture()*/ - /*case win.WM_GETDLGCODE: - println("GETDLGCODE")*/ - } - return w32.DefWindowProc(bt.hwnd, msg, wparam, lparam) - //return bt.W32Control.WndProc(msg, wparam, lparam) -} - -func (bt *Button) Checked() bool { - result := w32.SendMessage(bt.hwnd, w32.BM_GETCHECK, 0, 0) - return result == w32.BST_CHECKED -} - -func (bt *Button) SetChecked(checked bool) { - wparam := w32.BST_CHECKED - if !checked { - wparam = w32.BST_UNCHECKED - } - w32.SendMessage(bt.hwnd, w32.BM_SETCHECK, uintptr(wparam), 0) -} - -// SetIcon sets icon on the button. Recommended icons are 32x32 with 32bit color depth. -func (bt *Button) SetIcon(ico *Icon) { - w32.SendMessage(bt.hwnd, w32.BM_SETIMAGE, w32.IMAGE_ICON, uintptr(ico.handle)) -} - -func (bt *Button) SetResIcon(iconID uint16) { - if ico, err := NewIconFromResource(GetAppInstance(), iconID); err == nil { - bt.SetIcon(ico) - return - } - panic(fmt.Sprintf("missing icon with icon ID: %d", iconID)) -} - -type PushButton struct { - Button -} - -func NewPushButton(parent Controller) *PushButton { - pb := new(PushButton) - - pb.InitControl("BUTTON", parent, 0, w32.BS_PUSHBUTTON|w32.WS_TABSTOP|w32.WS_VISIBLE|w32.WS_CHILD) - RegMsgHandler(pb) - - pb.SetFont(DefaultFont) - pb.SetText("Button") - pb.SetSize(100, 22) - - return pb -} - -// SetDefault is used for dialogs to set default button. -func (pb *PushButton) SetDefault() { - pb.SetAndClearStyleBits(w32.BS_DEFPUSHBUTTON, w32.BS_PUSHBUTTON) -} - -// IconButton does not display text, requires SetResIcon call. -type IconButton struct { - Button -} - -func NewIconButton(parent Controller) *IconButton { - pb := new(IconButton) - - pb.InitControl("BUTTON", parent, 0, w32.BS_ICON|w32.WS_TABSTOP|w32.WS_VISIBLE|w32.WS_CHILD) - RegMsgHandler(pb) - - pb.SetFont(DefaultFont) - // even if text would be set it would not be displayed - pb.SetText("") - pb.SetSize(100, 22) - - return pb -} - -type CheckBox struct { - Button -} - -func NewCheckBox(parent Controller) *CheckBox { - cb := new(CheckBox) - - cb.InitControl("BUTTON", parent, 0, w32.WS_TABSTOP|w32.WS_VISIBLE|w32.WS_CHILD|w32.BS_AUTOCHECKBOX) - RegMsgHandler(cb) - - cb.SetFont(DefaultFont) - cb.SetText("CheckBox") - cb.SetSize(100, 22) - - return cb -} - -type RadioButton struct { - Button -} - -func NewRadioButton(parent Controller) *RadioButton { - rb := new(RadioButton) - - rb.InitControl("BUTTON", parent, 0, w32.WS_TABSTOP|w32.WS_VISIBLE|w32.WS_CHILD|w32.BS_AUTORADIOBUTTON) - RegMsgHandler(rb) - - rb.SetFont(DefaultFont) - rb.SetText("RadioButton") - rb.SetSize(100, 22) - - return rb -} - -type GroupBox struct { - Button -} - -func NewGroupBox(parent Controller) *GroupBox { - gb := new(GroupBox) - - gb.InitControl("BUTTON", parent, 0, w32.WS_CHILD|w32.WS_VISIBLE|w32.WS_GROUP|w32.BS_GROUPBOX) - RegMsgHandler(gb) - - gb.SetFont(DefaultFont) - gb.SetText("GroupBox") - gb.SetSize(100, 100) - - return gb -} diff --git a/v2/internal/frontend/desktop/windows/winc/canvas.go b/v2/internal/frontend/desktop/windows/winc/canvas.go deleted file mode 100644 index 0ca4deeb4..000000000 --- a/v2/internal/frontend/desktop/windows/winc/canvas.go +++ /dev/null @@ -1,159 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2013 Allen Dang. All Rights Reserved. - */ - -package winc - -import ( - "fmt" - - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -type Canvas struct { - hwnd w32.HWND - hdc w32.HDC - doNotDispose bool -} - -var nullBrush = NewNullBrush() - -func NewCanvasFromHwnd(hwnd w32.HWND) *Canvas { - hdc := w32.GetDC(hwnd) - if hdc == 0 { - panic(fmt.Sprintf("Create canvas from %v failed.", hwnd)) - } - - return &Canvas{hwnd: hwnd, hdc: hdc, doNotDispose: false} -} - -func NewCanvasFromHDC(hdc w32.HDC) *Canvas { - if hdc == 0 { - panic("Cannot create canvas from invalid HDC.") - } - - return &Canvas{hdc: hdc, doNotDispose: true} -} - -func (ca *Canvas) Dispose() { - if !ca.doNotDispose && ca.hdc != 0 { - if ca.hwnd == 0 { - w32.DeleteDC(ca.hdc) - } else { - w32.ReleaseDC(ca.hwnd, ca.hdc) - } - - ca.hdc = 0 - } -} - -func (ca *Canvas) DrawBitmap(bmp *Bitmap, x, y int) { - cdc := w32.CreateCompatibleDC(0) - defer w32.DeleteDC(cdc) - - hbmpOld := w32.SelectObject(cdc, w32.HGDIOBJ(bmp.GetHBITMAP())) - defer w32.SelectObject(cdc, w32.HGDIOBJ(hbmpOld)) - - w, h := bmp.Size() - - w32.BitBlt(ca.hdc, x, y, w, h, cdc, 0, 0, w32.SRCCOPY) -} - -func (ca *Canvas) DrawStretchedBitmap(bmp *Bitmap, rect *Rect) { - cdc := w32.CreateCompatibleDC(0) - defer w32.DeleteDC(cdc) - - hbmpOld := w32.SelectObject(cdc, w32.HGDIOBJ(bmp.GetHBITMAP())) - defer w32.SelectObject(cdc, w32.HGDIOBJ(hbmpOld)) - - w, h := bmp.Size() - - rc := rect.GetW32Rect() - w32.StretchBlt(ca.hdc, int(rc.Left), int(rc.Top), int(rc.Right), int(rc.Bottom), cdc, 0, 0, w, h, w32.SRCCOPY) -} - -func (ca *Canvas) DrawIcon(ico *Icon, x, y int) bool { - return w32.DrawIcon(ca.hdc, x, y, ico.Handle()) -} - -// DrawFillRect draw and fill rectangle with color. -func (ca *Canvas) DrawFillRect(rect *Rect, pen *Pen, brush *Brush) { - w32Rect := rect.GetW32Rect() - - previousPen := w32.SelectObject(ca.hdc, w32.HGDIOBJ(pen.GetHPEN())) - defer w32.SelectObject(ca.hdc, previousPen) - - previousBrush := w32.SelectObject(ca.hdc, w32.HGDIOBJ(brush.GetHBRUSH())) - defer w32.SelectObject(ca.hdc, previousBrush) - - w32.Rectangle(ca.hdc, w32Rect.Left, w32Rect.Top, w32Rect.Right, w32Rect.Bottom) -} - -func (ca *Canvas) DrawRect(rect *Rect, pen *Pen) { - w32Rect := rect.GetW32Rect() - - previousPen := w32.SelectObject(ca.hdc, w32.HGDIOBJ(pen.GetHPEN())) - defer w32.SelectObject(ca.hdc, previousPen) - - // nullBrush is used to make interior of the rect transparent - previousBrush := w32.SelectObject(ca.hdc, w32.HGDIOBJ(nullBrush.GetHBRUSH())) - defer w32.SelectObject(ca.hdc, previousBrush) - - w32.Rectangle(ca.hdc, w32Rect.Left, w32Rect.Top, w32Rect.Right, w32Rect.Bottom) -} - -func (ca *Canvas) FillRect(rect *Rect, brush *Brush) { - w32.FillRect(ca.hdc, rect.GetW32Rect(), brush.GetHBRUSH()) -} - -func (ca *Canvas) DrawEllipse(rect *Rect, pen *Pen) { - w32Rect := rect.GetW32Rect() - - previousPen := w32.SelectObject(ca.hdc, w32.HGDIOBJ(pen.GetHPEN())) - defer w32.SelectObject(ca.hdc, previousPen) - - // nullBrush is used to make interior of the rect transparent - previousBrush := w32.SelectObject(ca.hdc, w32.HGDIOBJ(nullBrush.GetHBRUSH())) - defer w32.SelectObject(ca.hdc, previousBrush) - - w32.Ellipse(ca.hdc, w32Rect.Left, w32Rect.Top, w32Rect.Right, w32Rect.Bottom) -} - -// DrawFillEllipse draw and fill ellipse with color. -func (ca *Canvas) DrawFillEllipse(rect *Rect, pen *Pen, brush *Brush) { - w32Rect := rect.GetW32Rect() - - previousPen := w32.SelectObject(ca.hdc, w32.HGDIOBJ(pen.GetHPEN())) - defer w32.SelectObject(ca.hdc, previousPen) - - previousBrush := w32.SelectObject(ca.hdc, w32.HGDIOBJ(brush.GetHBRUSH())) - defer w32.SelectObject(ca.hdc, previousBrush) - - w32.Ellipse(ca.hdc, w32Rect.Left, w32Rect.Top, w32Rect.Right, w32Rect.Bottom) -} - -func (ca *Canvas) DrawLine(x, y, x2, y2 int, pen *Pen) { - w32.MoveToEx(ca.hdc, x, y, nil) - - previousPen := w32.SelectObject(ca.hdc, w32.HGDIOBJ(pen.GetHPEN())) - defer w32.SelectObject(ca.hdc, previousPen) - - w32.LineTo(ca.hdc, int32(x2), int32(y2)) -} - -// Refer win32 DrawText document for uFormat. -func (ca *Canvas) DrawText(text string, rect *Rect, format uint, font *Font, textColor Color) { - previousFont := w32.SelectObject(ca.hdc, w32.HGDIOBJ(font.GetHFONT())) - defer w32.SelectObject(ca.hdc, w32.HGDIOBJ(previousFont)) - - previousBkMode := w32.SetBkMode(ca.hdc, w32.TRANSPARENT) - defer w32.SetBkMode(ca.hdc, previousBkMode) - - previousTextColor := w32.SetTextColor(ca.hdc, w32.COLORREF(textColor)) - defer w32.SetTextColor(ca.hdc, previousTextColor) - - w32.DrawText(ca.hdc, text, len(text), rect.GetW32Rect(), format) -} diff --git a/v2/internal/frontend/desktop/windows/winc/color.go b/v2/internal/frontend/desktop/windows/winc/color.go deleted file mode 100644 index 72b71b865..000000000 --- a/v2/internal/frontend/desktop/windows/winc/color.go +++ /dev/null @@ -1,26 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2013 Allen Dang. All Rights Reserved. - */ - -package winc - -type Color uint32 - -func RGB(r, g, b byte) Color { - return Color(uint32(r) | uint32(g)<<8 | uint32(b)<<16) -} - -func (c Color) R() byte { - return byte(c & 0xff) -} - -func (c Color) G() byte { - return byte((c >> 8) & 0xff) -} - -func (c Color) B() byte { - return byte((c >> 16) & 0xff) -} diff --git a/v2/internal/frontend/desktop/windows/winc/combobox.go b/v2/internal/frontend/desktop/windows/winc/combobox.go deleted file mode 100644 index 380ea88d8..000000000 --- a/v2/internal/frontend/desktop/windows/winc/combobox.go +++ /dev/null @@ -1,70 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - */ - -package winc - -import ( - "syscall" - "unsafe" - - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -type ComboBox struct { - ControlBase - onSelectedChange EventManager -} - -func NewComboBox(parent Controller) *ComboBox { - cb := new(ComboBox) - - cb.InitControl("COMBOBOX", parent, 0, w32.WS_CHILD|w32.WS_VISIBLE|w32.WS_TABSTOP|w32.WS_VSCROLL|w32.CBS_DROPDOWNLIST) - RegMsgHandler(cb) - - cb.SetFont(DefaultFont) - cb.SetSize(200, 400) - return cb -} - -func (cb *ComboBox) DeleteAllItems() bool { - return w32.SendMessage(cb.hwnd, w32.CB_RESETCONTENT, 0, 0) == w32.TRUE -} - -func (cb *ComboBox) InsertItem(index int, str string) bool { - lp := uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(str))) - return w32.SendMessage(cb.hwnd, w32.CB_INSERTSTRING, uintptr(index), lp) != w32.CB_ERR -} - -func (cb *ComboBox) DeleteItem(index int) bool { - return w32.SendMessage(cb.hwnd, w32.CB_DELETESTRING, uintptr(index), 0) != w32.CB_ERR -} - -func (cb *ComboBox) SelectedItem() int { - return int(int32(w32.SendMessage(cb.hwnd, w32.CB_GETCURSEL, 0, 0))) -} - -func (cb *ComboBox) SetSelectedItem(value int) bool { - return int(int32(w32.SendMessage(cb.hwnd, w32.CB_SETCURSEL, uintptr(value), 0))) == value -} - -func (cb *ComboBox) OnSelectedChange() *EventManager { - return &cb.onSelectedChange -} - -// Message processor -func (cb *ComboBox) WndProc(msg uint32, wparam, lparam uintptr) uintptr { - switch msg { - case w32.WM_COMMAND: - code := w32.HIWORD(uint32(wparam)) - - switch code { - case w32.CBN_SELCHANGE: - cb.onSelectedChange.Fire(NewEvent(cb, nil)) - } - } - return w32.DefWindowProc(cb.hwnd, msg, wparam, lparam) - //return cb.W32Control.WndProc(msg, wparam, lparam) -} diff --git a/v2/internal/frontend/desktop/windows/winc/commondlgs.go b/v2/internal/frontend/desktop/windows/winc/commondlgs.go deleted file mode 100644 index 07ba47a8f..000000000 --- a/v2/internal/frontend/desktop/windows/winc/commondlgs.go +++ /dev/null @@ -1,125 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2013 Allen Dang. All Rights Reserved. - */ - -package winc - -import ( - "fmt" - "syscall" - "unsafe" - - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -func genOFN(parent Controller, title, filter string, filterIndex uint, initialDir string, buf []uint16) *w32.OPENFILENAME { - var ofn w32.OPENFILENAME - ofn.StructSize = uint32(unsafe.Sizeof(ofn)) - ofn.Owner = parent.Handle() - - if filter != "" { - filterBuf := make([]uint16, len(filter)+1) - copy(filterBuf, syscall.StringToUTF16(filter)) - // Replace '|' with the expected '\0' - for i, c := range filterBuf { - if byte(c) == '|' { - filterBuf[i] = uint16(0) - } - } - ofn.Filter = &filterBuf[0] - ofn.FilterIndex = uint32(filterIndex) - } - - ofn.File = &buf[0] - ofn.MaxFile = uint32(len(buf)) - - if initialDir != "" { - ofn.InitialDir = syscall.StringToUTF16Ptr(initialDir) - } - if title != "" { - ofn.Title = syscall.StringToUTF16Ptr(title) - } - - ofn.Flags = w32.OFN_FILEMUSTEXIST - return &ofn -} - -func ShowOpenFileDlg(parent Controller, title, filter string, filterIndex uint, initialDir string) (filePath string, accepted bool) { - buf := make([]uint16, 1024) - ofn := genOFN(parent, title, filter, filterIndex, initialDir, buf) - - if accepted = w32.GetOpenFileName(ofn); accepted { - filePath = syscall.UTF16ToString(buf) - } - return -} - -func ShowSaveFileDlg(parent Controller, title, filter string, filterIndex uint, initialDir string) (filePath string, accepted bool) { - buf := make([]uint16, 1024) - ofn := genOFN(parent, title, filter, filterIndex, initialDir, buf) - - if accepted = w32.GetSaveFileName(ofn); accepted { - filePath = syscall.UTF16ToString(buf) - } - return -} - -func ShowBrowseFolderDlg(parent Controller, title string) (folder string, accepted bool) { - var bi w32.BROWSEINFO - bi.Owner = parent.Handle() - bi.Title = syscall.StringToUTF16Ptr(title) - bi.Flags = w32.BIF_RETURNONLYFSDIRS | w32.BIF_NEWDIALOGSTYLE - - w32.CoInitialize() - ret := w32.SHBrowseForFolder(&bi) - w32.CoUninitialize() - - folder = w32.SHGetPathFromIDList(ret) - accepted = folder != "" - return -} - -// MsgBoxOkCancel basic pop up message. Returns 1 for OK and 2 for CANCEL. -func MsgBoxOkCancel(parent Controller, title, caption string) int { - return MsgBox(parent, title, caption, w32.MB_ICONEXCLAMATION|w32.MB_OKCANCEL) -} - -func MsgBoxYesNo(parent Controller, title, caption string) int { - return MsgBox(parent, title, caption, w32.MB_ICONEXCLAMATION|w32.MB_YESNO) -} - -func MsgBoxOk(parent Controller, title, caption string) { - MsgBox(parent, title, caption, w32.MB_ICONINFORMATION|w32.MB_OK) -} - -// Warningf is generic warning message with OK and Cancel buttons. Returns 1 for OK. -func Warningf(parent Controller, format string, data ...interface{}) int { - caption := fmt.Sprintf(format, data...) - return MsgBox(parent, "Warning", caption, w32.MB_ICONWARNING|w32.MB_OKCANCEL) -} - -// Printf is generic info message with OK button. -func Printf(parent Controller, format string, data ...interface{}) { - caption := fmt.Sprintf(format, data...) - MsgBox(parent, "Information", caption, w32.MB_ICONINFORMATION|w32.MB_OK) -} - -// Errorf is generic error message with OK button. -func Errorf(parent Controller, format string, data ...interface{}) { - caption := fmt.Sprintf(format, data...) - MsgBox(parent, "Error", caption, w32.MB_ICONERROR|w32.MB_OK) -} - -func MsgBox(parent Controller, title, caption string, flags uint) int { - var result int - if parent != nil { - result = w32.MessageBox(parent.Handle(), caption, title, flags) - } else { - result = w32.MessageBox(0, caption, title, flags) - } - - return result -} diff --git a/v2/internal/frontend/desktop/windows/winc/controlbase.go b/v2/internal/frontend/desktop/windows/winc/controlbase.go deleted file mode 100644 index cdb29518c..000000000 --- a/v2/internal/frontend/desktop/windows/winc/controlbase.go +++ /dev/null @@ -1,560 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2013 Allen Dang. All Rights Reserved. - */ - -package winc - -import ( - "fmt" - "runtime" - "sync" - "syscall" - "unsafe" - - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -type ControlBase struct { - hwnd w32.HWND - font *Font - parent Controller - contextMenu *MenuItem - - isForm bool - - minWidth, minHeight int - maxWidth, maxHeight int - - // General events - onCreate EventManager - onClose EventManager - - // Focus events - onKillFocus EventManager - onSetFocus EventManager - - // Drag and drop events - onDropFiles EventManager - - // Mouse events - onLBDown EventManager - onLBUp EventManager - onLBDbl EventManager - onMBDown EventManager - onMBUp EventManager - onRBDown EventManager - onRBUp EventManager - onRBDbl EventManager - onMouseMove EventManager - - // use MouseControl to capture onMouseHover and onMouseLeave events. - onMouseHover EventManager - onMouseLeave EventManager - - // Keyboard events - onKeyUp EventManager - - // Paint events - onPaint EventManager - onSize EventManager - - m sync.Mutex - dispatchq []func() -} - -// InitControl is called by controls: edit, button, treeview, listview, and so on. -func (cba *ControlBase) InitControl(className string, parent Controller, exstyle, style uint) { - cba.hwnd = CreateWindow(className, parent, exstyle, style) - if cba.hwnd == 0 { - panic("cannot create window for " + className) - } - cba.parent = parent -} - -// InitWindow is called by custom window based controls such as split, panel, etc. -func (cba *ControlBase) InitWindow(className string, parent Controller, exstyle, style uint) { - RegClassOnlyOnce(className) - cba.hwnd = CreateWindow(className, parent, exstyle, style) - if cba.hwnd == 0 { - panic("cannot create window for " + className) - } - cba.parent = parent -} - -// SetTheme for TreeView and ListView controls. -func (cba *ControlBase) SetTheme(appName string) error { - if hr := w32.SetWindowTheme(cba.hwnd, syscall.StringToUTF16Ptr(appName), nil); w32.FAILED(hr) { - return fmt.Errorf("SetWindowTheme %d", hr) - } - return nil -} - -func (cba *ControlBase) Handle() w32.HWND { - return cba.hwnd -} - -func (cba *ControlBase) SetHandle(hwnd w32.HWND) { - cba.hwnd = hwnd -} - -func (cba *ControlBase) GetWindowDPI() (w32.UINT, w32.UINT) { - if w32.HasGetDpiForWindowFunc() { - // GetDpiForWindow is supported beginning with Windows 10, 1607 and is the most accureate - // one, especially it is consistent with the WM_DPICHANGED event. - dpi := w32.GetDpiForWindow(cba.hwnd) - return dpi, dpi - } - - if w32.HasGetDPIForMonitorFunc() { - // GetDpiForWindow is supported beginning with Windows 8.1 - monitor := w32.MonitorFromWindow(cba.hwnd, w32.MONITOR_DEFAULTTONEAREST) - if monitor == 0 { - return 0, 0 - } - var dpiX, dpiY w32.UINT - w32.GetDPIForMonitor(monitor, w32.MDT_EFFECTIVE_DPI, &dpiX, &dpiY) - return dpiX, dpiY - } - - // If none of the above is supported fallback to the System DPI. - screen := w32.GetDC(0) - x := w32.GetDeviceCaps(screen, w32.LOGPIXELSX) - y := w32.GetDeviceCaps(screen, w32.LOGPIXELSY) - w32.ReleaseDC(0, screen) - return w32.UINT(x), w32.UINT(y) -} - -func (cba *ControlBase) SetAndClearStyleBits(set, clear uint32) error { - style := uint32(w32.GetWindowLong(cba.hwnd, w32.GWL_STYLE)) - if style == 0 { - return fmt.Errorf("GetWindowLong") - } - - if newStyle := style&^clear | set; newStyle != style { - if w32.SetWindowLong(cba.hwnd, w32.GWL_STYLE, newStyle) == 0 { - return fmt.Errorf("SetWindowLong") - } - } - return nil -} - -func (cba *ControlBase) SetIsForm(isform bool) { - cba.isForm = isform -} - -func (cba *ControlBase) SetText(caption string) { - w32.SetWindowText(cba.hwnd, caption) -} - -func (cba *ControlBase) Text() string { - return w32.GetWindowText(cba.hwnd) -} - -func (cba *ControlBase) Close() { - UnRegMsgHandler(cba.hwnd) - w32.DestroyWindow(cba.hwnd) -} - -func (cba *ControlBase) SetTranslucentBackground() { - var accent = w32.ACCENT_POLICY{ - AccentState: w32.ACCENT_ENABLE_BLURBEHIND, - } - var data w32.WINDOWCOMPOSITIONATTRIBDATA - data.Attrib = w32.WCA_ACCENT_POLICY - data.PvData = unsafe.Pointer(&accent) - data.CbData = unsafe.Sizeof(accent) - - w32.SetWindowCompositionAttribute(cba.hwnd, &data) -} - -func (cba *ControlBase) SetContentProtection(enable bool) { - if enable { - w32.SetWindowDisplayAffinity(uintptr(cba.hwnd), w32.WDA_EXCLUDEFROMCAPTURE) - } else { - w32.SetWindowDisplayAffinity(uintptr(cba.hwnd), w32.WDA_NONE) - } -} - -func min(a, b int) int { - if a < b { - return a - } - return b -} - -func max(a, b int) int { - if a > b { - return a - } - return b -} - -func (cba *ControlBase) clampSize(width, height int) (int, int) { - if cba.minWidth != 0 { - width = max(width, cba.minWidth) - } - if cba.maxWidth != 0 { - width = min(width, cba.maxWidth) - } - if cba.minHeight != 0 { - height = max(height, cba.minHeight) - } - if cba.maxHeight != 0 { - height = min(height, cba.maxHeight) - } - return width, height -} - -func (cba *ControlBase) SetSize(width, height int) { - x, y := cba.Pos() - width, height = cba.clampSize(width, height) - width, height = cba.scaleWithWindowDPI(width, height) - w32.MoveWindow(cba.hwnd, x, y, width, height, true) -} - -func (cba *ControlBase) SetMinSize(width, height int) { - cba.minWidth = width - cba.minHeight = height - - // Ensure we set max if min > max - if cba.maxWidth > 0 { - cba.maxWidth = max(cba.minWidth, cba.maxWidth) - } - if cba.maxHeight > 0 { - cba.maxHeight = max(cba.minHeight, cba.maxHeight) - } - - x, y := cba.Pos() - currentWidth, currentHeight := cba.Size() - clampedWidth, clampedHeight := cba.clampSize(currentWidth, currentHeight) - if clampedWidth != currentWidth || clampedHeight != currentHeight { - w32.MoveWindow(cba.hwnd, x, y, clampedWidth, clampedHeight, true) - } -} -func (cba *ControlBase) SetMaxSize(width, height int) { - cba.maxWidth = width - cba.maxHeight = height - - // Ensure we set min if max > min - if cba.maxWidth > 0 { - cba.minWidth = min(cba.maxWidth, cba.minWidth) - } - if cba.maxHeight > 0 { - cba.minHeight = min(cba.maxHeight, cba.minHeight) - } - - x, y := cba.Pos() - currentWidth, currentHeight := cba.Size() - clampedWidth, clampedHeight := cba.clampSize(currentWidth, currentHeight) - if clampedWidth != currentWidth || clampedHeight != currentHeight { - w32.MoveWindow(cba.hwnd, x, y, clampedWidth, clampedHeight, true) - } -} - -func (cba *ControlBase) Size() (width, height int) { - rect := w32.GetWindowRect(cba.hwnd) - width = int(rect.Right - rect.Left) - height = int(rect.Bottom - rect.Top) - width, height = cba.scaleToDefaultDPI(width, height) - return -} - -func (cba *ControlBase) Width() int { - rect := w32.GetWindowRect(cba.hwnd) - return int(rect.Right - rect.Left) -} - -func (cba *ControlBase) Height() int { - rect := w32.GetWindowRect(cba.hwnd) - return int(rect.Bottom - rect.Top) -} - -func (cba *ControlBase) SetPos(x, y int) { - info := getMonitorInfo(cba.hwnd) - workRect := info.RcWork - - w32.SetWindowPos(cba.hwnd, w32.HWND_TOP, int(workRect.Left)+x, int(workRect.Top)+y, 0, 0, w32.SWP_NOSIZE) -} -func (cba *ControlBase) SetAlwaysOnTop(b bool) { - if b { - w32.SetWindowPos(cba.hwnd, w32.HWND_TOPMOST, 0, 0, 0, 0, w32.SWP_NOSIZE|w32.SWP_NOMOVE) - } else { - w32.SetWindowPos(cba.hwnd, w32.HWND_NOTOPMOST, 0, 0, 0, 0, w32.SWP_NOSIZE|w32.SWP_NOMOVE) - } -} - -func (cba *ControlBase) Pos() (x, y int) { - rect := w32.GetWindowRect(cba.hwnd) - x = int(rect.Left) - y = int(rect.Top) - if !cba.isForm && cba.parent != nil { - x, y, _ = w32.ScreenToClient(cba.parent.Handle(), x, y) - } - return -} - -func (cba *ControlBase) Visible() bool { - return w32.IsWindowVisible(cba.hwnd) -} - -func (cba *ControlBase) ToggleVisible() bool { - visible := w32.IsWindowVisible(cba.hwnd) - if visible { - cba.Hide() - } else { - cba.Show() - } - return !visible -} - -func (cba *ControlBase) ContextMenu() *MenuItem { - return cba.contextMenu -} - -func (cba *ControlBase) SetContextMenu(menu *MenuItem) { - cba.contextMenu = menu -} - -func (cba *ControlBase) Bounds() *Rect { - rect := w32.GetWindowRect(cba.hwnd) - if cba.isForm { - return &Rect{*rect} - } - - return ScreenToClientRect(cba.hwnd, rect) -} - -func (cba *ControlBase) ClientRect() *Rect { - rect := w32.GetClientRect(cba.hwnd) - return ScreenToClientRect(cba.hwnd, rect) -} -func (cba *ControlBase) ClientWidth() int { - rect := w32.GetClientRect(cba.hwnd) - return int(rect.Right - rect.Left) -} - -func (cba *ControlBase) ClientHeight() int { - rect := w32.GetClientRect(cba.hwnd) - return int(rect.Bottom - rect.Top) -} - -func (cba *ControlBase) Show() { - // WindowPos is used with HWND_TOPMOST to guarantee bring our app on top - // force set our main window on top - w32.SetWindowPos( - cba.hwnd, - w32.HWND_TOPMOST, - 0, 0, 0, 0, - w32.SWP_SHOWWINDOW|w32.SWP_NOSIZE|w32.SWP_NOMOVE, - ) - // remove topmost to allow normal windows manipulations - w32.SetWindowPos( - cba.hwnd, - w32.HWND_NOTOPMOST, - 0, 0, 0, 0, - w32.SWP_SHOWWINDOW|w32.SWP_NOSIZE|w32.SWP_NOMOVE, - ) - // put main window on tops foreground - w32.SetForegroundWindow(cba.hwnd) -} - -func (cba *ControlBase) Hide() { - w32.ShowWindow(cba.hwnd, w32.SW_HIDE) -} - -func (cba *ControlBase) Enabled() bool { - return w32.IsWindowEnabled(cba.hwnd) -} - -func (cba *ControlBase) SetEnabled(b bool) { - w32.EnableWindow(cba.hwnd, b) -} - -func (cba *ControlBase) SetFocus() { - w32.SetFocus(cba.hwnd) -} - -func (cba *ControlBase) Invalidate(erase bool) { - // pRect := w32.GetClientRect(cba.hwnd) - // if cba.isForm { - // w32.InvalidateRect(cba.hwnd, pRect, erase) - // } else { - // rc := ScreenToClientRect(cba.hwnd, pRect) - // w32.InvalidateRect(cba.hwnd, rc.GetW32Rect(), erase) - // } - w32.InvalidateRect(cba.hwnd, nil, erase) -} - -func (cba *ControlBase) Parent() Controller { - return cba.parent -} - -func (cba *ControlBase) SetParent(parent Controller) { - cba.parent = parent -} - -func (cba *ControlBase) Font() *Font { - return cba.font -} - -func (cba *ControlBase) SetFont(font *Font) { - w32.SendMessage(cba.hwnd, w32.WM_SETFONT, uintptr(font.hfont), 1) - cba.font = font -} - -func (cba *ControlBase) EnableDragAcceptFiles(b bool) { - w32.DragAcceptFiles(cba.hwnd, b) -} - -func (cba *ControlBase) InvokeRequired() bool { - if cba.hwnd == 0 { - return false - } - - windowThreadId, _ := w32.GetWindowThreadProcessId(cba.hwnd) - currentThreadId := w32.GetCurrentThreadId() - - return windowThreadId != currentThreadId -} - -func (cba *ControlBase) Invoke(f func()) { - if cba.tryInvokeOnCurrentGoRoutine(f) { - return - } - - cba.m.Lock() - cba.dispatchq = append(cba.dispatchq, f) - cba.m.Unlock() - w32.PostMessage(cba.hwnd, wmInvokeCallback, 0, 0) -} - -func (cba *ControlBase) PreTranslateMessage(msg *w32.MSG) bool { - if msg.Message == w32.WM_GETDLGCODE { - println("pretranslate, WM_GETDLGCODE") - } - return false -} - -// Events -func (cba *ControlBase) OnCreate() *EventManager { - return &cba.onCreate -} - -func (cba *ControlBase) OnClose() *EventManager { - return &cba.onClose -} - -func (cba *ControlBase) OnKillFocus() *EventManager { - return &cba.onKillFocus -} - -func (cba *ControlBase) OnSetFocus() *EventManager { - return &cba.onSetFocus -} - -func (cba *ControlBase) OnDropFiles() *EventManager { - return &cba.onDropFiles -} - -func (cba *ControlBase) OnLBDown() *EventManager { - return &cba.onLBDown -} - -func (cba *ControlBase) OnLBUp() *EventManager { - return &cba.onLBUp -} - -func (cba *ControlBase) OnLBDbl() *EventManager { - return &cba.onLBDbl -} - -func (cba *ControlBase) OnMBDown() *EventManager { - return &cba.onMBDown -} - -func (cba *ControlBase) OnMBUp() *EventManager { - return &cba.onMBUp -} - -func (cba *ControlBase) OnRBDown() *EventManager { - return &cba.onRBDown -} - -func (cba *ControlBase) OnRBUp() *EventManager { - return &cba.onRBUp -} - -func (cba *ControlBase) OnRBDbl() *EventManager { - return &cba.onRBDbl -} - -func (cba *ControlBase) OnMouseMove() *EventManager { - return &cba.onMouseMove -} - -func (cba *ControlBase) OnMouseHover() *EventManager { - return &cba.onMouseHover -} - -func (cba *ControlBase) OnMouseLeave() *EventManager { - return &cba.onMouseLeave -} - -func (cba *ControlBase) OnPaint() *EventManager { - return &cba.onPaint -} - -func (cba *ControlBase) OnSize() *EventManager { - return &cba.onSize -} - -func (cba *ControlBase) OnKeyUp() *EventManager { - return &cba.onKeyUp -} - -func (cba *ControlBase) scaleWithWindowDPI(width, height int) (int, int) { - dpix, dpiy := cba.GetWindowDPI() - scaledWidth := ScaleWithDPI(width, dpix) - scaledHeight := ScaleWithDPI(height, dpiy) - - return scaledWidth, scaledHeight -} - -func (cba *ControlBase) scaleToDefaultDPI(width, height int) (int, int) { - dpix, dpiy := cba.GetWindowDPI() - scaledWidth := ScaleToDefaultDPI(width, dpix) - scaledHeight := ScaleToDefaultDPI(height, dpiy) - - return scaledWidth, scaledHeight -} - -func (cba *ControlBase) tryInvokeOnCurrentGoRoutine(f func()) bool { - runtime.LockOSThread() - defer runtime.UnlockOSThread() - - if cba.InvokeRequired() { - return false - } - f() - return true -} - -func (cba *ControlBase) invokeCallbacks() { - runtime.LockOSThread() - defer runtime.UnlockOSThread() - - if cba.InvokeRequired() { - panic("InvokeCallbacks must always be called on the window thread") - } - - cba.m.Lock() - q := append([]func(){}, cba.dispatchq...) - cba.dispatchq = []func(){} - cba.m.Unlock() - for _, v := range q { - v() - } -} diff --git a/v2/internal/frontend/desktop/windows/winc/controller.go b/v2/internal/frontend/desktop/windows/winc/controller.go deleted file mode 100644 index b697d9977..000000000 --- a/v2/internal/frontend/desktop/windows/winc/controller.go +++ /dev/null @@ -1,85 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2013 Allen Dang. All Rights Reserved. - */ - -package winc - -import ( - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -type Controller interface { - Text() string - - Enabled() bool - SetFocus() - - Handle() w32.HWND - Invalidate(erase bool) - Parent() Controller - - Pos() (x, y int) - Size() (w, h int) - Height() int - Width() int - Visible() bool - Bounds() *Rect - ClientRect() *Rect - - SetText(s string) - SetEnabled(b bool) - SetPos(x, y int) - SetSize(w, h int) - EnableDragAcceptFiles(b bool) - Show() - Hide() - - ContextMenu() *MenuItem - SetContextMenu(menu *MenuItem) - - Font() *Font - SetFont(font *Font) - InvokeRequired() bool - Invoke(func()) - PreTranslateMessage(msg *w32.MSG) bool - WndProc(msg uint32, wparam, lparam uintptr) uintptr - - //General events - OnCreate() *EventManager - OnClose() *EventManager - - // Focus events - OnKillFocus() *EventManager - OnSetFocus() *EventManager - - //Drag and drop events - OnDropFiles() *EventManager - - //Mouse events - OnLBDown() *EventManager - OnLBUp() *EventManager - OnLBDbl() *EventManager - OnMBDown() *EventManager - OnMBUp() *EventManager - OnRBDown() *EventManager - OnRBUp() *EventManager - OnRBDbl() *EventManager - OnMouseMove() *EventManager - - // OnMouseLeave and OnMouseHover does not fire unless control called internalTrackMouseEvent. - // Use MouseControl for a how to example. - OnMouseHover() *EventManager - OnMouseLeave() *EventManager - - //Keyboard events - OnKeyUp() *EventManager - - //Paint events - OnPaint() *EventManager - OnSize() *EventManager - - invokeCallbacks() -} diff --git a/v2/internal/frontend/desktop/windows/winc/dialog.go b/v2/internal/frontend/desktop/windows/winc/dialog.go deleted file mode 100644 index 6ed87ae4c..000000000 --- a/v2/internal/frontend/desktop/windows/winc/dialog.go +++ /dev/null @@ -1,136 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2013 Allen Dang. All Rights Reserved. - */ - -package winc - -import "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" - -// Dialog displayed as z-order top window until closed. -// It also disables parent window so it can not be clicked. -type Dialog struct { - Form - isModal bool - - btnOk *PushButton - btnCancel *PushButton - - onLoad EventManager - onOk EventManager - onCancel EventManager -} - -func NewDialog(parent Controller) *Dialog { - dlg := new(Dialog) - - dlg.isForm = true - dlg.isModal = true - RegClassOnlyOnce("winc_Dialog") - - dlg.hwnd = CreateWindow("winc_Dialog", parent, w32.WS_EX_CONTROLPARENT, /* IMPORTANT */ - w32.WS_SYSMENU|w32.WS_CAPTION|w32.WS_THICKFRAME /*|w32.WS_BORDER|w32.WS_POPUP*/) - dlg.parent = parent - - // dlg might fail if icon resource is not embedded in the binary - if ico, err := NewIconFromResource(GetAppInstance(), uint16(AppIconID)); err == nil { - dlg.SetIcon(0, ico) - } - - // Dlg forces display of focus rectangles, as soon as the user starts to type. - w32.SendMessage(dlg.hwnd, w32.WM_CHANGEUISTATE, w32.UIS_INITIALIZE, 0) - RegMsgHandler(dlg) - - dlg.SetFont(DefaultFont) - dlg.SetText("Form") - dlg.SetSize(200, 100) - return dlg -} - -func (dlg *Dialog) SetModal(modal bool) { - dlg.isModal = modal -} - -// SetButtons wires up dialog events to buttons. btnCancel can be nil. -func (dlg *Dialog) SetButtons(btnOk *PushButton, btnCancel *PushButton) { - dlg.btnOk = btnOk - dlg.btnOk.SetDefault() - dlg.btnCancel = btnCancel -} - -// Events -func (dlg *Dialog) OnLoad() *EventManager { - return &dlg.onLoad -} - -func (dlg *Dialog) OnOk() *EventManager { - return &dlg.onOk -} - -func (dlg *Dialog) OnCancel() *EventManager { - return &dlg.onCancel -} - -// PreTranslateMessage handles dialog specific messages. IMPORTANT. -func (dlg *Dialog) PreTranslateMessage(msg *w32.MSG) bool { - if msg.Message >= w32.WM_KEYFIRST && msg.Message <= w32.WM_KEYLAST { - if w32.IsDialogMessage(dlg.hwnd, msg) { - return true - } - } - return false -} - -// Show dialog performs special setup for dialog windows. -func (dlg *Dialog) Show() { - if dlg.isModal { - dlg.Parent().SetEnabled(false) - } - dlg.onLoad.Fire(NewEvent(dlg, nil)) - dlg.Form.Show() -} - -// Close dialog when you done with it. -func (dlg *Dialog) Close() { - if dlg.isModal { - dlg.Parent().SetEnabled(true) - } - dlg.ControlBase.Close() -} - -func (dlg *Dialog) cancel() { - if dlg.btnCancel != nil { - dlg.btnCancel.onClick.Fire(NewEvent(dlg.btnCancel, nil)) - } - dlg.onCancel.Fire(NewEvent(dlg, nil)) -} - -func (dlg *Dialog) WndProc(msg uint32, wparam, lparam uintptr) uintptr { - switch msg { - case w32.WM_COMMAND: - switch w32.LOWORD(uint32(wparam)) { - case w32.IDOK: - if dlg.btnOk != nil { - dlg.btnOk.onClick.Fire(NewEvent(dlg.btnOk, nil)) - } - dlg.onOk.Fire(NewEvent(dlg, nil)) - return w32.TRUE - - case w32.IDCANCEL: - dlg.cancel() - return w32.TRUE - } - - case w32.WM_CLOSE: - dlg.cancel() // use onCancel or dlg.btnCancel.OnClick to close - return 0 - - case w32.WM_DESTROY: - if dlg.isModal { - dlg.Parent().SetEnabled(true) - } - } - return w32.DefWindowProc(dlg.hwnd, msg, wparam, lparam) -} diff --git a/v2/internal/frontend/desktop/windows/winc/dock_topbottom.png b/v2/internal/frontend/desktop/windows/winc/dock_topbottom.png deleted file mode 100644 index 32ffc2862..000000000 Binary files a/v2/internal/frontend/desktop/windows/winc/dock_topbottom.png and /dev/null differ diff --git a/v2/internal/frontend/desktop/windows/winc/dock_topleft.png b/v2/internal/frontend/desktop/windows/winc/dock_topleft.png deleted file mode 100644 index 7f466cafb..000000000 Binary files a/v2/internal/frontend/desktop/windows/winc/dock_topleft.png and /dev/null differ diff --git a/v2/internal/frontend/desktop/windows/winc/edit.go b/v2/internal/frontend/desktop/windows/winc/edit.go deleted file mode 100644 index 00e67b71f..000000000 --- a/v2/internal/frontend/desktop/windows/winc/edit.go +++ /dev/null @@ -1,113 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2013 Allen Dang. All Rights Reserved. - */ - -package winc - -import "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" - -type Edit struct { - ControlBase - onChange EventManager -} - -const passwordChar = '*' -const nopasswordChar = ' ' - -func NewEdit(parent Controller) *Edit { - edt := new(Edit) - - edt.InitControl("EDIT", parent, w32.WS_EX_CLIENTEDGE, w32.WS_CHILD|w32.WS_VISIBLE|w32.WS_TABSTOP|w32.ES_LEFT| - w32.ES_AUTOHSCROLL) - RegMsgHandler(edt) - - edt.SetFont(DefaultFont) - edt.SetSize(200, 22) - return edt -} - -// Events. -func (ed *Edit) OnChange() *EventManager { - return &ed.onChange -} - -// Public methods. -func (ed *Edit) SetReadOnly(isReadOnly bool) { - w32.SendMessage(ed.hwnd, w32.EM_SETREADONLY, uintptr(w32.BoolToBOOL(isReadOnly)), 0) -} - -// Public methods -func (ed *Edit) SetPassword(isPassword bool) { - if isPassword { - w32.SendMessage(ed.hwnd, w32.EM_SETPASSWORDCHAR, uintptr(passwordChar), 0) - } else { - w32.SendMessage(ed.hwnd, w32.EM_SETPASSWORDCHAR, 0, 0) - } -} - -func (ed *Edit) WndProc(msg uint32, wparam, lparam uintptr) uintptr { - switch msg { - case w32.WM_COMMAND: - switch w32.HIWORD(uint32(wparam)) { - case w32.EN_CHANGE: - ed.onChange.Fire(NewEvent(ed, nil)) - } - /*case w32.WM_GETDLGCODE: - println("Edit") - if wparam == w32.VK_RETURN { - return w32.DLGC_WANTALLKEYS - }*/ - } - return w32.DefWindowProc(ed.hwnd, msg, wparam, lparam) -} - -// MultiEdit is multiline text edit. -type MultiEdit struct { - ControlBase - onChange EventManager -} - -func NewMultiEdit(parent Controller) *MultiEdit { - med := new(MultiEdit) - - med.InitControl("EDIT", parent, w32.WS_EX_CLIENTEDGE, w32.WS_CHILD|w32.WS_VISIBLE|w32.WS_TABSTOP|w32.ES_LEFT| - w32.WS_VSCROLL|w32.WS_HSCROLL|w32.ES_MULTILINE|w32.ES_WANTRETURN|w32.ES_AUTOHSCROLL|w32.ES_AUTOVSCROLL) - RegMsgHandler(med) - - med.SetFont(DefaultFont) - med.SetSize(200, 400) - return med -} - -// Events -func (med *MultiEdit) OnChange() *EventManager { - return &med.onChange -} - -// Public methods -func (med *MultiEdit) SetReadOnly(isReadOnly bool) { - w32.SendMessage(med.hwnd, w32.EM_SETREADONLY, uintptr(w32.BoolToBOOL(isReadOnly)), 0) -} - -func (med *MultiEdit) AddLine(text string) { - if len(med.Text()) == 0 { - med.SetText(text) - } else { - med.SetText(med.Text() + "\r\n" + text) - } -} - -func (med *MultiEdit) WndProc(msg uint32, wparam, lparam uintptr) uintptr { - switch msg { - - case w32.WM_COMMAND: - switch w32.HIWORD(uint32(wparam)) { - case w32.EN_CHANGE: - med.onChange.Fire(NewEvent(med, nil)) - } - } - return w32.DefWindowProc(med.hwnd, msg, wparam, lparam) -} diff --git a/v2/internal/frontend/desktop/windows/winc/event.go b/v2/internal/frontend/desktop/windows/winc/event.go deleted file mode 100644 index 12f894f60..000000000 --- a/v2/internal/frontend/desktop/windows/winc/event.go +++ /dev/null @@ -1,17 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2013 Allen Dang. All Rights Reserved. - */ - -package winc - -type Event struct { - Sender Controller - Data interface{} -} - -func NewEvent(sender Controller, data interface{}) *Event { - return &Event{Sender: sender, Data: data} -} diff --git a/v2/internal/frontend/desktop/windows/winc/eventdata.go b/v2/internal/frontend/desktop/windows/winc/eventdata.go deleted file mode 100644 index 32798ebf4..000000000 --- a/v2/internal/frontend/desktop/windows/winc/eventdata.go +++ /dev/null @@ -1,52 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2013 Allen Dang. All Rights Reserved. - */ - -package winc - -import ( - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -type RawMsg struct { - Hwnd w32.HWND - Msg uint32 - WParam, LParam uintptr -} - -type MouseEventData struct { - X, Y int - Button int - Wheel int -} - -type DropFilesEventData struct { - X, Y int - Files []string -} - -type PaintEventData struct { - Canvas *Canvas -} - -type LabelEditEventData struct { - Item ListItem - Text string - //PszText *uint16 -} - -/*type LVDBLClickEventData struct { - NmItem *w32.NMITEMACTIVATE -}*/ - -type KeyUpEventData struct { - VKey, Code int -} - -type SizeEventData struct { - Type uint - X, Y int -} diff --git a/v2/internal/frontend/desktop/windows/winc/eventmanager.go b/v2/internal/frontend/desktop/windows/winc/eventmanager.go deleted file mode 100644 index f4372e9c1..000000000 --- a/v2/internal/frontend/desktop/windows/winc/eventmanager.go +++ /dev/null @@ -1,24 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2013 Allen Dang. All Rights Reserved. - */ - -package winc - -type EventHandler func(arg *Event) - -type EventManager struct { - handler EventHandler -} - -func (evm *EventManager) Fire(arg *Event) { - if evm.handler != nil { - evm.handler(arg) - } -} - -func (evm *EventManager) Bind(handler EventHandler) { - evm.handler = handler -} diff --git a/v2/internal/frontend/desktop/windows/winc/font.go b/v2/internal/frontend/desktop/windows/winc/font.go deleted file mode 100644 index 314f1bbdf..000000000 --- a/v2/internal/frontend/desktop/windows/winc/font.go +++ /dev/null @@ -1,121 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2013 Allen Dang. All Rights Reserved. - */ - -package winc - -import ( - "syscall" - - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -const ( - FontBold byte = 0x01 - FontItalic byte = 0x02 - FontUnderline byte = 0x04 - FontStrikeOut byte = 0x08 -) - -func init() { - DefaultFont = NewFont("MS Shell Dlg 2", 8, 0) -} - -type Font struct { - hfont w32.HFONT - family string - pointSize int - style byte -} - -func NewFont(family string, pointSize int, style byte) *Font { - if style > FontBold|FontItalic|FontUnderline|FontStrikeOut { - panic("Invalid font style") - } - - //Retrive screen DPI - hDC := w32.GetDC(0) - defer w32.ReleaseDC(0, hDC) - screenDPIY := w32.GetDeviceCaps(hDC, w32.LOGPIXELSY) - - font := Font{ - family: family, - pointSize: pointSize, - style: style, - } - - font.hfont = font.createForDPI(screenDPIY) - if font.hfont == 0 { - panic("CreateFontIndirect failed") - } - - return &font -} - -func (fnt *Font) createForDPI(dpi int) w32.HFONT { - var lf w32.LOGFONT - - lf.Height = int32(-w32.MulDiv(fnt.pointSize, dpi, 72)) - if fnt.style&FontBold > 0 { - lf.Weight = w32.FW_BOLD - } else { - lf.Weight = w32.FW_NORMAL - } - if fnt.style&FontItalic > 0 { - lf.Italic = 1 - } - if fnt.style&FontUnderline > 0 { - lf.Underline = 1 - } - if fnt.style&FontStrikeOut > 0 { - lf.StrikeOut = 1 - } - lf.CharSet = w32.DEFAULT_CHARSET - lf.OutPrecision = w32.OUT_TT_PRECIS - lf.ClipPrecision = w32.CLIP_DEFAULT_PRECIS - lf.Quality = w32.CLEARTYPE_QUALITY - lf.PitchAndFamily = w32.VARIABLE_PITCH | w32.FF_SWISS - - src := syscall.StringToUTF16(fnt.family) - dest := lf.FaceName[:] - copy(dest, src) - - return w32.CreateFontIndirect(&lf) -} - -func (fnt *Font) GetHFONT() w32.HFONT { - return fnt.hfont -} - -func (fnt *Font) Bold() bool { - return fnt.style&FontBold > 0 -} - -func (fnt *Font) Dispose() { - if fnt.hfont != 0 { - w32.DeleteObject(w32.HGDIOBJ(fnt.hfont)) - } -} - -func (fnt *Font) Family() string { - return fnt.family -} - -func (fnt *Font) Italic() bool { - return fnt.style&FontItalic > 0 -} - -func (fnt *Font) StrikeOut() bool { - return fnt.style&FontStrikeOut > 0 -} - -func (fnt *Font) Underline() bool { - return fnt.style&FontUnderline > 0 -} - -func (fnt *Font) Style() byte { - return fnt.style -} diff --git a/v2/internal/frontend/desktop/windows/winc/form.go b/v2/internal/frontend/desktop/windows/winc/form.go deleted file mode 100644 index c9acf7278..000000000 --- a/v2/internal/frontend/desktop/windows/winc/form.go +++ /dev/null @@ -1,317 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2013 Allen Dang. All Rights Reserved. - */ - -package winc - -import ( - "unsafe" - - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -type LayoutManager interface { - Update() -} - -// A Form is main window of the application. -type Form struct { - ControlBase - - layoutMng LayoutManager - - // Fullscreen / Unfullscreen - isFullscreen bool - previousWindowStyle uint32 - previousWindowExStyle uint32 - previousWindowPlacement w32.WINDOWPLACEMENT -} - -func NewCustomForm(parent Controller, exStyle int, dwStyle uint) *Form { - fm := new(Form) - - RegClassOnlyOnce("winc_Form") - - fm.isForm = true - - if exStyle == 0 { - exStyle = w32.WS_EX_CONTROLPARENT | w32.WS_EX_APPWINDOW - } - - if dwStyle == 0 { - dwStyle = w32.WS_OVERLAPPEDWINDOW - } - - fm.hwnd = CreateWindow("winc_Form", parent, uint(exStyle), dwStyle) - fm.parent = parent - - // this might fail if icon resource is not embedded in the binary - if ico, err := NewIconFromResource(GetAppInstance(), uint16(AppIconID)); err == nil { - fm.SetIcon(0, ico) - } - - // This forces display of focus rectangles, as soon as the user starts to type. - w32.SendMessage(fm.hwnd, w32.WM_CHANGEUISTATE, w32.UIS_INITIALIZE, 0) - - RegMsgHandler(fm) - - fm.SetFont(DefaultFont) - fm.SetText("Form") - return fm -} - -func NewForm(parent Controller) *Form { - fm := new(Form) - - RegClassOnlyOnce("winc_Form") - - fm.isForm = true - fm.hwnd = CreateWindow("winc_Form", parent, w32.WS_EX_CONTROLPARENT|w32.WS_EX_APPWINDOW, w32.WS_OVERLAPPEDWINDOW) - fm.parent = parent - - // this might fail if icon resource is not embedded in the binary - if ico, err := NewIconFromResource(GetAppInstance(), uint16(AppIconID)); err == nil { - fm.SetIcon(0, ico) - } - - // This forces display of focus rectangles, as soon as the user starts to type. - w32.SendMessage(fm.hwnd, w32.WM_CHANGEUISTATE, w32.UIS_INITIALIZE, 0) - - RegMsgHandler(fm) - - fm.SetFont(DefaultFont) - fm.SetText("Form") - return fm -} - -func (fm *Form) SetLayout(mng LayoutManager) { - fm.layoutMng = mng -} - -// UpdateLayout refresh layout. -func (fm *Form) UpdateLayout() { - if fm.layoutMng != nil { - fm.layoutMng.Update() - } -} - -func (fm *Form) NewMenu() *Menu { - hMenu := w32.CreateMenu() - if hMenu == 0 { - panic("failed CreateMenu") - } - m := &Menu{hMenu: hMenu, hwnd: fm.hwnd} - if !w32.SetMenu(fm.hwnd, hMenu) { - panic("failed SetMenu") - } - return m -} - -func (fm *Form) DisableIcon() { - windowInfo := getWindowInfo(fm.hwnd) - frameless := windowInfo.IsPopup() - if frameless { - return - } - exStyle := w32.GetWindowLong(fm.hwnd, w32.GWL_EXSTYLE) - w32.SetWindowLong(fm.hwnd, w32.GWL_EXSTYLE, uint32(exStyle|w32.WS_EX_DLGMODALFRAME)) - w32.SetWindowPos(fm.hwnd, 0, 0, 0, 0, 0, - uint( - w32.SWP_FRAMECHANGED| - w32.SWP_NOMOVE| - w32.SWP_NOSIZE| - w32.SWP_NOZORDER), - ) -} - -func (fm *Form) Maximise() { - w32.ShowWindow(fm.hwnd, w32.SW_MAXIMIZE) -} - -func (fm *Form) Minimise() { - w32.ShowWindow(fm.hwnd, w32.SW_MINIMIZE) -} - -func (fm *Form) Restore() { - // SC_RESTORE param for WM_SYSCOMMAND to restore app if it is minimized - const SC_RESTORE = 0xF120 - // restore the minimized window, if it is - w32.SendMessage( - fm.hwnd, - w32.WM_SYSCOMMAND, - SC_RESTORE, - 0, - ) - w32.ShowWindow(fm.hwnd, w32.SW_SHOW) -} - -// Public methods -func (fm *Form) Center() { - - windowInfo := getWindowInfo(fm.hwnd) - frameless := windowInfo.IsPopup() - - info := getMonitorInfo(fm.hwnd) - workRect := info.RcWork - screenMiddleW := workRect.Left + (workRect.Right-workRect.Left)/2 - screenMiddleH := workRect.Top + (workRect.Bottom-workRect.Top)/2 - var winRect *w32.RECT - if !frameless { - winRect = w32.GetWindowRect(fm.hwnd) - } else { - winRect = w32.GetClientRect(fm.hwnd) - } - winWidth := winRect.Right - winRect.Left - winHeight := winRect.Bottom - winRect.Top - windowX := screenMiddleW - (winWidth / 2) - windowY := screenMiddleH - (winHeight / 2) - w32.SetWindowPos(fm.hwnd, w32.HWND_TOP, int(windowX), int(windowY), int(winWidth), int(winHeight), w32.SWP_NOSIZE) -} - -func (fm *Form) Fullscreen() { - if fm.isFullscreen { - return - } - - fm.previousWindowStyle = uint32(w32.GetWindowLongPtr(fm.hwnd, w32.GWL_STYLE)) - fm.previousWindowExStyle = uint32(w32.GetWindowLong(fm.hwnd, w32.GWL_EXSTYLE)) - - monitor := w32.MonitorFromWindow(fm.hwnd, w32.MONITOR_DEFAULTTOPRIMARY) - var monitorInfo w32.MONITORINFO - monitorInfo.CbSize = uint32(unsafe.Sizeof(monitorInfo)) - if !w32.GetMonitorInfo(monitor, &monitorInfo) { - return - } - if !w32.GetWindowPlacement(fm.hwnd, &fm.previousWindowPlacement) { - return - } - // According to https://devblogs.microsoft.com/oldnewthing/20050505-04/?p=35703 one should use w32.WS_POPUP | w32.WS_VISIBLE - w32.SetWindowLong(fm.hwnd, w32.GWL_STYLE, fm.previousWindowStyle & ^uint32(w32.WS_OVERLAPPEDWINDOW) | (w32.WS_POPUP|w32.WS_VISIBLE)) - w32.SetWindowLong(fm.hwnd, w32.GWL_EXSTYLE, fm.previousWindowExStyle & ^uint32(w32.WS_EX_DLGMODALFRAME)) - fm.isFullscreen = true - w32.SetWindowPos(fm.hwnd, w32.HWND_TOP, - int(monitorInfo.RcMonitor.Left), - int(monitorInfo.RcMonitor.Top), - int(monitorInfo.RcMonitor.Right-monitorInfo.RcMonitor.Left), - int(monitorInfo.RcMonitor.Bottom-monitorInfo.RcMonitor.Top), - w32.SWP_NOOWNERZORDER|w32.SWP_FRAMECHANGED) -} - -func (fm *Form) UnFullscreen() { - if !fm.isFullscreen { - return - } - w32.SetWindowLong(fm.hwnd, w32.GWL_STYLE, fm.previousWindowStyle) - w32.SetWindowLong(fm.hwnd, w32.GWL_EXSTYLE, fm.previousWindowExStyle) - w32.SetWindowPlacement(fm.hwnd, &fm.previousWindowPlacement) - fm.isFullscreen = false - w32.SetWindowPos(fm.hwnd, 0, 0, 0, 0, 0, - w32.SWP_NOMOVE|w32.SWP_NOSIZE|w32.SWP_NOZORDER|w32.SWP_NOOWNERZORDER|w32.SWP_FRAMECHANGED) -} - -func (fm *Form) IsFullScreen() bool { - return fm.isFullscreen -} - -// IconType: 1 - ICON_BIG; 0 - ICON_SMALL -func (fm *Form) SetIcon(iconType int, icon *Icon) { - if iconType > 1 { - panic("IconType is invalid") - } - w32.SendMessage(fm.hwnd, w32.WM_SETICON, uintptr(iconType), uintptr(icon.Handle())) -} - -func (fm *Form) EnableMaxButton(b bool) { - SetStyle(fm.hwnd, b, w32.WS_MAXIMIZEBOX) -} - -func (fm *Form) EnableMinButton(b bool) { - SetStyle(fm.hwnd, b, w32.WS_MINIMIZEBOX) -} - -func (fm *Form) EnableSizable(b bool) { - SetStyle(fm.hwnd, b, w32.WS_THICKFRAME) -} - -func (fm *Form) EnableDragMove(_ bool) { - //fm.isDragMove = b -} - -func (fm *Form) EnableTopMost(b bool) { - tag := w32.HWND_NOTOPMOST - if b { - tag = w32.HWND_TOPMOST - } - w32.SetWindowPos(fm.hwnd, tag, 0, 0, 0, 0, w32.SWP_NOMOVE|w32.SWP_NOSIZE) -} - -func (fm *Form) WndProc(msg uint32, wparam, lparam uintptr) uintptr { - - switch msg { - case w32.WM_COMMAND: - if lparam == 0 && w32.HIWORD(uint32(wparam)) == 0 { - // Menu support. - actionID := uint16(w32.LOWORD(uint32(wparam))) - if action, ok := actionsByID[actionID]; ok { - action.onClick.Fire(NewEvent(fm, nil)) - } - } - case w32.WM_KEYDOWN: - // Accelerator support. - key := Key(wparam) - if uint32(lparam)>>30 == 0 { - // Using TranslateAccelerators refused to work, so we handle them - // ourselves, at least for now. - shortcut := Shortcut{ModifiersDown(), key} - if action, ok := shortcut2Action[shortcut]; ok { - if action.Enabled() { - action.onClick.Fire(NewEvent(fm, nil)) - } - } - } - - case w32.WM_CLOSE: - return 0 - case w32.WM_DESTROY: - w32.PostQuitMessage(0) - return 0 - - case w32.WM_SIZE, w32.WM_PAINT: - if fm.layoutMng != nil { - fm.layoutMng.Update() - } - case w32.WM_GETMINMAXINFO: - mmi := (*w32.MINMAXINFO)(unsafe.Pointer(lparam)) - hasConstraints := false - if fm.minWidth > 0 || fm.minHeight > 0 { - hasConstraints = true - - width, height := fm.scaleWithWindowDPI(fm.minWidth, fm.minHeight) - if width > 0 { - mmi.PtMinTrackSize.X = int32(width) - } - if height > 0 { - mmi.PtMinTrackSize.Y = int32(height) - } - } - if fm.maxWidth > 0 || fm.maxHeight > 0 { - hasConstraints = true - - width, height := fm.scaleWithWindowDPI(fm.maxWidth, fm.maxHeight) - if width > 0 { - mmi.PtMaxTrackSize.X = int32(width) - } - if height > 0 { - mmi.PtMaxTrackSize.Y = int32(height) - } - } - if hasConstraints { - return 0 - } - } - - return w32.DefWindowProc(fm.hwnd, msg, wparam, lparam) -} diff --git a/v2/internal/frontend/desktop/windows/winc/globalvars.go b/v2/internal/frontend/desktop/windows/winc/globalvars.go deleted file mode 100644 index 46777da0f..000000000 --- a/v2/internal/frontend/desktop/windows/winc/globalvars.go +++ /dev/null @@ -1,27 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2013 Allen Dang. All Rights Reserved. - */ - -package winc - -import ( - "syscall" - - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -// Private global variables. -var ( - gAppInstance w32.HINSTANCE - gControllerRegistry map[w32.HWND]Controller - gRegisteredClasses []string -) - -// Public global variables. -var ( - GeneralWndprocCallBack = syscall.NewCallback(generalWndProc) - DefaultFont *Font -) diff --git a/v2/internal/frontend/desktop/windows/winc/icon.go b/v2/internal/frontend/desktop/windows/winc/icon.go deleted file mode 100644 index 6a3e1a391..000000000 --- a/v2/internal/frontend/desktop/windows/winc/icon.go +++ /dev/null @@ -1,55 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2013 Allen Dang. All Rights Reserved. - */ - -package winc - -import ( - "errors" - "fmt" - "syscall" - - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -type Icon struct { - handle w32.HICON -} - -func NewIconFromFile(path string) (*Icon, error) { - ico := new(Icon) - var err error - if ico.handle = w32.LoadIcon(0, syscall.StringToUTF16Ptr(path)); ico.handle == 0 { - err = errors.New(fmt.Sprintf("Cannot load icon from %s", path)) - } - return ico, err -} - -func NewIconFromResource(instance w32.HINSTANCE, resId uint16) (*Icon, error) { - ico := new(Icon) - var err error - if ico.handle = w32.LoadIconWithResourceID(instance, resId); ico.handle == 0 { - err = errors.New(fmt.Sprintf("Cannot load icon from resource with id %v", resId)) - } - return ico, err -} - -func ExtractIcon(fileName string, index int) (*Icon, error) { - ico := new(Icon) - var err error - if ico.handle = w32.ExtractIcon(fileName, index); ico.handle == 0 || ico.handle == 1 { - err = errors.New(fmt.Sprintf("Cannot extract icon from %s at index %v", fileName, index)) - } - return ico, err -} - -func (ic *Icon) Destroy() bool { - return w32.DestroyIcon(ic.handle) -} - -func (ic *Icon) Handle() w32.HICON { - return ic.handle -} diff --git a/v2/internal/frontend/desktop/windows/winc/imagelist.go b/v2/internal/frontend/desktop/windows/winc/imagelist.go deleted file mode 100644 index c540a816d..000000000 --- a/v2/internal/frontend/desktop/windows/winc/imagelist.go +++ /dev/null @@ -1,64 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2013 Allen Dang. All Rights Reserved. - */ - -package winc - -import ( - "fmt" - - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -type ImageList struct { - handle w32.HIMAGELIST -} - -func NewImageList(cx, cy int) *ImageList { - return newImageList(cx, cy, w32.ILC_COLOR32, 0, 0) -} - -func newImageList(cx, cy int, flags uint, cInitial, cGrow int) *ImageList { - imgl := new(ImageList) - imgl.handle = w32.ImageList_Create(cx, cy, flags, cInitial, cGrow) - return imgl -} - -func (im *ImageList) Handle() w32.HIMAGELIST { - return im.handle -} - -func (im *ImageList) Destroy() bool { - return w32.ImageList_Destroy(im.handle) -} - -func (im *ImageList) SetImageCount(uNewCount uint) bool { - return w32.ImageList_SetImageCount(im.handle, uNewCount) -} - -func (im *ImageList) ImageCount() int { - return w32.ImageList_GetImageCount(im.handle) -} - -func (im *ImageList) AddIcon(icon *Icon) int { - return w32.ImageList_AddIcon(im.handle, icon.Handle()) -} - -func (im *ImageList) AddResIcon(iconID uint16) { - if ico, err := NewIconFromResource(GetAppInstance(), iconID); err == nil { - im.AddIcon(ico) - return - } - panic(fmt.Sprintf("missing icon with icon ID: %d", iconID)) -} - -func (im *ImageList) RemoveAll() bool { - return w32.ImageList_RemoveAll(im.handle) -} - -func (im *ImageList) Remove(i int) bool { - return w32.ImageList_Remove(im.handle, i) -} diff --git a/v2/internal/frontend/desktop/windows/winc/imageview.go b/v2/internal/frontend/desktop/windows/winc/imageview.go deleted file mode 100644 index 8e3ae50b3..000000000 --- a/v2/internal/frontend/desktop/windows/winc/imageview.go +++ /dev/null @@ -1,59 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - */ - -package winc - -import "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" - -type ImageView struct { - ControlBase - - bmp *Bitmap -} - -func NewImageView(parent Controller) *ImageView { - iv := new(ImageView) - - iv.InitWindow("winc_ImageView", parent, w32.WS_EX_CONTROLPARENT, w32.WS_CHILD|w32.WS_VISIBLE) - RegMsgHandler(iv) - - iv.SetFont(DefaultFont) - iv.SetText("") - iv.SetSize(200, 65) - return iv -} - -func (iv *ImageView) DrawImageFile(filepath string) error { - bmp, err := NewBitmapFromFile(filepath, RGB(255, 255, 0)) - if err != nil { - return err - } - iv.bmp = bmp - return nil -} - -func (iv *ImageView) DrawImage(bmp *Bitmap) { - iv.bmp = bmp -} - -func (iv *ImageView) WndProc(msg uint32, wparam, lparam uintptr) uintptr { - switch msg { - case w32.WM_SIZE, w32.WM_SIZING: - iv.Invalidate(true) - - case w32.WM_ERASEBKGND: - return 1 // important - - case w32.WM_PAINT: - if iv.bmp != nil { - canvas := NewCanvasFromHwnd(iv.hwnd) - defer canvas.Dispose() - iv.SetSize(iv.bmp.Size()) - canvas.DrawBitmap(iv.bmp, 0, 0) - } - } - return w32.DefWindowProc(iv.hwnd, msg, wparam, lparam) -} diff --git a/v2/internal/frontend/desktop/windows/winc/imageviewbox.go b/v2/internal/frontend/desktop/windows/winc/imageviewbox.go deleted file mode 100644 index 0f6f57be9..000000000 --- a/v2/internal/frontend/desktop/windows/winc/imageviewbox.go +++ /dev/null @@ -1,342 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - */ - -package winc - -import ( - "fmt" - "time" - - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -type direction int - -const ( - DirNone direction = iota - DirX - DirY - DirX2 - DirY2 -) - -var ImageBoxPen = NewPen(w32.PS_GEOMETRIC, 2, NewSolidColorBrush(RGB(140, 140, 220))) -var ImageBoxHiPen = NewPen(w32.PS_GEOMETRIC, 2, NewSolidColorBrush(RGB(220, 140, 140))) -var ImageBoxMarkBrush = NewSolidColorBrush(RGB(40, 40, 40)) -var ImageBoxMarkPen = NewPen(w32.PS_GEOMETRIC, 2, ImageBoxMarkBrush) - -type ImageBox struct { - Name string - Type int - X, Y, X2, Y2 int - - underMouse bool // dynamic value -} - -func (b *ImageBox) Rect() *Rect { - return NewRect(b.X, b.Y, b.X2, b.Y2) -} - -// ImageViewBox is image view with boxes. -type ImageViewBox struct { - ControlBase - - bmp *Bitmap - mouseLeft bool - modified bool // used by GUI to see if any image box modified - - add bool - - Boxes []*ImageBox // might be persisted to file - dragBox *ImageBox - selBox *ImageBox - - dragStartX, dragStartY int - resize direction - - onSelectedChange EventManager - onAdd EventManager - onModify EventManager -} - -func NewImageViewBox(parent Controller) *ImageViewBox { - iv := new(ImageViewBox) - - iv.InitWindow("winc_ImageViewBox", parent, w32.WS_EX_CONTROLPARENT, w32.WS_CHILD|w32.WS_VISIBLE) - RegMsgHandler(iv) - - iv.SetFont(DefaultFont) - iv.SetText("") - iv.SetSize(200, 65) - - return iv -} - -func (iv *ImageViewBox) OnSelectedChange() *EventManager { - return &iv.onSelectedChange -} - -func (iv *ImageViewBox) OnAdd() *EventManager { - return &iv.onAdd -} - -func (iv *ImageViewBox) OnModify() *EventManager { - return &iv.onModify -} - -func (iv *ImageViewBox) IsModified() bool { return iv.modified } -func (iv *ImageViewBox) SetModified(modified bool) { iv.modified = modified } -func (iv *ImageViewBox) IsLoaded() bool { return iv.bmp != nil } -func (iv *ImageViewBox) AddMode() bool { return iv.add } -func (iv *ImageViewBox) SetAddMode(add bool) { iv.add = add } -func (iv *ImageViewBox) HasSelected() bool { return iv.selBox != nil && iv.bmp != nil } - -func (iv *ImageViewBox) wasModified() { - iv.modified = true - iv.onModify.Fire(NewEvent(iv, nil)) -} - -func (iv *ImageViewBox) DeleteSelected() { - if iv.selBox != nil { - for i, b := range iv.Boxes { - if b == iv.selBox { - iv.Boxes = append(iv.Boxes[:i], iv.Boxes[i+1:]...) - iv.selBox = nil - iv.Invalidate(true) - iv.wasModified() - iv.onSelectedChange.Fire(NewEvent(iv, nil)) - return - } - } - } -} - -func (iv *ImageViewBox) NameSelected() string { - if iv.selBox != nil { - return iv.selBox.Name - } - return "" -} - -func (iv *ImageViewBox) SetNameSelected(name string) { - if iv.selBox != nil { - iv.selBox.Name = name - iv.wasModified() - } -} - -func (iv *ImageViewBox) TypeSelected() int { - if iv.selBox != nil { - return iv.selBox.Type - } - return 0 -} - -func (iv *ImageViewBox) SetTypeSelected(typ int) { - if iv.selBox != nil { - iv.selBox.Type = typ - iv.wasModified() - } -} - -func (ib *ImageViewBox) updateHighlight(x, y int) bool { - var changed bool - for _, b := range ib.Boxes { - under := x >= b.X && y >= b.Y && x <= b.X2 && y <= b.Y2 - if b.underMouse != under { - changed = true - } - b.underMouse = under - /*if sel { - break // allow only one to be underMouse - }*/ - } - return changed -} - -func (ib *ImageViewBox) isUnderMouse(x, y int) *ImageBox { - for _, b := range ib.Boxes { - if x >= b.X && y >= b.Y && x <= b.X2 && y <= b.Y2 { - return b - } - } - return nil -} - -func (ib *ImageViewBox) getCursor(x, y int) uint16 { - for _, b := range ib.Boxes { - switch d := ib.resizingDirection(b, x, y); d { - case DirY, DirY2: - return w32.IDC_SIZENS - case DirX, DirX2: - return w32.IDC_SIZEWE - } - // w32.IDC_SIZEALL or w32.IDC_SIZE for resize - } - return w32.IDC_ARROW -} - -func (ib *ImageViewBox) resizingDirection(b *ImageBox, x, y int) direction { - if b == nil { - return DirNone - } - switch { - case b.X == x || b.X == x-1 || b.X == x+1: - return DirX - case b.X2 == x || b.X2 == x-1 || b.X2 == x+1: - return DirX2 - case b.Y == y || b.Y == y-1 || b.Y == y+1: - return DirY - case b.Y2 == y || b.Y2 == y-1 || b.Y2 == y+1: - return DirY2 - } - return DirNone -} - -func (ib *ImageViewBox) resizeToDirection(b *ImageBox, x, y int) { - switch ib.resize { - case DirX: - b.X = x - case DirY: - b.Y = y - case DirX2: - b.X2 = x - case DirY2: - b.Y2 = y - } -} - -func (ib *ImageViewBox) drag(b *ImageBox, x, y int) { - w, h := b.X2-b.X, b.Y2-b.Y - - nx := ib.dragStartX - b.X - ny := ib.dragStartY - b.Y - - b.X = x - nx - b.Y = y - ny - b.X2 = b.X + w - b.Y2 = b.Y + h - - ib.dragStartX, ib.dragStartY = x, y -} - -func (iv *ImageViewBox) DrawImageFile(filepath string) (err error) { - iv.bmp, err = NewBitmapFromFile(filepath, RGB(255, 255, 0)) - iv.selBox = nil - iv.modified = false - iv.onSelectedChange.Fire(NewEvent(iv, nil)) - iv.onModify.Fire(NewEvent(iv, nil)) - return -} - -func (iv *ImageViewBox) DrawImage(bmp *Bitmap) { - iv.bmp = bmp - iv.selBox = nil - iv.modified = false - iv.onSelectedChange.Fire(NewEvent(iv, nil)) - iv.onModify.Fire(NewEvent(iv, nil)) -} - -func (iv *ImageViewBox) WndProc(msg uint32, wparam, lparam uintptr) uintptr { - switch msg { - case w32.WM_SIZE, w32.WM_SIZING: - iv.Invalidate(true) - - case w32.WM_ERASEBKGND: - return 1 // important - - case w32.WM_CREATE: - internalTrackMouseEvent(iv.hwnd) - - case w32.WM_PAINT: - if iv.bmp != nil { - canvas := NewCanvasFromHwnd(iv.hwnd) - defer canvas.Dispose() - iv.SetSize(iv.bmp.Size()) - canvas.DrawBitmap(iv.bmp, 0, 0) - - for _, b := range iv.Boxes { - // old code used NewSystemColorBrush(w32.COLOR_BTNFACE) w32.COLOR_WINDOW - pen := ImageBoxPen - if b.underMouse { - pen = ImageBoxHiPen - } - canvas.DrawRect(b.Rect(), pen) - - if b == iv.selBox { - x1 := []int{b.X, b.X2, b.X2, b.X} - y1 := []int{b.Y, b.Y, b.Y2, b.Y2} - - for i := 0; i < len(x1); i++ { - r := NewRect(x1[i]-2, y1[i]-2, x1[i]+2, y1[i]+2) - canvas.DrawFillRect(r, ImageBoxMarkPen, ImageBoxMarkBrush) - } - - } - } - } - - case w32.WM_MOUSEMOVE: - x, y := genPoint(lparam) - - if iv.dragBox != nil { - if iv.resize == DirNone { - iv.drag(iv.dragBox, x, y) - iv.wasModified() - } else { - iv.resizeToDirection(iv.dragBox, x, y) - iv.wasModified() - } - iv.Invalidate(true) - - } else { - if !iv.add { - w32.SetCursor(w32.LoadCursorWithResourceID(0, iv.getCursor(x, y))) - } - // do not call repaint if underMouse item did not change. - if iv.updateHighlight(x, y) { - iv.Invalidate(true) - } - } - - if iv.mouseLeft { - internalTrackMouseEvent(iv.hwnd) - iv.mouseLeft = false - } - - case w32.WM_MOUSELEAVE: - iv.dragBox = nil - iv.mouseLeft = true - iv.updateHighlight(-1, -1) - iv.Invalidate(true) - - case w32.WM_LBUTTONUP: - iv.dragBox = nil - - case w32.WM_LBUTTONDOWN: - x, y := genPoint(lparam) - if iv.add { - now := time.Now() - s := fmt.Sprintf("field%s", now.Format("020405")) - b := &ImageBox{Name: s, underMouse: true, X: x, Y: y, X2: x + 150, Y2: y + 30} - iv.Boxes = append(iv.Boxes, b) - iv.selBox = b - iv.wasModified() - iv.onAdd.Fire(NewEvent(iv, nil)) - } else { - iv.dragBox = iv.isUnderMouse(x, y) - iv.selBox = iv.dragBox - iv.dragStartX, iv.dragStartY = x, y - iv.resize = iv.resizingDirection(iv.dragBox, x, y) - } - iv.Invalidate(true) - iv.onSelectedChange.Fire(NewEvent(iv, nil)) - - case w32.WM_RBUTTONDOWN: - - } - return w32.DefWindowProc(iv.hwnd, msg, wparam, lparam) -} diff --git a/v2/internal/frontend/desktop/windows/winc/init.go b/v2/internal/frontend/desktop/windows/winc/init.go deleted file mode 100644 index b0037f5aa..000000000 --- a/v2/internal/frontend/desktop/windows/winc/init.go +++ /dev/null @@ -1,21 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2013 Allen Dang. All Rights Reserved. - */ - -package winc - -import ( - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -func init() { - gControllerRegistry = make(map[w32.HWND]Controller) - gRegisteredClasses = make([]string, 0) - - var si w32.GdiplusStartupInput - si.GdiplusVersion = 1 - w32.GdiplusStartup(&si, nil) -} diff --git a/v2/internal/frontend/desktop/windows/winc/keyboard.go b/v2/internal/frontend/desktop/windows/winc/keyboard.go deleted file mode 100644 index 1f6369240..000000000 --- a/v2/internal/frontend/desktop/windows/winc/keyboard.go +++ /dev/null @@ -1,440 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2013 Allen Dang. All Rights Reserved. - */ - -package winc - -import ( - "bytes" - - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -type Key uint16 - -func (k Key) String() string { - return key2string[k] -} - -const ( - KeyLButton Key = w32.VK_LBUTTON - KeyRButton Key = w32.VK_RBUTTON - KeyCancel Key = w32.VK_CANCEL - KeyMButton Key = w32.VK_MBUTTON - KeyXButton1 Key = w32.VK_XBUTTON1 - KeyXButton2 Key = w32.VK_XBUTTON2 - KeyBack Key = w32.VK_BACK - KeyTab Key = w32.VK_TAB - KeyClear Key = w32.VK_CLEAR - KeyReturn Key = w32.VK_RETURN - KeyShift Key = w32.VK_SHIFT - KeyControl Key = w32.VK_CONTROL - KeyAlt Key = w32.VK_MENU - KeyMenu Key = w32.VK_MENU - KeyPause Key = w32.VK_PAUSE - KeyCapital Key = w32.VK_CAPITAL - KeyKana Key = w32.VK_KANA - KeyHangul Key = w32.VK_HANGUL - KeyJunja Key = w32.VK_JUNJA - KeyFinal Key = w32.VK_FINAL - KeyHanja Key = w32.VK_HANJA - KeyKanji Key = w32.VK_KANJI - KeyEscape Key = w32.VK_ESCAPE - KeyConvert Key = w32.VK_CONVERT - KeyNonconvert Key = w32.VK_NONCONVERT - KeyAccept Key = w32.VK_ACCEPT - KeyModeChange Key = w32.VK_MODECHANGE - KeySpace Key = w32.VK_SPACE - KeyPrior Key = w32.VK_PRIOR - KeyNext Key = w32.VK_NEXT - KeyEnd Key = w32.VK_END - KeyHome Key = w32.VK_HOME - KeyLeft Key = w32.VK_LEFT - KeyUp Key = w32.VK_UP - KeyRight Key = w32.VK_RIGHT - KeyDown Key = w32.VK_DOWN - KeySelect Key = w32.VK_SELECT - KeyPrint Key = w32.VK_PRINT - KeyExecute Key = w32.VK_EXECUTE - KeySnapshot Key = w32.VK_SNAPSHOT - KeyInsert Key = w32.VK_INSERT - KeyDelete Key = w32.VK_DELETE - KeyHelp Key = w32.VK_HELP - Key0 Key = 0x30 - Key1 Key = 0x31 - Key2 Key = 0x32 - Key3 Key = 0x33 - Key4 Key = 0x34 - Key5 Key = 0x35 - Key6 Key = 0x36 - Key7 Key = 0x37 - Key8 Key = 0x38 - Key9 Key = 0x39 - KeyA Key = 0x41 - KeyB Key = 0x42 - KeyC Key = 0x43 - KeyD Key = 0x44 - KeyE Key = 0x45 - KeyF Key = 0x46 - KeyG Key = 0x47 - KeyH Key = 0x48 - KeyI Key = 0x49 - KeyJ Key = 0x4A - KeyK Key = 0x4B - KeyL Key = 0x4C - KeyM Key = 0x4D - KeyN Key = 0x4E - KeyO Key = 0x4F - KeyP Key = 0x50 - KeyQ Key = 0x51 - KeyR Key = 0x52 - KeyS Key = 0x53 - KeyT Key = 0x54 - KeyU Key = 0x55 - KeyV Key = 0x56 - KeyW Key = 0x57 - KeyX Key = 0x58 - KeyY Key = 0x59 - KeyZ Key = 0x5A - KeyLWIN Key = w32.VK_LWIN - KeyRWIN Key = w32.VK_RWIN - KeyApps Key = w32.VK_APPS - KeySleep Key = w32.VK_SLEEP - KeyNumpad0 Key = w32.VK_NUMPAD0 - KeyNumpad1 Key = w32.VK_NUMPAD1 - KeyNumpad2 Key = w32.VK_NUMPAD2 - KeyNumpad3 Key = w32.VK_NUMPAD3 - KeyNumpad4 Key = w32.VK_NUMPAD4 - KeyNumpad5 Key = w32.VK_NUMPAD5 - KeyNumpad6 Key = w32.VK_NUMPAD6 - KeyNumpad7 Key = w32.VK_NUMPAD7 - KeyNumpad8 Key = w32.VK_NUMPAD8 - KeyNumpad9 Key = w32.VK_NUMPAD9 - KeyMultiply Key = w32.VK_MULTIPLY - KeyAdd Key = w32.VK_ADD - KeySeparator Key = w32.VK_SEPARATOR - KeySubtract Key = w32.VK_SUBTRACT - KeyDecimal Key = w32.VK_DECIMAL - KeyDivide Key = w32.VK_DIVIDE - KeyF1 Key = w32.VK_F1 - KeyF2 Key = w32.VK_F2 - KeyF3 Key = w32.VK_F3 - KeyF4 Key = w32.VK_F4 - KeyF5 Key = w32.VK_F5 - KeyF6 Key = w32.VK_F6 - KeyF7 Key = w32.VK_F7 - KeyF8 Key = w32.VK_F8 - KeyF9 Key = w32.VK_F9 - KeyF10 Key = w32.VK_F10 - KeyF11 Key = w32.VK_F11 - KeyF12 Key = w32.VK_F12 - KeyF13 Key = w32.VK_F13 - KeyF14 Key = w32.VK_F14 - KeyF15 Key = w32.VK_F15 - KeyF16 Key = w32.VK_F16 - KeyF17 Key = w32.VK_F17 - KeyF18 Key = w32.VK_F18 - KeyF19 Key = w32.VK_F19 - KeyF20 Key = w32.VK_F20 - KeyF21 Key = w32.VK_F21 - KeyF22 Key = w32.VK_F22 - KeyF23 Key = w32.VK_F23 - KeyF24 Key = w32.VK_F24 - KeyNumlock Key = w32.VK_NUMLOCK - KeyScroll Key = w32.VK_SCROLL - KeyLShift Key = w32.VK_LSHIFT - KeyRShift Key = w32.VK_RSHIFT - KeyLControl Key = w32.VK_LCONTROL - KeyRControl Key = w32.VK_RCONTROL - KeyLAlt Key = w32.VK_LMENU - KeyLMenu Key = w32.VK_LMENU - KeyRAlt Key = w32.VK_RMENU - KeyRMenu Key = w32.VK_RMENU - KeyBrowserBack Key = w32.VK_BROWSER_BACK - KeyBrowserForward Key = w32.VK_BROWSER_FORWARD - KeyBrowserRefresh Key = w32.VK_BROWSER_REFRESH - KeyBrowserStop Key = w32.VK_BROWSER_STOP - KeyBrowserSearch Key = w32.VK_BROWSER_SEARCH - KeyBrowserFavorites Key = w32.VK_BROWSER_FAVORITES - KeyBrowserHome Key = w32.VK_BROWSER_HOME - KeyVolumeMute Key = w32.VK_VOLUME_MUTE - KeyVolumeDown Key = w32.VK_VOLUME_DOWN - KeyVolumeUp Key = w32.VK_VOLUME_UP - KeyMediaNextTrack Key = w32.VK_MEDIA_NEXT_TRACK - KeyMediaPrevTrack Key = w32.VK_MEDIA_PREV_TRACK - KeyMediaStop Key = w32.VK_MEDIA_STOP - KeyMediaPlayPause Key = w32.VK_MEDIA_PLAY_PAUSE - KeyLaunchMail Key = w32.VK_LAUNCH_MAIL - KeyLaunchMediaSelect Key = w32.VK_LAUNCH_MEDIA_SELECT - KeyLaunchApp1 Key = w32.VK_LAUNCH_APP1 - KeyLaunchApp2 Key = w32.VK_LAUNCH_APP2 - KeyOEM1 Key = w32.VK_OEM_1 - KeyOEMPlus Key = w32.VK_OEM_PLUS - KeyOEMComma Key = w32.VK_OEM_COMMA - KeyOEMMinus Key = w32.VK_OEM_MINUS - KeyOEMPeriod Key = w32.VK_OEM_PERIOD - KeyOEM2 Key = w32.VK_OEM_2 - KeyOEM3 Key = w32.VK_OEM_3 - KeyOEM4 Key = w32.VK_OEM_4 - KeyOEM5 Key = w32.VK_OEM_5 - KeyOEM6 Key = w32.VK_OEM_6 - KeyOEM7 Key = w32.VK_OEM_7 - KeyOEM8 Key = w32.VK_OEM_8 - KeyOEM102 Key = w32.VK_OEM_102 - KeyProcessKey Key = w32.VK_PROCESSKEY - KeyPacket Key = w32.VK_PACKET - KeyAttn Key = w32.VK_ATTN - KeyCRSel Key = w32.VK_CRSEL - KeyEXSel Key = w32.VK_EXSEL - KeyErEOF Key = w32.VK_EREOF - KeyPlay Key = w32.VK_PLAY - KeyZoom Key = w32.VK_ZOOM - KeyNoName Key = w32.VK_NONAME - KeyPA1 Key = w32.VK_PA1 - KeyOEMClear Key = w32.VK_OEM_CLEAR -) - -var key2string = map[Key]string{ - KeyLButton: "LButton", - KeyRButton: "RButton", - KeyCancel: "Cancel", - KeyMButton: "MButton", - KeyXButton1: "XButton1", - KeyXButton2: "XButton2", - KeyBack: "Back", - KeyTab: "Tab", - KeyClear: "Clear", - KeyReturn: "Return", - KeyShift: "Shift", - KeyControl: "Control", - KeyAlt: "Alt / Menu", - KeyPause: "Pause", - KeyCapital: "Capital", - KeyKana: "Kana / Hangul", - KeyJunja: "Junja", - KeyFinal: "Final", - KeyHanja: "Hanja / Kanji", - KeyEscape: "Escape", - KeyConvert: "Convert", - KeyNonconvert: "Nonconvert", - KeyAccept: "Accept", - KeyModeChange: "ModeChange", - KeySpace: "Space", - KeyPrior: "Prior", - KeyNext: "Next", - KeyEnd: "End", - KeyHome: "Home", - KeyLeft: "Left", - KeyUp: "Up", - KeyRight: "Right", - KeyDown: "Down", - KeySelect: "Select", - KeyPrint: "Print", - KeyExecute: "Execute", - KeySnapshot: "Snapshot", - KeyInsert: "Insert", - KeyDelete: "Delete", - KeyHelp: "Help", - Key0: "0", - Key1: "1", - Key2: "2", - Key3: "3", - Key4: "4", - Key5: "5", - Key6: "6", - Key7: "7", - Key8: "8", - Key9: "9", - KeyA: "A", - KeyB: "B", - KeyC: "C", - KeyD: "D", - KeyE: "E", - KeyF: "F", - KeyG: "G", - KeyH: "H", - KeyI: "I", - KeyJ: "J", - KeyK: "K", - KeyL: "L", - KeyM: "M", - KeyN: "N", - KeyO: "O", - KeyP: "P", - KeyQ: "Q", - KeyR: "R", - KeyS: "S", - KeyT: "T", - KeyU: "U", - KeyV: "V", - KeyW: "W", - KeyX: "X", - KeyY: "Y", - KeyZ: "Z", - KeyLWIN: "LWIN", - KeyRWIN: "RWIN", - KeyApps: "Apps", - KeySleep: "Sleep", - KeyNumpad0: "Numpad0", - KeyNumpad1: "Numpad1", - KeyNumpad2: "Numpad2", - KeyNumpad3: "Numpad3", - KeyNumpad4: "Numpad4", - KeyNumpad5: "Numpad5", - KeyNumpad6: "Numpad6", - KeyNumpad7: "Numpad7", - KeyNumpad8: "Numpad8", - KeyNumpad9: "Numpad9", - KeyMultiply: "Multiply", - KeyAdd: "Add", - KeySeparator: "Separator", - KeySubtract: "Subtract", - KeyDecimal: "Decimal", - KeyDivide: "Divide", - KeyF1: "F1", - KeyF2: "F2", - KeyF3: "F3", - KeyF4: "F4", - KeyF5: "F5", - KeyF6: "F6", - KeyF7: "F7", - KeyF8: "F8", - KeyF9: "F9", - KeyF10: "F10", - KeyF11: "F11", - KeyF12: "F12", - KeyF13: "F13", - KeyF14: "F14", - KeyF15: "F15", - KeyF16: "F16", - KeyF17: "F17", - KeyF18: "F18", - KeyF19: "F19", - KeyF20: "F20", - KeyF21: "F21", - KeyF22: "F22", - KeyF23: "F23", - KeyF24: "F24", - KeyNumlock: "Numlock", - KeyScroll: "Scroll", - KeyLShift: "LShift", - KeyRShift: "RShift", - KeyLControl: "LControl", - KeyRControl: "RControl", - KeyLMenu: "LMenu", - KeyRMenu: "RMenu", - KeyBrowserBack: "BrowserBack", - KeyBrowserForward: "BrowserForward", - KeyBrowserRefresh: "BrowserRefresh", - KeyBrowserStop: "BrowserStop", - KeyBrowserSearch: "BrowserSearch", - KeyBrowserFavorites: "BrowserFavorites", - KeyBrowserHome: "BrowserHome", - KeyVolumeMute: "VolumeMute", - KeyVolumeDown: "VolumeDown", - KeyVolumeUp: "VolumeUp", - KeyMediaNextTrack: "MediaNextTrack", - KeyMediaPrevTrack: "MediaPrevTrack", - KeyMediaStop: "MediaStop", - KeyMediaPlayPause: "MediaPlayPause", - KeyLaunchMail: "LaunchMail", - KeyLaunchMediaSelect: "LaunchMediaSelect", - KeyLaunchApp1: "LaunchApp1", - KeyLaunchApp2: "LaunchApp2", - KeyOEM1: "OEM1", - KeyOEMPlus: "OEMPlus", - KeyOEMComma: "OEMComma", - KeyOEMMinus: "OEMMinus", - KeyOEMPeriod: "OEMPeriod", - KeyOEM2: "OEM2", - KeyOEM3: "OEM3", - KeyOEM4: "OEM4", - KeyOEM5: "OEM5", - KeyOEM6: "OEM6", - KeyOEM7: "OEM7", - KeyOEM8: "OEM8", - KeyOEM102: "OEM102", - KeyProcessKey: "ProcessKey", - KeyPacket: "Packet", - KeyAttn: "Attn", - KeyCRSel: "CRSel", - KeyEXSel: "EXSel", - KeyErEOF: "ErEOF", - KeyPlay: "Play", - KeyZoom: "Zoom", - KeyNoName: "NoName", - KeyPA1: "PA1", - KeyOEMClear: "OEMClear", -} - -type Modifiers byte - -func (m Modifiers) String() string { - return modifiers2string[m] -} - -var modifiers2string = map[Modifiers]string{ - ModShift: "Shift", - ModControl: "Ctrl", - ModControl | ModShift: "Ctrl+Shift", - ModAlt: "Alt", - ModAlt | ModShift: "Alt+Shift", - ModAlt | ModControl | ModShift: "Alt+Ctrl+Shift", -} - -const ( - ModShift Modifiers = 1 << iota - ModControl - ModAlt -) - -func ModifiersDown() Modifiers { - var m Modifiers - - if ShiftDown() { - m |= ModShift - } - if ControlDown() { - m |= ModControl - } - if AltDown() { - m |= ModAlt - } - - return m -} - -type Shortcut struct { - Modifiers Modifiers - Key Key -} - -func (s Shortcut) String() string { - m := s.Modifiers.String() - if m == "" { - return s.Key.String() - } - - b := new(bytes.Buffer) - - b.WriteString(m) - b.WriteRune('+') - b.WriteString(s.Key.String()) - - return b.String() -} - -func AltDown() bool { - return w32.GetKeyState(int32(KeyAlt))>>15 != 0 -} - -func ControlDown() bool { - return w32.GetKeyState(int32(KeyControl))>>15 != 0 -} - -func ShiftDown() bool { - return w32.GetKeyState(int32(KeyShift))>>15 != 0 -} diff --git a/v2/internal/frontend/desktop/windows/winc/label.go b/v2/internal/frontend/desktop/windows/winc/label.go deleted file mode 100644 index 6e441e9e2..000000000 --- a/v2/internal/frontend/desktop/windows/winc/label.go +++ /dev/null @@ -1,31 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - */ - -package winc - -import ( - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -type Label struct { - ControlBase -} - -func NewLabel(parent Controller) *Label { - lb := new(Label) - - lb.InitControl("STATIC", parent, 0, w32.WS_CHILD|w32.WS_VISIBLE|w32.SS_LEFTNOWORDWRAP) - RegMsgHandler(lb) - - lb.SetFont(DefaultFont) - lb.SetText("Label") - lb.SetSize(100, 25) - return lb -} - -func (lb *Label) WndProc(msg uint32, wparam, lparam uintptr) uintptr { - return w32.DefWindowProc(lb.hwnd, msg, wparam, lparam) -} diff --git a/v2/internal/frontend/desktop/windows/winc/layout.go b/v2/internal/frontend/desktop/windows/winc/layout.go deleted file mode 100644 index 7962dc726..000000000 --- a/v2/internal/frontend/desktop/windows/winc/layout.go +++ /dev/null @@ -1,222 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - */ - -package winc - -import ( - "encoding/json" - "fmt" - "io" - "os" - "sort" - "unsafe" - - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -// Dockable component must satisfy interface to be docked. -type Dockable interface { - Handle() w32.HWND - - Pos() (x, y int) - Width() int - Height() int - Visible() bool - - SetPos(x, y int) - SetSize(width, height int) - - OnMouseMove() *EventManager - OnLBUp() *EventManager -} - -// DockAllow is window, panel or other component that satisfies interface. -type DockAllow interface { - Handle() w32.HWND - ClientWidth() int - ClientHeight() int - SetLayout(mng LayoutManager) -} - -// Various layout managers -type Direction int - -const ( - Top Direction = iota - Bottom - Left - Right - Fill -) - -type LayoutControl struct { - child Dockable - dir Direction -} - -type LayoutControls []*LayoutControl - -type SimpleDock struct { - parent DockAllow - layoutCtl LayoutControls - loadedState bool -} - -// CtlState gets saved and loaded from json -type CtlState struct { - X, Y, Width, Height int -} - -type LayoutState struct { - WindowState string - Controls []*CtlState -} - -func (lc LayoutControls) Len() int { return len(lc) } -func (lc LayoutControls) Swap(i, j int) { lc[i], lc[j] = lc[j], lc[i] } -func (lc LayoutControls) Less(i, j int) bool { return lc[i].dir < lc[j].dir } - -func NewSimpleDock(parent DockAllow) *SimpleDock { - d := &SimpleDock{parent: parent} - parent.SetLayout(d) - return d -} - -// Layout management for the child controls. -func (sd *SimpleDock) Dock(child Dockable, dir Direction) { - sd.layoutCtl = append(sd.layoutCtl, &LayoutControl{child, dir}) -} - -// SaveState of the layout. Only works for Docks with parent set to main form. -func (sd *SimpleDock) SaveState(w io.Writer) error { - var ls LayoutState - - var wp w32.WINDOWPLACEMENT - wp.Length = uint32(unsafe.Sizeof(wp)) - if !w32.GetWindowPlacement(sd.parent.Handle(), &wp) { - return fmt.Errorf("GetWindowPlacement failed") - } - - ls.WindowState = fmt.Sprint( - wp.Flags, wp.ShowCmd, - wp.PtMinPosition.X, wp.PtMinPosition.Y, - wp.PtMaxPosition.X, wp.PtMaxPosition.Y, - wp.RcNormalPosition.Left, wp.RcNormalPosition.Top, - wp.RcNormalPosition.Right, wp.RcNormalPosition.Bottom) - - for _, c := range sd.layoutCtl { - x, y := c.child.Pos() - w, h := c.child.Width(), c.child.Height() - - ctl := &CtlState{X: x, Y: y, Width: w, Height: h} - ls.Controls = append(ls.Controls, ctl) - } - - if err := json.NewEncoder(w).Encode(ls); err != nil { - return err - } - - return nil -} - -// LoadState of the layout. Only works for Docks with parent set to main form. -func (sd *SimpleDock) LoadState(r io.Reader) error { - var ls LayoutState - - if err := json.NewDecoder(r).Decode(&ls); err != nil { - return err - } - - var wp w32.WINDOWPLACEMENT - if _, err := fmt.Sscan(ls.WindowState, - &wp.Flags, &wp.ShowCmd, - &wp.PtMinPosition.X, &wp.PtMinPosition.Y, - &wp.PtMaxPosition.X, &wp.PtMaxPosition.Y, - &wp.RcNormalPosition.Left, &wp.RcNormalPosition.Top, - &wp.RcNormalPosition.Right, &wp.RcNormalPosition.Bottom); err != nil { - return err - } - wp.Length = uint32(unsafe.Sizeof(wp)) - - if !w32.SetWindowPlacement(sd.parent.Handle(), &wp) { - return fmt.Errorf("SetWindowPlacement failed") - } - - // if number of controls in the saved layout does not match - // current number on screen - something changed and we do not reload - // rest of control sizes from json - if len(sd.layoutCtl) != len(ls.Controls) { - return nil - } - - for i, c := range sd.layoutCtl { - c.child.SetPos(ls.Controls[i].X, ls.Controls[i].Y) - c.child.SetSize(ls.Controls[i].Width, ls.Controls[i].Height) - } - return nil -} - -// SaveStateFile convenience function. -func (sd *SimpleDock) SaveStateFile(file string) error { - f, err := os.Create(file) - if err != nil { - return err - } - return sd.SaveState(f) -} - -// LoadStateFile loads state ignores error if file is not found. -func (sd *SimpleDock) LoadStateFile(file string) error { - f, err := os.Open(file) - if err != nil { - return nil // if file is not found or not accessible ignore it - } - return sd.LoadState(f) -} - -// Update is called to resize child items based on layout directions. -func (sd *SimpleDock) Update() { - sort.Stable(sd.layoutCtl) - - x, y := 0, 0 - w, h := sd.parent.ClientWidth(), sd.parent.ClientHeight() - winw, winh := w, h - - for _, c := range sd.layoutCtl { - // Non visible controls do not preserve space. - if !c.child.Visible() { - continue - } - - switch c.dir { - case Top: - c.child.SetPos(x, y) - c.child.SetSize(w, c.child.Height()) - h -= c.child.Height() - y += c.child.Height() - case Bottom: - c.child.SetPos(x, winh-c.child.Height()) - c.child.SetSize(w, c.child.Height()) - h -= c.child.Height() - winh -= c.child.Height() - case Left: - c.child.SetPos(x, y) - c.child.SetSize(c.child.Width(), h) - w -= c.child.Width() - x += c.child.Width() - case Right: - c.child.SetPos(winw-c.child.Width(), y) - c.child.SetSize(c.child.Width(), h) - w -= c.child.Width() - winw -= c.child.Width() - case Fill: - // fill available space - c.child.SetPos(x, y) - c.child.SetSize(w, h) - } - //c.child.Invalidate(true) - } -} diff --git a/v2/internal/frontend/desktop/windows/winc/listview.go b/v2/internal/frontend/desktop/windows/winc/listview.go deleted file mode 100644 index 8edfd1c11..000000000 --- a/v2/internal/frontend/desktop/windows/winc/listview.go +++ /dev/null @@ -1,549 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - */ - -package winc - -import ( - "errors" - "fmt" - "syscall" - "unsafe" - - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -// ListItem represents an item in a ListView widget. -type ListItem interface { - Text() []string // Text returns the text of the multi-column item. - ImageIndex() int // ImageIndex is used only if SetImageList is called on the listview -} - -// ListItemChecker is used for checkbox support in ListView. -type ListItemChecker interface { - Checked() bool - SetChecked(checked bool) -} - -// ListItemSetter is used in OnEndLabelEdit event. -type ListItemSetter interface { - SetText(s string) // set first item in the array via LabelEdit event -} - -// StringListItem is helper for basic string lists. -type StringListItem struct { - ID int - Data string - Check bool -} - -func (s StringListItem) Text() []string { return []string{s.Data} } -func (s StringListItem) Checked() bool { return s.Check } -func (s StringListItem) SetChecked(checked bool) { s.Check = checked } -func (s StringListItem) ImageIndex() int { return 0 } - -type ListView struct { - ControlBase - - iml *ImageList - lastIndex int - cols int // count of columns - - item2Handle map[ListItem]uintptr - handle2Item map[uintptr]ListItem - - onEndLabelEdit EventManager - onDoubleClick EventManager - onClick EventManager - onKeyDown EventManager - onItemChanging EventManager - onItemChanged EventManager - onCheckChanged EventManager - onViewChange EventManager - onEndScroll EventManager -} - -func NewListView(parent Controller) *ListView { - lv := new(ListView) - - lv.InitControl("SysListView32", parent /*w32.WS_EX_CLIENTEDGE*/, 0, - w32.WS_CHILD|w32.WS_VISIBLE|w32.WS_TABSTOP|w32.LVS_REPORT|w32.LVS_EDITLABELS|w32.LVS_SHOWSELALWAYS) - - lv.item2Handle = make(map[ListItem]uintptr) - lv.handle2Item = make(map[uintptr]ListItem) - - RegMsgHandler(lv) - - lv.SetFont(DefaultFont) - lv.SetSize(200, 400) - - if err := lv.SetTheme("Explorer"); err != nil { - // theme error is ignored - } - return lv -} - -// FIXME: Changes the state of an item in a list-view control. Refer LVM_SETITEMSTATE message. -func (lv *ListView) setItemState(i int, state, mask uint) { - var item w32.LVITEM - item.State, item.StateMask = uint32(state), uint32(mask) - w32.SendMessage(lv.hwnd, w32.LVM_SETITEMSTATE, uintptr(i), uintptr(unsafe.Pointer(&item))) -} - -func (lv *ListView) EnableSingleSelect(enable bool) { - SetStyle(lv.hwnd, enable, w32.LVS_SINGLESEL) -} - -func (lv *ListView) EnableSortHeader(enable bool) { - SetStyle(lv.hwnd, enable, w32.LVS_NOSORTHEADER) -} - -func (lv *ListView) EnableSortAscending(enable bool) { - SetStyle(lv.hwnd, enable, w32.LVS_SORTASCENDING) -} - -func (lv *ListView) EnableEditLabels(enable bool) { - SetStyle(lv.hwnd, enable, w32.LVS_EDITLABELS) -} - -func (lv *ListView) EnableFullRowSelect(enable bool) { - if enable { - w32.SendMessage(lv.hwnd, w32.LVM_SETEXTENDEDLISTVIEWSTYLE, 0, w32.LVS_EX_FULLROWSELECT) - } else { - w32.SendMessage(lv.hwnd, w32.LVM_SETEXTENDEDLISTVIEWSTYLE, w32.LVS_EX_FULLROWSELECT, 0) - } -} - -func (lv *ListView) EnableDoubleBuffer(enable bool) { - if enable { - w32.SendMessage(lv.hwnd, w32.LVM_SETEXTENDEDLISTVIEWSTYLE, 0, w32.LVS_EX_DOUBLEBUFFER) - } else { - w32.SendMessage(lv.hwnd, w32.LVM_SETEXTENDEDLISTVIEWSTYLE, w32.LVS_EX_DOUBLEBUFFER, 0) - } -} - -func (lv *ListView) EnableHotTrack(enable bool) { - if enable { - w32.SendMessage(lv.hwnd, w32.LVM_SETEXTENDEDLISTVIEWSTYLE, 0, w32.LVS_EX_TRACKSELECT) - } else { - w32.SendMessage(lv.hwnd, w32.LVM_SETEXTENDEDLISTVIEWSTYLE, w32.LVS_EX_TRACKSELECT, 0) - } -} - -func (lv *ListView) SetItemCount(count int) bool { - return w32.SendMessage(lv.hwnd, w32.LVM_SETITEMCOUNT, uintptr(count), 0) != 0 -} - -func (lv *ListView) ItemCount() int { - return int(w32.SendMessage(lv.hwnd, w32.LVM_GETITEMCOUNT, 0, 0)) -} - -func (lv *ListView) ItemAt(x, y int) ListItem { - hti := w32.LVHITTESTINFO{Pt: w32.POINT{int32(x), int32(y)}} - w32.SendMessage(lv.hwnd, w32.LVM_HITTEST, 0, uintptr(unsafe.Pointer(&hti))) - return lv.findItemByIndex(int(hti.IItem)) -} - -func (lv *ListView) Items() (list []ListItem) { - for item := range lv.item2Handle { - list = append(list, item) - } - return list -} - -func (lv *ListView) AddColumn(caption string, width int) { - var lc w32.LVCOLUMN - lc.Mask = w32.LVCF_TEXT - if width != 0 { - lc.Mask = lc.Mask | w32.LVCF_WIDTH - lc.Cx = int32(width) - } - lc.PszText = syscall.StringToUTF16Ptr(caption) - lv.insertLvColumn(&lc, lv.cols) - lv.cols++ -} - -// StretchLastColumn makes the last column take up all remaining horizontal -// space of the *ListView. -// The effect of this is not persistent. -func (lv *ListView) StretchLastColumn() error { - if lv.cols == 0 { - return nil - } - if w32.SendMessage(lv.hwnd, w32.LVM_SETCOLUMNWIDTH, uintptr(lv.cols-1), w32.LVSCW_AUTOSIZE_USEHEADER) == 0 { - //panic("LVM_SETCOLUMNWIDTH failed") - } - return nil -} - -// CheckBoxes returns if the *TableView has check boxes. -func (lv *ListView) CheckBoxes() bool { - return w32.SendMessage(lv.hwnd, w32.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0)&w32.LVS_EX_CHECKBOXES > 0 -} - -// SetCheckBoxes sets if the *TableView has check boxes. -func (lv *ListView) SetCheckBoxes(value bool) { - exStyle := w32.SendMessage(lv.hwnd, w32.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0) - oldStyle := exStyle - if value { - exStyle |= w32.LVS_EX_CHECKBOXES - } else { - exStyle &^= w32.LVS_EX_CHECKBOXES - } - if exStyle != oldStyle { - w32.SendMessage(lv.hwnd, w32.LVM_SETEXTENDEDLISTVIEWSTYLE, 0, exStyle) - } - - mask := w32.SendMessage(lv.hwnd, w32.LVM_GETCALLBACKMASK, 0, 0) - if value { - mask |= w32.LVIS_STATEIMAGEMASK - } else { - mask &^= w32.LVIS_STATEIMAGEMASK - } - - if w32.SendMessage(lv.hwnd, w32.LVM_SETCALLBACKMASK, mask, 0) == w32.FALSE { - panic("SendMessage(LVM_SETCALLBACKMASK)") - } -} - -func (lv *ListView) applyImage(lc *w32.LVITEM, imIndex int) { - if lv.iml != nil { - lc.Mask |= w32.LVIF_IMAGE - lc.IImage = int32(imIndex) - } -} - -func (lv *ListView) AddItem(item ListItem) { - lv.InsertItem(item, lv.ItemCount()) -} - -func (lv *ListView) InsertItem(item ListItem, index int) { - text := item.Text() - li := &w32.LVITEM{ - Mask: w32.LVIF_TEXT | w32.LVIF_PARAM, - PszText: syscall.StringToUTF16Ptr(text[0]), - IItem: int32(index), - } - - lv.lastIndex++ - ix := new(int) - *ix = lv.lastIndex - li.LParam = uintptr(*ix) - lv.handle2Item[li.LParam] = item - lv.item2Handle[item] = li.LParam - - lv.applyImage(li, item.ImageIndex()) - lv.insertLvItem(li) - - for i := 1; i < len(text); i++ { - li.Mask = w32.LVIF_TEXT - li.PszText = syscall.StringToUTF16Ptr(text[i]) - li.ISubItem = int32(i) - lv.setLvItem(li) - } -} - -func (lv *ListView) UpdateItem(item ListItem) bool { - lparam, ok := lv.item2Handle[item] - if !ok { - return false - } - - index := lv.findIndexByItem(item) - if index == -1 { - return false - } - - text := item.Text() - li := &w32.LVITEM{ - Mask: w32.LVIF_TEXT | w32.LVIF_PARAM, - PszText: syscall.StringToUTF16Ptr(text[0]), - LParam: lparam, - IItem: int32(index), - } - - lv.applyImage(li, item.ImageIndex()) - lv.setLvItem(li) - - for i := 1; i < len(text); i++ { - li.Mask = w32.LVIF_TEXT - li.PszText = syscall.StringToUTF16Ptr(text[i]) - li.ISubItem = int32(i) - lv.setLvItem(li) - } - return true -} - -func (lv *ListView) insertLvColumn(lvColumn *w32.LVCOLUMN, iCol int) { - w32.SendMessage(lv.hwnd, w32.LVM_INSERTCOLUMN, uintptr(iCol), uintptr(unsafe.Pointer(lvColumn))) -} - -func (lv *ListView) insertLvItem(lvItem *w32.LVITEM) { - w32.SendMessage(lv.hwnd, w32.LVM_INSERTITEM, 0, uintptr(unsafe.Pointer(lvItem))) -} - -func (lv *ListView) setLvItem(lvItem *w32.LVITEM) { - w32.SendMessage(lv.hwnd, w32.LVM_SETITEM, 0, uintptr(unsafe.Pointer(lvItem))) -} - -func (lv *ListView) DeleteAllItems() bool { - if w32.SendMessage(lv.hwnd, w32.LVM_DELETEALLITEMS, 0, 0) == w32.TRUE { - lv.item2Handle = make(map[ListItem]uintptr) - lv.handle2Item = make(map[uintptr]ListItem) - return true - } - return false -} - -func (lv *ListView) DeleteItem(item ListItem) error { - index := lv.findIndexByItem(item) - if index == -1 { - return errors.New("item not found") - } - - if w32.SendMessage(lv.hwnd, w32.LVM_DELETEITEM, uintptr(index), 0) == 0 { - return errors.New("SendMessage(TVM_DELETEITEM) failed") - } - - h := lv.item2Handle[item] - delete(lv.item2Handle, item) - delete(lv.handle2Item, h) - return nil -} - -func (lv *ListView) findIndexByItem(item ListItem) int { - lparam, ok := lv.item2Handle[item] - if !ok { - return -1 - } - - it := &w32.LVFINDINFO{ - Flags: w32.LVFI_PARAM, - LParam: lparam, - } - var i int = -1 - return int(w32.SendMessage(lv.hwnd, w32.LVM_FINDITEM, uintptr(i), uintptr(unsafe.Pointer(it)))) -} - -func (lv *ListView) findItemByIndex(i int) ListItem { - it := &w32.LVITEM{ - Mask: w32.LVIF_PARAM, - IItem: int32(i), - } - - if w32.SendMessage(lv.hwnd, w32.LVM_GETITEM, 0, uintptr(unsafe.Pointer(it))) == w32.TRUE { - if item, ok := lv.handle2Item[it.LParam]; ok { - return item - } - } - return nil -} - -func (lv *ListView) EnsureVisible(item ListItem) bool { - if i := lv.findIndexByItem(item); i != -1 { - return w32.SendMessage(lv.hwnd, w32.LVM_ENSUREVISIBLE, uintptr(i), 1) == 0 - } - return false -} - -func (lv *ListView) SelectedItem() ListItem { - if items := lv.SelectedItems(); len(items) > 0 { - return items[0] - } - return nil -} - -func (lv *ListView) SetSelectedItem(item ListItem) bool { - if i := lv.findIndexByItem(item); i > -1 { - lv.SetSelectedIndex(i) - return true - } - return false -} - -// mask is used to set the LVITEM.Mask for ListView.GetItem which indicates which attributes you'd like to receive -// of LVITEM. -func (lv *ListView) SelectedItems() []ListItem { - var items []ListItem - - var i int = -1 - for { - if i = int(w32.SendMessage(lv.hwnd, w32.LVM_GETNEXTITEM, uintptr(i), uintptr(w32.LVNI_SELECTED))); i == -1 { - break - } - - if item := lv.findItemByIndex(i); item != nil { - items = append(items, item) - } - } - return items -} - -func (lv *ListView) SelectedCount() uint { - return uint(w32.SendMessage(lv.hwnd, w32.LVM_GETSELECTEDCOUNT, 0, 0)) -} - -// GetSelectedIndex first selected item index. Returns -1 if no item is selected. -func (lv *ListView) SelectedIndex() int { - var i int = -1 - return int(w32.SendMessage(lv.hwnd, w32.LVM_GETNEXTITEM, uintptr(i), uintptr(w32.LVNI_SELECTED))) -} - -// Set i to -1 to select all items. -func (lv *ListView) SetSelectedIndex(i int) { - lv.setItemState(i, w32.LVIS_SELECTED, w32.LVIS_SELECTED) -} - -func (lv *ListView) SetImageList(imageList *ImageList) { - w32.SendMessage(lv.hwnd, w32.LVM_SETIMAGELIST, w32.LVSIL_SMALL, uintptr(imageList.Handle())) - lv.iml = imageList -} - -// Event publishers -func (lv *ListView) OnEndLabelEdit() *EventManager { - return &lv.onEndLabelEdit -} - -func (lv *ListView) OnDoubleClick() *EventManager { - return &lv.onDoubleClick -} - -func (lv *ListView) OnClick() *EventManager { - return &lv.onClick -} - -func (lv *ListView) OnKeyDown() *EventManager { - return &lv.onKeyDown -} - -func (lv *ListView) OnItemChanging() *EventManager { - return &lv.onItemChanging -} - -func (lv *ListView) OnItemChanged() *EventManager { - return &lv.onItemChanged -} - -func (lv *ListView) OnCheckChanged() *EventManager { - return &lv.onCheckChanged -} - -func (lv *ListView) OnViewChange() *EventManager { - return &lv.onViewChange -} - -func (lv *ListView) OnEndScroll() *EventManager { - return &lv.onEndScroll -} - -// Message processor -func (lv *ListView) WndProc(msg uint32, wparam, lparam uintptr) uintptr { - switch msg { - /*case w32.WM_ERASEBKGND: - lv.StretchLastColumn() - println("case w32.WM_ERASEBKGND") - return 1*/ - - case w32.WM_NOTIFY: - nm := (*w32.NMHDR)(unsafe.Pointer(lparam)) - code := int32(nm.Code) - - switch code { - case w32.LVN_BEGINLABELEDITW: - // println("Begin label edit") - case w32.LVN_ENDLABELEDITW: - nmdi := (*w32.NMLVDISPINFO)(unsafe.Pointer(lparam)) - if nmdi.Item.PszText != nil { - fmt.Println(nmdi.Item.PszText, nmdi.Item) - if item, ok := lv.handle2Item[nmdi.Item.LParam]; ok { - lv.onEndLabelEdit.Fire(NewEvent(lv, - &LabelEditEventData{Item: item, - Text: w32.UTF16PtrToString(nmdi.Item.PszText)})) - } - return w32.TRUE - } - case w32.NM_DBLCLK: - lv.onDoubleClick.Fire(NewEvent(lv, nil)) - - case w32.NM_CLICK: - ac := (*w32.NMITEMACTIVATE)(unsafe.Pointer(lparam)) - var hti w32.LVHITTESTINFO - hti.Pt = w32.POINT{ac.PtAction.X, ac.PtAction.Y} - w32.SendMessage(lv.hwnd, w32.LVM_HITTEST, 0, uintptr(unsafe.Pointer(&hti))) - - if hti.Flags == w32.LVHT_ONITEMSTATEICON { - if item := lv.findItemByIndex(int(hti.IItem)); item != nil { - if item, ok := item.(ListItemChecker); ok { - checked := !item.Checked() - item.SetChecked(checked) - lv.onCheckChanged.Fire(NewEvent(lv, item)) - - if w32.SendMessage(lv.hwnd, w32.LVM_UPDATE, uintptr(hti.IItem), 0) == w32.FALSE { - panic("SendMessage(LVM_UPDATE)") - } - } - } - } - - hti.Pt = w32.POINT{ac.PtAction.X, ac.PtAction.Y} - w32.SendMessage(lv.hwnd, w32.LVM_SUBITEMHITTEST, 0, uintptr(unsafe.Pointer(&hti))) - lv.onClick.Fire(NewEvent(lv, hti.ISubItem)) - - case w32.LVN_KEYDOWN: - nmkey := (*w32.NMLVKEYDOWN)(unsafe.Pointer(lparam)) - if nmkey.WVKey == w32.VK_SPACE && lv.CheckBoxes() { - if item := lv.SelectedItem(); item != nil { - if item, ok := item.(ListItemChecker); ok { - checked := !item.Checked() - item.SetChecked(checked) - lv.onCheckChanged.Fire(NewEvent(lv, item)) - } - - index := lv.findIndexByItem(item) - if w32.SendMessage(lv.hwnd, w32.LVM_UPDATE, uintptr(index), 0) == w32.FALSE { - panic("SendMessage(LVM_UPDATE)") - } - } - } - lv.onKeyDown.Fire(NewEvent(lv, nmkey.WVKey)) - key := nmkey.WVKey - w32.SendMessage(lv.Parent().Handle(), w32.WM_KEYDOWN, uintptr(key), 0) - - case w32.LVN_ITEMCHANGING: - // This event also fires when listview has changed via code. - nmlv := (*w32.NMLISTVIEW)(unsafe.Pointer(lparam)) - item := lv.findItemByIndex(int(nmlv.IItem)) - lv.onItemChanging.Fire(NewEvent(lv, item)) - - case w32.LVN_ITEMCHANGED: - // This event also fires when listview has changed via code. - nmlv := (*w32.NMLISTVIEW)(unsafe.Pointer(lparam)) - item := lv.findItemByIndex(int(nmlv.IItem)) - lv.onItemChanged.Fire(NewEvent(lv, item)) - - case w32.LVN_GETDISPINFO: - nmdi := (*w32.NMLVDISPINFO)(unsafe.Pointer(lparam)) - if nmdi.Item.StateMask&w32.LVIS_STATEIMAGEMASK > 0 { - if item, ok := lv.handle2Item[nmdi.Item.LParam]; ok { - if item, ok := item.(ListItemChecker); ok { - - checked := item.Checked() - if checked { - nmdi.Item.State = 0x2000 - } else { - nmdi.Item.State = 0x1000 - } - } - } - } - - lv.onViewChange.Fire(NewEvent(lv, nil)) - - case w32.LVN_ENDSCROLL: - lv.onEndScroll.Fire(NewEvent(lv, nil)) - } - } - return w32.DefWindowProc(lv.hwnd, msg, wparam, lparam) -} diff --git a/v2/internal/frontend/desktop/windows/winc/menu.go b/v2/internal/frontend/desktop/windows/winc/menu.go deleted file mode 100644 index d1567e648..000000000 --- a/v2/internal/frontend/desktop/windows/winc/menu.go +++ /dev/null @@ -1,339 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - */ - -package winc - -import ( - "fmt" - "syscall" - "unsafe" - - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -var ( - nextMenuItemID uint16 = 3 - actionsByID = make(map[uint16]*MenuItem) - shortcut2Action = make(map[Shortcut]*MenuItem) - menuItems = make(map[w32.HMENU][]*MenuItem) - radioGroups = make(map[*MenuItem]*RadioGroup) - initialised bool -) - -var NoShortcut = Shortcut{} - -// Menu for main window and context menus on controls. -// Most methods used for both main window menu and context menu. -type Menu struct { - hMenu w32.HMENU - hwnd w32.HWND // hwnd might be nil if it is context menu. -} - -type MenuItem struct { - hMenu w32.HMENU - hSubMenu w32.HMENU // Non zero if this item is in itself a submenu. - - text string - toolTip string - image *Bitmap - shortcut Shortcut - enabled bool - - checkable bool - checked bool - isRadio bool - - id uint16 - - onClick EventManager -} - -type RadioGroup struct { - members []*MenuItem - hwnd w32.HWND -} - -func NewContextMenu() *MenuItem { - hMenu := w32.CreatePopupMenu() - if hMenu == 0 { - panic("failed CreateMenu") - } - - item := &MenuItem{ - hMenu: hMenu, - hSubMenu: hMenu, - } - return item -} - -func (m *Menu) Dispose() { - if m.hMenu != 0 { - w32.DestroyMenu(m.hMenu) - m.hMenu = 0 - } -} - -func (m *Menu) IsDisposed() bool { - return m.hMenu == 0 -} - -func initMenuItemInfoFromAction(mii *w32.MENUITEMINFO, a *MenuItem) { - mii.CbSize = uint32(unsafe.Sizeof(*mii)) - mii.FMask = w32.MIIM_FTYPE | w32.MIIM_ID | w32.MIIM_STATE | w32.MIIM_STRING - if a.image != nil { - mii.FMask |= w32.MIIM_BITMAP - mii.HbmpItem = a.image.handle - } - if a.IsSeparator() { - mii.FType = w32.MFT_SEPARATOR - } else { - mii.FType = w32.MFT_STRING - var text string - if s := a.shortcut; s.Key != 0 { - text = fmt.Sprintf("%s\t%s", a.text, s.String()) - shortcut2Action[a.shortcut] = a - } else { - text = a.text - } - mii.DwTypeData = syscall.StringToUTF16Ptr(text) - mii.Cch = uint32(len([]rune(a.text))) - } - mii.WID = uint32(a.id) - - if a.Enabled() { - mii.FState &^= w32.MFS_DISABLED - } else { - mii.FState |= w32.MFS_DISABLED - } - - if a.Checkable() { - mii.FMask |= w32.MIIM_CHECKMARKS - } - if a.Checked() { - mii.FState |= w32.MFS_CHECKED - } - - if a.hSubMenu != 0 { - mii.FMask |= w32.MIIM_SUBMENU - mii.HSubMenu = a.hSubMenu - } -} - -// Show menu on the main window. -func (m *Menu) Show() { - initialised = true - updateRadioGroups() - if !w32.DrawMenuBar(m.hwnd) { - panic("DrawMenuBar failed") - } -} - -// AddSubMenu returns item that is used as submenu to perform AddItem(s). -func (m *Menu) AddSubMenu(text string) *MenuItem { - hSubMenu := w32.CreateMenu() - if hSubMenu == 0 { - panic("failed CreateMenu") - } - return addMenuItem(m.hMenu, hSubMenu, text, Shortcut{}, nil, false) -} - -// This method will iterate through the menu items, group radio items together, build a -// quick access map and set the initial items -func updateRadioGroups() { - - if !initialised { - return - } - - radioItemsChecked := []*MenuItem{} - radioGroups = make(map[*MenuItem]*RadioGroup) - var currentRadioGroupMembers []*MenuItem - // Iterate the menus - for _, menu := range menuItems { - menuLength := len(menu) - for index, menuItem := range menu { - if menuItem.isRadio { - currentRadioGroupMembers = append(currentRadioGroupMembers, menuItem) - if menuItem.checked { - radioItemsChecked = append(radioItemsChecked, menuItem) - } - - // If end of menu - if index == menuLength-1 { - radioGroup := &RadioGroup{ - members: currentRadioGroupMembers, - hwnd: menuItem.hMenu, - } - // Save the group to each member iin the radiomap - for _, member := range currentRadioGroupMembers { - radioGroups[member] = radioGroup - } - currentRadioGroupMembers = []*MenuItem{} - } - continue - } - - // Not a radio item - if len(currentRadioGroupMembers) > 0 { - radioGroup := &RadioGroup{ - members: currentRadioGroupMembers, - hwnd: menuItem.hMenu, - } - // Save the group to each member iin the radiomap - for _, member := range currentRadioGroupMembers { - radioGroups[member] = radioGroup - } - currentRadioGroupMembers = []*MenuItem{} - } - } - } - - // Enable the checked items - for _, item := range radioItemsChecked { - radioGroup := radioGroups[item] - startID := radioGroup.members[0].id - endID := radioGroup.members[len(radioGroup.members)-1].id - w32.SelectRadioMenuItem(item.id, startID, endID, radioGroup.hwnd) - } - -} - -func (mi *MenuItem) OnClick() *EventManager { - return &mi.onClick -} - -func (mi *MenuItem) AddSeparator() { - addMenuItem(mi.hSubMenu, 0, "-", Shortcut{}, nil, false) -} - -// AddItem adds plain menu item. -func (mi *MenuItem) AddItem(text string, shortcut Shortcut) *MenuItem { - return addMenuItem(mi.hSubMenu, 0, text, shortcut, nil, false) -} - -// AddItemCheckable adds plain menu item that can have a checkmark. -func (mi *MenuItem) AddItemCheckable(text string, shortcut Shortcut) *MenuItem { - return addMenuItem(mi.hSubMenu, 0, text, shortcut, nil, true) -} - -// AddItemRadio adds plain menu item that can have a checkmark and is part of a radio group. -func (mi *MenuItem) AddItemRadio(text string, shortcut Shortcut) *MenuItem { - menuItem := addMenuItem(mi.hSubMenu, 0, text, shortcut, nil, true) - menuItem.isRadio = true - return menuItem -} - -// AddItemWithBitmap adds menu item with shortcut and bitmap. -func (mi *MenuItem) AddItemWithBitmap(text string, shortcut Shortcut, image *Bitmap) *MenuItem { - return addMenuItem(mi.hSubMenu, 0, text, shortcut, image, false) -} - -// AddSubMenu adds a submenu. -func (mi *MenuItem) AddSubMenu(text string) *MenuItem { - hSubMenu := w32.CreatePopupMenu() - if hSubMenu == 0 { - panic("failed CreatePopupMenu") - } - return addMenuItem(mi.hSubMenu, hSubMenu, text, Shortcut{}, nil, false) -} - -// AddItem to the menu, set text to "-" for separators. -func addMenuItem(hMenu, hSubMenu w32.HMENU, text string, shortcut Shortcut, image *Bitmap, checkable bool) *MenuItem { - item := &MenuItem{ - hMenu: hMenu, - hSubMenu: hSubMenu, - text: text, - shortcut: shortcut, - image: image, - enabled: true, - id: nextMenuItemID, - checkable: checkable, - isRadio: false, - //visible: true, - } - nextMenuItemID++ - actionsByID[item.id] = item - menuItems[hMenu] = append(menuItems[hMenu], item) - - var mii w32.MENUITEMINFO - initMenuItemInfoFromAction(&mii, item) - - index := -1 - if !w32.InsertMenuItem(hMenu, uint32(index), true, &mii) { - panic("InsertMenuItem failed") - } - return item -} - -func indexInObserver(a *MenuItem) int { - var idx int - for _, mi := range menuItems[a.hMenu] { - if mi == a { - return idx - } - idx++ - } - return -1 -} - -func findMenuItemByID(id int) *MenuItem { - return actionsByID[uint16(id)] -} - -func (mi *MenuItem) update() { - var mii w32.MENUITEMINFO - initMenuItemInfoFromAction(&mii, mi) - - if !w32.SetMenuItemInfo(mi.hMenu, uint32(indexInObserver(mi)), true, &mii) { - panic("SetMenuItemInfo failed") - } - if mi.isRadio { - mi.updateRadioGroup() - } -} - -func (mi *MenuItem) IsSeparator() bool { return mi.text == "-" } -func (mi *MenuItem) SetSeparator() { mi.text = "-" } - -func (mi *MenuItem) Enabled() bool { return mi.enabled } -func (mi *MenuItem) SetEnabled(b bool) { mi.enabled = b; mi.update() } - -func (mi *MenuItem) Checkable() bool { return mi.checkable } -func (mi *MenuItem) SetCheckable(b bool) { mi.checkable = b; mi.update() } - -func (mi *MenuItem) Checked() bool { return mi.checked } -func (mi *MenuItem) SetChecked(b bool) { - if mi.isRadio { - radioGroup := radioGroups[mi] - if radioGroup != nil { - for _, member := range radioGroup.members { - member.checked = false - } - } - - } - mi.checked = b - mi.update() -} - -func (mi *MenuItem) Text() string { return mi.text } -func (mi *MenuItem) SetText(s string) { mi.text = s; mi.update() } - -func (mi *MenuItem) Image() *Bitmap { return mi.image } -func (mi *MenuItem) SetImage(b *Bitmap) { mi.image = b; mi.update() } - -func (mi *MenuItem) ToolTip() string { return mi.toolTip } -func (mi *MenuItem) SetToolTip(s string) { mi.toolTip = s; mi.update() } - -func (mi *MenuItem) updateRadioGroup() { - radioGroup := radioGroups[mi] - if radioGroup == nil { - return - } - startID := radioGroup.members[0].id - endID := radioGroup.members[len(radioGroup.members)-1].id - w32.SelectRadioMenuItem(mi.id, startID, endID, radioGroup.hwnd) -} diff --git a/v2/internal/frontend/desktop/windows/winc/mousecontrol.go b/v2/internal/frontend/desktop/windows/winc/mousecontrol.go deleted file mode 100644 index 2b89dd307..000000000 --- a/v2/internal/frontend/desktop/windows/winc/mousecontrol.go +++ /dev/null @@ -1,50 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - */ - -package winc - -import ( - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -// MouseControl used for creating custom controls that need mouse hover or mouse leave events. -type MouseControl struct { - ControlBase - isMouseLeft bool -} - -func (cc *MouseControl) Init(parent Controller, className string, exStyle, style uint) { - RegClassOnlyOnce(className) - cc.hwnd = CreateWindow(className, parent, exStyle, style) - cc.parent = parent - RegMsgHandler(cc) - - cc.isMouseLeft = true - cc.SetFont(DefaultFont) -} - -func (cc *MouseControl) WndProc(msg uint32, wparam, lparam uintptr) uintptr { - sender := GetMsgHandler(cc.hwnd) - switch msg { - case w32.WM_CREATE: - internalTrackMouseEvent(cc.hwnd) - cc.onCreate.Fire(NewEvent(sender, nil)) - case w32.WM_CLOSE: - cc.onClose.Fire(NewEvent(sender, nil)) - case w32.WM_MOUSEMOVE: - //if cc.isMouseLeft { - - cc.onMouseHover.Fire(NewEvent(sender, nil)) - //internalTrackMouseEvent(cc.hwnd) - cc.isMouseLeft = false - - //} - case w32.WM_MOUSELEAVE: - cc.onMouseLeave.Fire(NewEvent(sender, nil)) - cc.isMouseLeft = true - } - return w32.DefWindowProc(cc.hwnd, msg, wparam, lparam) -} diff --git a/v2/internal/frontend/desktop/windows/winc/msghandlerregistry.go b/v2/internal/frontend/desktop/windows/winc/msghandlerregistry.go deleted file mode 100644 index 2f165e3c5..000000000 --- a/v2/internal/frontend/desktop/windows/winc/msghandlerregistry.go +++ /dev/null @@ -1,28 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2013 Allen Dang. All Rights Reserved. - */ - -package winc - -import ( - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -func RegMsgHandler(controller Controller) { - gControllerRegistry[controller.Handle()] = controller -} - -func UnRegMsgHandler(hwnd w32.HWND) { - delete(gControllerRegistry, hwnd) -} - -func GetMsgHandler(hwnd w32.HWND) Controller { - if controller, isExists := gControllerRegistry[hwnd]; isExists { - return controller - } - - return nil -} diff --git a/v2/internal/frontend/desktop/windows/winc/panel.go b/v2/internal/frontend/desktop/windows/winc/panel.go deleted file mode 100644 index f6aaea26b..000000000 --- a/v2/internal/frontend/desktop/windows/winc/panel.go +++ /dev/null @@ -1,200 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - */ - -package winc - -import ( - "fmt" - - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -type Panel struct { - ControlBase - layoutMng LayoutManager -} - -func NewPanel(parent Controller) *Panel { - pa := new(Panel) - - RegClassOnlyOnce("winc_Panel") - pa.hwnd = CreateWindow("winc_Panel", parent, w32.WS_EX_CONTROLPARENT, w32.WS_CHILD|w32.WS_VISIBLE) - pa.parent = parent - RegMsgHandler(pa) - - pa.SetFont(DefaultFont) - pa.SetText("") - pa.SetSize(200, 65) - return pa -} - -// SetLayout panel implements DockAllow interface. -func (pa *Panel) SetLayout(mng LayoutManager) { - pa.layoutMng = mng -} - -func (pa *Panel) WndProc(msg uint32, wparam, lparam uintptr) uintptr { - switch msg { - case w32.WM_SIZE, w32.WM_PAINT: - if pa.layoutMng != nil { - pa.layoutMng.Update() - } - } - return w32.DefWindowProc(pa.hwnd, msg, wparam, lparam) -} - -var errorPanelPen = NewPen(w32.PS_GEOMETRIC, 2, NewSolidColorBrush(RGB(255, 128, 128))) -var errorPanelOkPen = NewPen(w32.PS_GEOMETRIC, 2, NewSolidColorBrush(RGB(220, 220, 220))) - -// ErrorPanel shows errors or important messages. -// It is meant to stand out of other on screen controls. -type ErrorPanel struct { - ControlBase - pen *Pen - margin int -} - -// NewErrorPanel. -func NewErrorPanel(parent Controller) *ErrorPanel { - f := new(ErrorPanel) - f.init(parent) - - f.SetFont(DefaultFont) - f.SetText("No errors") - f.SetSize(200, 65) - f.margin = 5 - f.pen = errorPanelOkPen - return f -} - -func (epa *ErrorPanel) init(parent Controller) { - RegClassOnlyOnce("winc_ErrorPanel") - - epa.hwnd = CreateWindow("winc_ErrorPanel", parent, w32.WS_EX_CONTROLPARENT, w32.WS_CHILD|w32.WS_VISIBLE) - epa.parent = parent - - RegMsgHandler(epa) -} - -func (epa *ErrorPanel) SetMargin(margin int) { - epa.margin = margin -} - -func (epa *ErrorPanel) Printf(format string, v ...interface{}) { - epa.SetText(fmt.Sprintf(format, v...)) - epa.ShowAsError(false) -} - -func (epa *ErrorPanel) Errorf(format string, v ...interface{}) { - epa.SetText(fmt.Sprintf(format, v...)) - epa.ShowAsError(true) -} - -func (epa *ErrorPanel) ShowAsError(show bool) { - if show { - epa.pen = errorPanelPen - } else { - epa.pen = errorPanelOkPen - } - epa.Invalidate(true) -} - -func (epa *ErrorPanel) WndProc(msg uint32, wparam, lparam uintptr) uintptr { - switch msg { - case w32.WM_ERASEBKGND: - canvas := NewCanvasFromHDC(w32.HDC(wparam)) - r := epa.Bounds() - r.rect.Left += int32(epa.margin) - r.rect.Right -= int32(epa.margin) - r.rect.Top += int32(epa.margin) - r.rect.Bottom -= int32(epa.margin) - // old code used NewSystemColorBrush(w32.COLOR_BTNFACE) - canvas.DrawFillRect(r, epa.pen, NewSystemColorBrush(w32.COLOR_WINDOW)) - - r.rect.Left += 5 - canvas.DrawText(epa.Text(), r, 0, epa.Font(), RGB(0, 0, 0)) - canvas.Dispose() - return 1 - } - return w32.DefWindowProc(epa.hwnd, msg, wparam, lparam) -} - -// MultiPanel contains other panels and only makes one of them visible. -type MultiPanel struct { - ControlBase - current int - panels []*Panel -} - -func NewMultiPanel(parent Controller) *MultiPanel { - mpa := new(MultiPanel) - - RegClassOnlyOnce("winc_MultiPanel") - mpa.hwnd = CreateWindow("winc_MultiPanel", parent, w32.WS_EX_CONTROLPARENT, w32.WS_CHILD|w32.WS_VISIBLE) - mpa.parent = parent - RegMsgHandler(mpa) - - mpa.SetFont(DefaultFont) - mpa.SetText("") - mpa.SetSize(300, 200) - mpa.current = -1 - return mpa -} - -func (mpa *MultiPanel) Count() int { return len(mpa.panels) } - -// AddPanel adds panels to the internal list, first panel is visible all others are hidden. -func (mpa *MultiPanel) AddPanel(panel *Panel) { - if len(mpa.panels) > 0 { - panel.Hide() - } - mpa.current = 0 - mpa.panels = append(mpa.panels, panel) -} - -// ReplacePanel replaces panel, useful for refreshing controls on screen. -func (mpa *MultiPanel) ReplacePanel(index int, panel *Panel) { - mpa.panels[index] = panel -} - -// DeletePanel removed panel. -func (mpa *MultiPanel) DeletePanel(index int) { - mpa.panels = append(mpa.panels[:index], mpa.panels[index+1:]...) -} - -func (mpa *MultiPanel) Current() int { - return mpa.current -} - -func (mpa *MultiPanel) SetCurrent(index int) { - if index >= len(mpa.panels) { - panic("index greater than number of panels") - } - if mpa.current == -1 { - panic("no current panel, add panels first") - } - for i := range mpa.panels { - if i != index { - mpa.panels[i].Hide() - mpa.panels[i].Invalidate(true) - } - } - mpa.panels[index].Show() - mpa.panels[index].Invalidate(true) - mpa.current = index -} - -func (mpa *MultiPanel) WndProc(msg uint32, wparam, lparam uintptr) uintptr { - switch msg { - case w32.WM_SIZE: - // resize contained panels - for _, p := range mpa.panels { - p.SetPos(0, 0) - p.SetSize(mpa.Size()) - } - } - return w32.DefWindowProc(mpa.hwnd, msg, wparam, lparam) -} diff --git a/v2/internal/frontend/desktop/windows/winc/path.go b/v2/internal/frontend/desktop/windows/winc/path.go deleted file mode 100644 index f52a2b931..000000000 --- a/v2/internal/frontend/desktop/windows/winc/path.go +++ /dev/null @@ -1,77 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2013 Allen Dang. All Rights Reserved. - */ - -package winc - -import ( - "fmt" - "os" - "path/filepath" - "syscall" - - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -func knownFolderPath(id w32.CSIDL) (string, error) { - var buf [w32.MAX_PATH]uint16 - - if !w32.SHGetSpecialFolderPath(0, &buf[0], id, false) { - return "", fmt.Errorf("SHGetSpecialFolderPath failed") - } - - return syscall.UTF16ToString(buf[0:]), nil -} - -func AppDataPath() (string, error) { - return knownFolderPath(w32.CSIDL_APPDATA) -} - -func CommonAppDataPath() (string, error) { - return knownFolderPath(w32.CSIDL_COMMON_APPDATA) -} - -func LocalAppDataPath() (string, error) { - return knownFolderPath(w32.CSIDL_LOCAL_APPDATA) -} - -// EnsureAppDataPath uses AppDataPath to ensure storage for local settings and databases. -func EnsureAppDataPath(company, product string) (string, error) { - path, err := AppDataPath() - if err != nil { - return path, err - } - p := filepath.Join(path, company, product) - - if _, err := os.Stat(p); os.IsNotExist(err) { - // path/to/whatever does not exist - if err := os.MkdirAll(p, os.ModePerm); err != nil { - return p, err - } - } - return p, nil -} - -func DriveNames() ([]string, error) { - bufLen := w32.GetLogicalDriveStrings(0, nil) - if bufLen == 0 { - return nil, fmt.Errorf("GetLogicalDriveStrings failed") - } - buf := make([]uint16, bufLen+1) - - bufLen = w32.GetLogicalDriveStrings(bufLen+1, &buf[0]) - if bufLen == 0 { - return nil, fmt.Errorf("GetLogicalDriveStrings failed") - } - - var names []string - for i := 0; i < len(buf)-2; { - name := syscall.UTF16ToString(buf[i:]) - names = append(names, name) - i += len(name) + 1 - } - return names, nil -} diff --git a/v2/internal/frontend/desktop/windows/winc/pen.go b/v2/internal/frontend/desktop/windows/winc/pen.go deleted file mode 100644 index 232f2bb4f..000000000 --- a/v2/internal/frontend/desktop/windows/winc/pen.go +++ /dev/null @@ -1,61 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2013 Allen Dang. All Rights Reserved. - */ - -package winc - -import ( - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -type Pen struct { - hPen w32.HPEN - style uint - brush *Brush -} - -func NewPen(style uint, width uint, brush *Brush) *Pen { - if brush == nil { - panic("Brush cannot be nil") - } - - hPen := w32.ExtCreatePen(style, width, brush.GetLOGBRUSH(), 0, nil) - if hPen == 0 { - panic("Failed to create pen") - } - - return &Pen{hPen, style, brush} -} - -func NewNullPen() *Pen { - lb := w32.LOGBRUSH{LbStyle: w32.BS_NULL} - - hPen := w32.ExtCreatePen(w32.PS_COSMETIC|w32.PS_NULL, 1, &lb, 0, nil) - if hPen == 0 { - panic("failed to create null brush") - } - - return &Pen{hPen: hPen} -} - -func (pen *Pen) Style() uint { - return pen.style -} - -func (pen *Pen) Brush() *Brush { - return pen.brush -} - -func (pen *Pen) GetHPEN() w32.HPEN { - return pen.hPen -} - -func (pen *Pen) Dispose() { - if pen.hPen != 0 { - w32.DeleteObject(w32.HGDIOBJ(pen.hPen)) - pen.hPen = 0 - } -} diff --git a/v2/internal/frontend/desktop/windows/winc/progressbar.go b/v2/internal/frontend/desktop/windows/winc/progressbar.go deleted file mode 100644 index 5d51a8a50..000000000 --- a/v2/internal/frontend/desktop/windows/winc/progressbar.go +++ /dev/null @@ -1,48 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - */ - -package winc - -import ( - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -type ProgressBar struct { - ControlBase -} - -func NewProgressBar(parent Controller) *ProgressBar { - pb := new(ProgressBar) - - pb.InitControl(w32.PROGRESS_CLASS, parent, 0, w32.WS_CHILD|w32.WS_VISIBLE) - RegMsgHandler(pb) - - pb.SetSize(200, 22) - return pb -} - -func (pr *ProgressBar) Value() int { - ret := w32.SendMessage(pr.hwnd, w32.PBM_GETPOS, 0, 0) - return int(ret) -} - -func (pr *ProgressBar) SetValue(v int) { - w32.SendMessage(pr.hwnd, w32.PBM_SETPOS, uintptr(v), 0) -} - -func (pr *ProgressBar) Range() (min, max uint) { - min = uint(w32.SendMessage(pr.hwnd, w32.PBM_GETRANGE, uintptr(w32.BoolToBOOL(true)), 0)) - max = uint(w32.SendMessage(pr.hwnd, w32.PBM_GETRANGE, uintptr(w32.BoolToBOOL(false)), 0)) - return -} - -func (pr *ProgressBar) SetRange(min, max int) { - w32.SendMessage(pr.hwnd, w32.PBM_SETRANGE32, uintptr(min), uintptr(max)) -} - -func (pr *ProgressBar) WndProc(msg uint32, wparam, lparam uintptr) uintptr { - return w32.DefWindowProc(pr.hwnd, msg, wparam, lparam) -} diff --git a/v2/internal/frontend/desktop/windows/winc/rect.go b/v2/internal/frontend/desktop/windows/winc/rect.go deleted file mode 100644 index dd9a70845..000000000 --- a/v2/internal/frontend/desktop/windows/winc/rect.go +++ /dev/null @@ -1,87 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2013 Allen Dang. All Rights Reserved. - */ - -package winc - -import ( - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -type Rect struct { - rect w32.RECT -} - -func NewEmptyRect() *Rect { - var newRect Rect - w32.SetRectEmpty(&newRect.rect) - - return &newRect -} - -func NewRect(left, top, right, bottom int) *Rect { - var newRect Rect - w32.SetRectEmpty(&newRect.rect) - newRect.Set(left, top, right, bottom) - - return &newRect -} - -func (re *Rect) Data() (left, top, right, bottom int32) { - left = re.rect.Left - top = re.rect.Top - right = re.rect.Right - bottom = re.rect.Bottom - return -} - -func (re *Rect) Width() int { - return int(re.rect.Right - re.rect.Left) -} - -func (re *Rect) Height() int { - return int(re.rect.Bottom - re.rect.Top) -} - -func (re *Rect) GetW32Rect() *w32.RECT { - return &re.rect -} - -func (re *Rect) Set(left, top, right, bottom int) { - w32.SetRect(&re.rect, left, top, right, bottom) -} - -func (re *Rect) IsEqual(rect *Rect) bool { - return w32.EqualRect(&re.rect, &rect.rect) -} - -func (re *Rect) Inflate(x, y int) { - w32.InflateRect(&re.rect, x, y) -} - -func (re *Rect) Intersect(src *Rect) { - w32.IntersectRect(&re.rect, &re.rect, &src.rect) -} - -func (re *Rect) IsEmpty() bool { - return w32.IsRectEmpty(&re.rect) -} - -func (re *Rect) Offset(x, y int) { - w32.OffsetRect(&re.rect, x, y) -} - -func (re *Rect) IsPointIn(x, y int) bool { - return w32.PtInRect(&re.rect, x, y) -} - -func (re *Rect) Substract(src *Rect) { - w32.SubtractRect(&re.rect, &re.rect, &src.rect) -} - -func (re *Rect) Union(src *Rect) { - w32.UnionRect(&re.rect, &re.rect, &src.rect) -} diff --git a/v2/internal/frontend/desktop/windows/winc/resizer.go b/v2/internal/frontend/desktop/windows/winc/resizer.go deleted file mode 100644 index 2e9ea02f8..000000000 --- a/v2/internal/frontend/desktop/windows/winc/resizer.go +++ /dev/null @@ -1,216 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - */ - -package winc - -import ( - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -type VResizer struct { - ControlBase - - control1 Dockable - control2 Dockable - dir Direction - - mouseLeft bool - drag bool -} - -func NewVResizer(parent Controller) *VResizer { - sp := new(VResizer) - - RegClassOnlyOnce("winc_VResizer") - sp.hwnd = CreateWindow("winc_VResizer", parent, w32.WS_EX_CONTROLPARENT, w32.WS_CHILD|w32.WS_VISIBLE) - sp.parent = parent - sp.mouseLeft = true - RegMsgHandler(sp) - - sp.SetFont(DefaultFont) - sp.SetText("") - sp.SetSize(20, 100) - return sp -} - -func (sp *VResizer) SetControl(control1, control2 Dockable, dir Direction, minSize int) { - sp.control1 = control1 - sp.control2 = control2 - if dir != Left && dir != Right { - panic("invalid direction") - } - sp.dir = dir - - // TODO(vi): ADDED - /*internalTrackMouseEvent(control1.Handle()) - internalTrackMouseEvent(control2.Handle()) - - control1.OnMouseMove().Bind(func(e *Event) { - if sp.drag { - x := e.Data.(*MouseEventData).X - sp.update(x) - w32.SetCursor(w32.LoadCursorWithResourceID(0, w32.IDC_SIZEWE)) - - } - fmt.Println("control1.OnMouseMove") - }) - - control2.OnMouseMove().Bind(func(e *Event) { - if sp.drag { - x := e.Data.(*MouseEventData).X - sp.update(x) - w32.SetCursor(w32.LoadCursorWithResourceID(0, w32.IDC_SIZEWE)) - - } - fmt.Println("control2.OnMouseMove") - }) - - control1.OnLBUp().Bind(func(e *Event) { - sp.drag = false - sp.mouseLeft = true - fmt.Println("control1.OnLBUp") - }) - - control2.OnLBUp().Bind(func(e *Event) { - sp.drag = false - sp.mouseLeft = true - fmt.Println("control2.OnLBUp") - })*/ - - // ---- finish ADDED - -} - -func (sp *VResizer) update(x int) { - pos := x - 10 - - w1, h1 := sp.control1.Width(), sp.control1.Height() - if sp.dir == Left { - w1 += pos - } else { - w1 -= pos - } - sp.control1.SetSize(w1, h1) - fm := sp.parent.(*Form) - fm.UpdateLayout() - - w32.SetCursor(w32.LoadCursorWithResourceID(0, w32.IDC_ARROW)) -} - -func (sp *VResizer) WndProc(msg uint32, wparam, lparam uintptr) uintptr { - switch msg { - case w32.WM_CREATE: - internalTrackMouseEvent(sp.hwnd) - - case w32.WM_MOUSEMOVE: - if sp.drag { - x, _ := genPoint(lparam) - sp.update(x) - } else { - w32.SetCursor(w32.LoadCursorWithResourceID(0, w32.IDC_SIZEWE)) - } - - if sp.mouseLeft { - internalTrackMouseEvent(sp.hwnd) - sp.mouseLeft = false - } - - case w32.WM_MOUSELEAVE: - sp.drag = false - sp.mouseLeft = true - - case w32.WM_LBUTTONUP: - sp.drag = false - - case w32.WM_LBUTTONDOWN: - sp.drag = true - } - return w32.DefWindowProc(sp.hwnd, msg, wparam, lparam) -} - -type HResizer struct { - ControlBase - - control1 Dockable - control2 Dockable - dir Direction - mouseLeft bool - drag bool -} - -func NewHResizer(parent Controller) *HResizer { - sp := new(HResizer) - - RegClassOnlyOnce("winc_HResizer") - sp.hwnd = CreateWindow("winc_HResizer", parent, w32.WS_EX_CONTROLPARENT, w32.WS_CHILD|w32.WS_VISIBLE) - sp.parent = parent - sp.mouseLeft = true - RegMsgHandler(sp) - - sp.SetFont(DefaultFont) - sp.SetText("") - sp.SetSize(100, 20) - - return sp -} - -func (sp *HResizer) SetControl(control1, control2 Dockable, dir Direction, minSize int) { - sp.control1 = control1 - sp.control2 = control2 - if dir != Top && dir != Bottom { - panic("invalid direction") - } - sp.dir = dir - -} - -func (sp *HResizer) update(y int) { - pos := y - 10 - - w1, h1 := sp.control1.Width(), sp.control1.Height() - if sp.dir == Top { - h1 += pos - } else { - h1 -= pos - } - sp.control1.SetSize(w1, h1) - - fm := sp.parent.(*Form) - fm.UpdateLayout() - - w32.SetCursor(w32.LoadCursorWithResourceID(0, w32.IDC_ARROW)) -} - -func (sp *HResizer) WndProc(msg uint32, wparam, lparam uintptr) uintptr { - switch msg { - case w32.WM_CREATE: - internalTrackMouseEvent(sp.hwnd) - - case w32.WM_MOUSEMOVE: - if sp.drag { - _, y := genPoint(lparam) - sp.update(y) - } else { - w32.SetCursor(w32.LoadCursorWithResourceID(0, w32.IDC_SIZENS)) - } - - if sp.mouseLeft { - internalTrackMouseEvent(sp.hwnd) - sp.mouseLeft = false - } - - case w32.WM_MOUSELEAVE: - sp.drag = false - sp.mouseLeft = true - - case w32.WM_LBUTTONUP: - sp.drag = false - - case w32.WM_LBUTTONDOWN: - sp.drag = true - } - return w32.DefWindowProc(sp.hwnd, msg, wparam, lparam) -} diff --git a/v2/internal/frontend/desktop/windows/winc/scrollview.go b/v2/internal/frontend/desktop/windows/winc/scrollview.go deleted file mode 100644 index d9e932932..000000000 --- a/v2/internal/frontend/desktop/windows/winc/scrollview.go +++ /dev/null @@ -1,121 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - */ - -package winc - -import ( - "unsafe" - - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -type ScrollView struct { - ControlBase - child Dockable -} - -func NewScrollView(parent Controller) *ScrollView { - sv := new(ScrollView) - - RegClassOnlyOnce("winc_ScrollView") - sv.hwnd = CreateWindow("winc_ScrollView", parent, w32.WS_EX_CONTROLPARENT, - w32.WS_CHILD|w32.WS_HSCROLL|w32.WS_VISIBLE|w32.WS_VSCROLL) - sv.parent = parent - RegMsgHandler(sv) - - sv.SetFont(DefaultFont) - sv.SetText("") - sv.SetSize(200, 200) - return sv -} - -func (sv *ScrollView) SetChild(child Dockable) { - sv.child = child -} - -func (sv *ScrollView) UpdateScrollBars() { - w, h := sv.child.Width(), sv.child.Height() - sw, sh := sv.Size() - - var si w32.SCROLLINFO - si.CbSize = uint32(unsafe.Sizeof(si)) - si.FMask = w32.SIF_PAGE | w32.SIF_RANGE - - si.NMax = int32(w - 1) - si.NPage = uint32(sw) - w32.SetScrollInfo(sv.hwnd, w32.SB_HORZ, &si, true) - x := sv.scroll(w32.SB_HORZ, w32.SB_THUMBPOSITION) - - si.NMax = int32(h) - si.NPage = uint32(sh) - w32.SetScrollInfo(sv.hwnd, w32.SB_VERT, &si, true) - y := sv.scroll(w32.SB_VERT, w32.SB_THUMBPOSITION) - - sv.child.SetPos(x, y) -} - -func (sv *ScrollView) scroll(sb int32, cmd uint16) int { - var pos int32 - var si w32.SCROLLINFO - si.CbSize = uint32(unsafe.Sizeof(si)) - si.FMask = w32.SIF_PAGE | w32.SIF_POS | w32.SIF_RANGE | w32.SIF_TRACKPOS - - w32.GetScrollInfo(sv.hwnd, sb, &si) - pos = si.NPos - - switch cmd { - case w32.SB_LINELEFT: // == win.SB_LINEUP - pos -= 20 - - case w32.SB_LINERIGHT: // == win.SB_LINEDOWN - pos += 20 - - case w32.SB_PAGELEFT: // == win.SB_PAGEUP - pos -= int32(si.NPage) - - case w32.SB_PAGERIGHT: // == win.SB_PAGEDOWN - pos += int32(si.NPage) - - case w32.SB_THUMBTRACK: - pos = si.NTrackPos - } - - if pos < 0 { - pos = 0 - } - if pos > si.NMax+1-int32(si.NPage) { - pos = si.NMax + 1 - int32(si.NPage) - } - - si.FMask = w32.SIF_POS - si.NPos = pos - w32.SetScrollInfo(sv.hwnd, sb, &si, true) - - return -int(pos) -} - -func (sv *ScrollView) WndProc(msg uint32, wparam, lparam uintptr) uintptr { - if sv.child != nil { - switch msg { - case w32.WM_PAINT: - sv.UpdateScrollBars() - - case w32.WM_HSCROLL: - x, y := sv.child.Pos() - x = sv.scroll(w32.SB_HORZ, w32.LOWORD(uint32(wparam))) - sv.child.SetPos(x, y) - - case w32.WM_VSCROLL: - x, y := sv.child.Pos() - y = sv.scroll(w32.SB_VERT, w32.LOWORD(uint32(wparam))) - sv.child.SetPos(x, y) - - case w32.WM_SIZE, w32.WM_SIZING: - sv.UpdateScrollBars() - } - } - return w32.DefWindowProc(sv.hwnd, msg, wparam, lparam) -} diff --git a/v2/internal/frontend/desktop/windows/winc/slider.go b/v2/internal/frontend/desktop/windows/winc/slider.go deleted file mode 100644 index 2be9f13b6..000000000 --- a/v2/internal/frontend/desktop/windows/winc/slider.go +++ /dev/null @@ -1,79 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - */ - -package winc - -import "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" - -type Slider struct { - ControlBase - prevPos int - - onScroll EventManager -} - -func NewSlider(parent Controller) *Slider { - tb := new(Slider) - - tb.InitControl("msctls_trackbar32", parent, 0, w32.WS_TABSTOP|w32.WS_VISIBLE|w32.WS_CHILD /*|w32.TBS_AUTOTICKS*/) - RegMsgHandler(tb) - - tb.SetFont(DefaultFont) - tb.SetText("Slider") - tb.SetSize(200, 32) - - tb.SetRange(0, 100) - tb.SetPage(10) - return tb -} - -func (tb *Slider) OnScroll() *EventManager { - return &tb.onScroll -} - -func (tb *Slider) Value() int { - ret := w32.SendMessage(tb.hwnd, w32.TBM_GETPOS, 0, 0) - return int(ret) -} - -func (tb *Slider) SetValue(v int) { - tb.prevPos = v - w32.SendMessage(tb.hwnd, w32.TBM_SETPOS, uintptr(w32.BoolToBOOL(true)), uintptr(v)) -} - -func (tb *Slider) Range() (min, max int) { - min = int(w32.SendMessage(tb.hwnd, w32.TBM_GETRANGEMIN, 0, 0)) - max = int(w32.SendMessage(tb.hwnd, w32.TBM_GETRANGEMAX, 0, 0)) - return min, max -} - -func (tb *Slider) SetRange(min, max int) { - w32.SendMessage(tb.hwnd, w32.TBM_SETRANGE, uintptr(w32.BoolToBOOL(true)), uintptr(w32.MAKELONG(uint16(min), uint16(max)))) -} - -func (tb *Slider) SetPage(pagesize int) { - w32.SendMessage(tb.hwnd, w32.TBM_SETPAGESIZE, 0, uintptr(pagesize)) -} - -func (tb *Slider) WndProc(msg uint32, wparam, lparam uintptr) uintptr { - /* - // REMOVE: - // following code did not work, used workaround below - code := w32.LOWORD(uint32(wparam)) - - switch code { - case w32.TB_ENDTRACK: - tb.onScroll.Fire(NewEvent(tb, nil)) - }*/ - - newPos := tb.Value() - if newPos != tb.prevPos { - tb.onScroll.Fire(NewEvent(tb, nil)) - tb.prevPos = newPos - } - - return w32.DefWindowProc(tb.hwnd, msg, wparam, lparam) -} diff --git a/v2/internal/frontend/desktop/windows/winc/tabview.go b/v2/internal/frontend/desktop/windows/winc/tabview.go deleted file mode 100644 index 5e8fe5093..000000000 --- a/v2/internal/frontend/desktop/windows/winc/tabview.go +++ /dev/null @@ -1,107 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - */ - -package winc - -import ( - "syscall" - "unsafe" - - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -// TabView creates MultiPanel internally and manages tabs as panels. -type TabView struct { - ControlBase - - panels *MultiPanel - onSelectedChange EventManager -} - -func NewTabView(parent Controller) *TabView { - tv := new(TabView) - - tv.InitControl("SysTabControl32", parent, 0, - w32.WS_CHILD|w32.WS_VISIBLE|w32.WS_TABSTOP|w32.WS_CLIPSIBLINGS) - RegMsgHandler(tv) - - tv.panels = NewMultiPanel(parent) - - tv.SetFont(DefaultFont) - tv.SetSize(200, 24) - return tv -} - -func (tv *TabView) Panels() *MultiPanel { - return tv.panels -} - -func (tv *TabView) tcitemFromPage(panel *Panel) *w32.TCITEM { - text := syscall.StringToUTF16(panel.Text()) - item := &w32.TCITEM{ - Mask: w32.TCIF_TEXT, - PszText: &text[0], - CchTextMax: int32(len(text)), - } - return item -} - -func (tv *TabView) AddPanel(text string) *Panel { - panel := NewPanel(tv.panels) - panel.SetText(text) - - item := tv.tcitemFromPage(panel) - index := tv.panels.Count() - idx := int(w32.SendMessage(tv.hwnd, w32.TCM_INSERTITEM, uintptr(index), uintptr(unsafe.Pointer(item)))) - if idx == -1 { - panic("SendMessage(TCM_INSERTITEM) failed") - } - - tv.panels.AddPanel(panel) - tv.SetCurrent(idx) - return panel -} - -func (tv *TabView) DeletePanel(index int) { - w32.SendMessage(tv.hwnd, w32.TCM_DELETEITEM, uintptr(index), 0) - tv.panels.DeletePanel(index) - switch { - case tv.panels.Count() > index: - tv.SetCurrent(index) - case tv.panels.Count() == 0: - tv.SetCurrent(0) - } -} - -func (tv *TabView) Current() int { - return tv.panels.Current() -} - -func (tv *TabView) SetCurrent(index int) { - if index < 0 || index >= tv.panels.Count() { - panic("invalid index") - } - if ret := int(w32.SendMessage(tv.hwnd, w32.TCM_SETCURSEL, uintptr(index), 0)); ret == -1 { - panic("SendMessage(TCM_SETCURSEL) failed") - } - tv.panels.SetCurrent(index) -} - -func (tv *TabView) WndProc(msg uint32, wparam, lparam uintptr) uintptr { - switch msg { - case w32.WM_NOTIFY: - nmhdr := (*w32.NMHDR)(unsafe.Pointer(lparam)) - - switch int32(nmhdr.Code) { - case w32.TCN_SELCHANGE: - cur := int(w32.SendMessage(tv.hwnd, w32.TCM_GETCURSEL, 0, 0)) - tv.SetCurrent(cur) - - tv.onSelectedChange.Fire(NewEvent(tv, nil)) - } - } - return w32.DefWindowProc(tv.hwnd, msg, wparam, lparam) -} diff --git a/v2/internal/frontend/desktop/windows/winc/toolbar.go b/v2/internal/frontend/desktop/windows/winc/toolbar.go deleted file mode 100644 index bbe945e1c..000000000 --- a/v2/internal/frontend/desktop/windows/winc/toolbar.go +++ /dev/null @@ -1,181 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - */ - -package winc - -import ( - "syscall" - "unsafe" - - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -type Toolbar struct { - ControlBase - iml *ImageList - - buttons []*ToolButton -} - -type ToolButton struct { - tb *Toolbar - - text string - enabled bool - checkable bool - checked bool - image int - - onClick EventManager -} - -func (bt *ToolButton) OnClick() *EventManager { - return &bt.onClick -} - -func (bt *ToolButton) update() { bt.tb.update(bt) } - -func (bt *ToolButton) IsSeparator() bool { return bt.text == "-" } -func (bt *ToolButton) SetSeparator() { bt.text = "-" } - -func (bt *ToolButton) Enabled() bool { return bt.enabled } -func (bt *ToolButton) SetEnabled(b bool) { bt.enabled = b; bt.update() } - -func (bt *ToolButton) Checkable() bool { return bt.checkable } -func (bt *ToolButton) SetCheckable(b bool) { bt.checkable = b; bt.update() } - -func (bt *ToolButton) Checked() bool { return bt.checked } -func (bt *ToolButton) SetChecked(b bool) { bt.checked = b; bt.update() } - -func (bt *ToolButton) Text() string { return bt.text } -func (bt *ToolButton) SetText(s string) { bt.text = s; bt.update() } - -func (bt *ToolButton) Image() int { return bt.image } -func (bt *ToolButton) SetImage(i int) { bt.image = i; bt.update() } - -// NewHToolbar creates horizontal toolbar with text on same line as image. -func NewHToolbar(parent Controller) *Toolbar { - return newToolbar(parent, w32.CCS_NODIVIDER|w32.TBSTYLE_FLAT|w32.TBSTYLE_TOOLTIPS|w32.TBSTYLE_WRAPABLE| - w32.WS_CHILD|w32.TBSTYLE_LIST) -} - -// NewToolbar creates toolbar with text below the image. -func NewToolbar(parent Controller) *Toolbar { - return newToolbar(parent, w32.CCS_NODIVIDER|w32.TBSTYLE_FLAT|w32.TBSTYLE_TOOLTIPS|w32.TBSTYLE_WRAPABLE| - w32.WS_CHILD /*|w32.TBSTYLE_TRANSPARENT*/) -} - -func newToolbar(parent Controller, style uint) *Toolbar { - tb := new(Toolbar) - - tb.InitControl("ToolbarWindow32", parent, 0, style) - - exStyle := w32.SendMessage(tb.hwnd, w32.TB_GETEXTENDEDSTYLE, 0, 0) - exStyle |= w32.TBSTYLE_EX_DRAWDDARROWS | w32.TBSTYLE_EX_MIXEDBUTTONS - w32.SendMessage(tb.hwnd, w32.TB_SETEXTENDEDSTYLE, 0, exStyle) - RegMsgHandler(tb) - - tb.SetFont(DefaultFont) - tb.SetPos(0, 0) - tb.SetSize(200, 40) - - return tb -} - -func (tb *Toolbar) SetImageList(imageList *ImageList) { - w32.SendMessage(tb.hwnd, w32.TB_SETIMAGELIST, 0, uintptr(imageList.Handle())) - tb.iml = imageList -} - -func (tb *Toolbar) initButton(btn *ToolButton, state, style *byte, image *int32, text *uintptr) { - *style |= w32.BTNS_AUTOSIZE - - if btn.checked { - *state |= w32.TBSTATE_CHECKED - } - - if btn.enabled { - *state |= w32.TBSTATE_ENABLED - } - - if btn.checkable { - *style |= w32.BTNS_CHECK - } - - if len(btn.Text()) > 0 { - *style |= w32.BTNS_SHOWTEXT - } - - if btn.IsSeparator() { - *style = w32.BTNS_SEP - } - - *image = int32(btn.Image()) - *text = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(btn.Text()))) -} - -func (tb *Toolbar) update(btn *ToolButton) { - tbbi := w32.TBBUTTONINFO{ - DwMask: w32.TBIF_IMAGE | w32.TBIF_STATE | w32.TBIF_STYLE | w32.TBIF_TEXT, - } - - tbbi.CbSize = uint32(unsafe.Sizeof(tbbi)) - - var i int - for i = range tb.buttons { - if tb.buttons[i] == btn { - break - } - } - - tb.initButton(btn, &tbbi.FsState, &tbbi.FsStyle, &tbbi.IImage, &tbbi.PszText) - if w32.SendMessage(tb.hwnd, w32.TB_SETBUTTONINFO, uintptr(i), uintptr(unsafe.Pointer(&tbbi))) == 0 { - panic("SendMessage(TB_SETBUTTONINFO) failed") - } -} - -func (tb *Toolbar) AddSeparator() { - tb.AddButton("-", 0) -} - -// AddButton creates and adds button to the toolbar. Use returned toolbutton to setup OnClick event. -func (tb *Toolbar) AddButton(text string, image int) *ToolButton { - bt := &ToolButton{ - tb: tb, // points to parent - text: text, - image: image, - enabled: true, - } - tb.buttons = append(tb.buttons, bt) - index := len(tb.buttons) - 1 - - tbb := w32.TBBUTTON{ - IdCommand: int32(index), - } - - tb.initButton(bt, &tbb.FsState, &tbb.FsStyle, &tbb.IBitmap, &tbb.IString) - w32.SendMessage(tb.hwnd, w32.TB_BUTTONSTRUCTSIZE, uintptr(unsafe.Sizeof(tbb)), 0) - - if w32.SendMessage(tb.hwnd, w32.TB_INSERTBUTTON, uintptr(index), uintptr(unsafe.Pointer(&tbb))) == w32.FALSE { - panic("SendMessage(TB_ADDBUTTONS)") - } - - w32.SendMessage(tb.hwnd, w32.TB_AUTOSIZE, 0, 0) - return bt -} - -func (tb *Toolbar) WndProc(msg uint32, wparam, lparam uintptr) uintptr { - switch msg { - case w32.WM_COMMAND: - switch w32.HIWORD(uint32(wparam)) { - case w32.BN_CLICKED: - id := uint16(w32.LOWORD(uint32(wparam))) - btn := tb.buttons[id] - btn.onClick.Fire(NewEvent(tb, nil)) - } - } - return w32.DefWindowProc(tb.hwnd, msg, wparam, lparam) -} diff --git a/v2/internal/frontend/desktop/windows/winc/tooltip.go b/v2/internal/frontend/desktop/windows/winc/tooltip.go deleted file mode 100644 index ec1568bb9..000000000 --- a/v2/internal/frontend/desktop/windows/winc/tooltip.go +++ /dev/null @@ -1,45 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2013 Allen Dang. All Rights Reserved. - */ - -package winc - -import ( - "syscall" - "unsafe" - - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -type ToolTip struct { - ControlBase -} - -func NewToolTip(parent Controller) *ToolTip { - tp := new(ToolTip) - - tp.InitControl("tooltips_class32", parent, w32.WS_EX_TOPMOST, w32.WS_POPUP|w32.TTS_NOPREFIX|w32.TTS_ALWAYSTIP) - w32.SetWindowPos(tp.Handle(), w32.HWND_TOPMOST, 0, 0, 0, 0, w32.SWP_NOMOVE|w32.SWP_NOSIZE|w32.SWP_NOACTIVATE) - - return tp -} - -func (tp *ToolTip) SetTip(tool Controller, tip string) bool { - var ti w32.TOOLINFO - ti.CbSize = uint32(unsafe.Sizeof(ti)) - if tool.Parent() != nil { - ti.Hwnd = tool.Parent().Handle() - } - ti.UFlags = w32.TTF_IDISHWND | w32.TTF_SUBCLASS /* | TTF_ABSOLUTE */ - ti.UId = uintptr(tool.Handle()) - ti.LpszText = syscall.StringToUTF16Ptr(tip) - - return w32.SendMessage(tp.Handle(), w32.TTM_ADDTOOL, 0, uintptr(unsafe.Pointer(&ti))) != w32.FALSE -} - -func (tp *ToolTip) WndProc(msg uint, wparam, lparam uintptr) uintptr { - return w32.DefWindowProc(tp.hwnd, uint32(msg), wparam, lparam) -} diff --git a/v2/internal/frontend/desktop/windows/winc/treeview.go b/v2/internal/frontend/desktop/windows/winc/treeview.go deleted file mode 100644 index 2cdc0e936..000000000 --- a/v2/internal/frontend/desktop/windows/winc/treeview.go +++ /dev/null @@ -1,286 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - */ - -package winc - -import ( - "errors" - "syscall" - "unsafe" - - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -// TreeItem represents an item in a TreeView widget. -type TreeItem interface { - Text() string // Text returns the text of the item. - ImageIndex() int // ImageIndex is used only if SetImageList is called on the treeview -} - -type treeViewItemInfo struct { - handle w32.HTREEITEM - child2Handle map[TreeItem]w32.HTREEITEM -} - -// StringTreeItem is helper for basic string lists. -type StringTreeItem struct { - Data string - Image int -} - -func (s StringTreeItem) Text() string { return s.Data } -func (s StringTreeItem) ImageIndex() int { return s.Image } - -type TreeView struct { - ControlBase - - iml *ImageList - item2Info map[TreeItem]*treeViewItemInfo - handle2Item map[w32.HTREEITEM]TreeItem - currItem TreeItem - - onSelectedChange EventManager - onExpand EventManager - onCollapse EventManager - onViewChange EventManager -} - -func NewTreeView(parent Controller) *TreeView { - tv := new(TreeView) - - tv.InitControl("SysTreeView32", parent, 0, w32.WS_CHILD|w32.WS_VISIBLE| - w32.WS_BORDER|w32.TVS_HASBUTTONS|w32.TVS_LINESATROOT|w32.TVS_SHOWSELALWAYS| - w32.TVS_TRACKSELECT /*|w32.WS_EX_CLIENTEDGE*/) - - tv.item2Info = make(map[TreeItem]*treeViewItemInfo) - tv.handle2Item = make(map[w32.HTREEITEM]TreeItem) - - RegMsgHandler(tv) - - tv.SetFont(DefaultFont) - tv.SetSize(200, 400) - - if err := tv.SetTheme("Explorer"); err != nil { - // theme error is ignored - } - return tv -} - -func (tv *TreeView) EnableDoubleBuffer(enable bool) { - if enable { - w32.SendMessage(tv.hwnd, w32.TVM_SETEXTENDEDSTYLE, 0, w32.TVS_EX_DOUBLEBUFFER) - } else { - w32.SendMessage(tv.hwnd, w32.TVM_SETEXTENDEDSTYLE, w32.TVS_EX_DOUBLEBUFFER, 0) - } -} - -// SelectedItem is current selected item after OnSelectedChange event. -func (tv *TreeView) SelectedItem() TreeItem { - return tv.currItem -} - -func (tv *TreeView) SetSelectedItem(item TreeItem) bool { - var handle w32.HTREEITEM - if item != nil { - if info := tv.item2Info[item]; info == nil { - return false // invalid item - } else { - handle = info.handle - } - } - - if w32.SendMessage(tv.hwnd, w32.TVM_SELECTITEM, w32.TVGN_CARET, uintptr(handle)) == 0 { - return false // set selected failed - } - tv.currItem = item - return true -} - -func (tv *TreeView) ItemAt(x, y int) TreeItem { - hti := w32.TVHITTESTINFO{Pt: w32.POINT{int32(x), int32(y)}} - w32.SendMessage(tv.hwnd, w32.TVM_HITTEST, 0, uintptr(unsafe.Pointer(&hti))) - if item, ok := tv.handle2Item[hti.HItem]; ok { - return item - } - return nil -} - -func (tv *TreeView) Items() (list []TreeItem) { - for item := range tv.item2Info { - list = append(list, item) - } - return list -} - -func (tv *TreeView) InsertItem(item, parent, insertAfter TreeItem) error { - var tvins w32.TVINSERTSTRUCT - tvi := &tvins.Item - - tvi.Mask = w32.TVIF_TEXT // w32.TVIF_CHILDREN | w32.TVIF_TEXT - tvi.PszText = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(item.Text()))) // w32.LPSTR_TEXTCALLBACK - tvi.CChildren = 0 // w32.I_CHILDRENCALLBACK - - if parent == nil { - tvins.HParent = w32.TVI_ROOT - } else { - info := tv.item2Info[parent] - if info == nil { - return errors.New("winc: invalid parent") - } - tvins.HParent = info.handle - } - - if insertAfter == nil { - tvins.HInsertAfter = w32.TVI_LAST - } else { - info := tv.item2Info[insertAfter] - if info == nil { - return errors.New("winc: invalid prev item") - } - tvins.HInsertAfter = info.handle - } - - tv.applyImage(tvi, item) - - hItem := w32.HTREEITEM(w32.SendMessage(tv.hwnd, w32.TVM_INSERTITEM, 0, uintptr(unsafe.Pointer(&tvins)))) - if hItem == 0 { - return errors.New("winc: TVM_INSERTITEM failed") - } - tv.item2Info[item] = &treeViewItemInfo{hItem, make(map[TreeItem]w32.HTREEITEM)} - tv.handle2Item[hItem] = item - return nil -} - -func (tv *TreeView) UpdateItem(item TreeItem) bool { - it := tv.item2Info[item] - if it == nil { - return false - } - - tvi := &w32.TVITEM{ - Mask: w32.TVIF_TEXT, - HItem: it.handle, - PszText: uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(item.Text()))), - } - tv.applyImage(tvi, item) - - if w32.SendMessage(tv.hwnd, w32.TVM_SETITEM, 0, uintptr(unsafe.Pointer(tvi))) == 0 { - return false - } - return true -} - -func (tv *TreeView) DeleteItem(item TreeItem) bool { - it := tv.item2Info[item] - if it == nil { - return false - } - - if w32.SendMessage(tv.hwnd, w32.TVM_DELETEITEM, 0, uintptr(it.handle)) == 0 { - return false - } - - delete(tv.item2Info, item) - delete(tv.handle2Item, it.handle) - return true -} - -func (tv *TreeView) DeleteAllItems() bool { - if w32.SendMessage(tv.hwnd, w32.TVM_DELETEITEM, 0, 0) == 0 { - return false - } - - tv.item2Info = make(map[TreeItem]*treeViewItemInfo) - tv.handle2Item = make(map[w32.HTREEITEM]TreeItem) - return true -} - -func (tv *TreeView) Expand(item TreeItem) bool { - if w32.SendMessage(tv.hwnd, w32.TVM_EXPAND, w32.TVE_EXPAND, uintptr(tv.item2Info[item].handle)) == 0 { - return false - } - return true -} - -func (tv *TreeView) Collapse(item TreeItem) bool { - if w32.SendMessage(tv.hwnd, w32.TVM_EXPAND, w32.TVE_COLLAPSE, uintptr(tv.item2Info[item].handle)) == 0 { - return false - } - return true -} - -func (tv *TreeView) EnsureVisible(item TreeItem) bool { - if info := tv.item2Info[item]; info != nil { - return w32.SendMessage(tv.hwnd, w32.TVM_ENSUREVISIBLE, 0, uintptr(info.handle)) != 0 - } - return false -} - -func (tv *TreeView) SetImageList(imageList *ImageList) { - w32.SendMessage(tv.hwnd, w32.TVM_SETIMAGELIST, 0, uintptr(imageList.Handle())) - tv.iml = imageList -} - -func (tv *TreeView) applyImage(tc *w32.TVITEM, item TreeItem) { - if tv.iml != nil { - tc.Mask |= w32.TVIF_IMAGE | w32.TVIF_SELECTEDIMAGE - tc.IImage = int32(item.ImageIndex()) - tc.ISelectedImage = int32(item.ImageIndex()) - } -} - -func (tv *TreeView) OnSelectedChange() *EventManager { - return &tv.onSelectedChange -} - -func (tv *TreeView) OnExpand() *EventManager { - return &tv.onExpand -} - -func (tv *TreeView) OnCollapse() *EventManager { - return &tv.onCollapse -} - -func (tv *TreeView) OnViewChange() *EventManager { - return &tv.onViewChange -} - -// Message processor -func (tv *TreeView) WndProc(msg uint32, wparam, lparam uintptr) uintptr { - switch msg { - case w32.WM_NOTIFY: - nm := (*w32.NMHDR)(unsafe.Pointer(lparam)) - - switch nm.Code { - case w32.TVN_ITEMEXPANDED: - nmtv := (*w32.NMTREEVIEW)(unsafe.Pointer(lparam)) - - switch nmtv.Action { - case w32.TVE_COLLAPSE: - tv.onCollapse.Fire(NewEvent(tv, nil)) - - case w32.TVE_COLLAPSERESET: - - case w32.TVE_EXPAND: - tv.onExpand.Fire(NewEvent(tv, nil)) - - case w32.TVE_EXPANDPARTIAL: - - case w32.TVE_TOGGLE: - } - - case w32.TVN_SELCHANGED: - nmtv := (*w32.NMTREEVIEW)(unsafe.Pointer(lparam)) - tv.currItem = tv.handle2Item[nmtv.ItemNew.HItem] - tv.onSelectedChange.Fire(NewEvent(tv, nil)) - - case w32.TVN_GETDISPINFO: - tv.onViewChange.Fire(NewEvent(tv, nil)) - } - - } - return w32.DefWindowProc(tv.hwnd, msg, wparam, lparam) -} diff --git a/v2/internal/frontend/desktop/windows/winc/utils.go b/v2/internal/frontend/desktop/windows/winc/utils.go deleted file mode 100644 index c2d91a8c3..000000000 --- a/v2/internal/frontend/desktop/windows/winc/utils.go +++ /dev/null @@ -1,156 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2013 Allen Dang. All Rights Reserved. - */ - -package winc - -import ( - "fmt" - "syscall" - "unsafe" - - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -func internalTrackMouseEvent(hwnd w32.HWND) { - var tme w32.TRACKMOUSEEVENT - tme.CbSize = uint32(unsafe.Sizeof(tme)) - tme.DwFlags = w32.TME_LEAVE - tme.HwndTrack = hwnd - tme.DwHoverTime = w32.HOVER_DEFAULT - - w32.TrackMouseEvent(&tme) -} - -func SetStyle(hwnd w32.HWND, b bool, style int) { - originalStyle := int(w32.GetWindowLongPtr(hwnd, w32.GWL_STYLE)) - if originalStyle != 0 { - if b { - originalStyle |= style - } else { - originalStyle &^= style - } - w32.SetWindowLongPtr(hwnd, w32.GWL_STYLE, uintptr(originalStyle)) - } -} - -func SetExStyle(hwnd w32.HWND, b bool, style int) { - originalStyle := int(w32.GetWindowLongPtr(hwnd, w32.GWL_EXSTYLE)) - if originalStyle != 0 { - if b { - originalStyle |= style - } else { - originalStyle &^= style - } - w32.SetWindowLongPtr(hwnd, w32.GWL_EXSTYLE, uintptr(originalStyle)) - } -} - -func CreateWindow(className string, parent Controller, exStyle, style uint) w32.HWND { - instance := GetAppInstance() - var parentHwnd w32.HWND - if parent != nil { - parentHwnd = parent.Handle() - } - var hwnd w32.HWND - hwnd = w32.CreateWindowEx( - exStyle, - syscall.StringToUTF16Ptr(className), - nil, - style, - w32.CW_USEDEFAULT, - w32.CW_USEDEFAULT, - w32.CW_USEDEFAULT, - w32.CW_USEDEFAULT, - parentHwnd, - 0, - instance, - nil) - - if hwnd == 0 { - errStr := fmt.Sprintf("Error occurred in CreateWindow(%s, %v, %d, %d)", className, parent, exStyle, style) - panic(errStr) - } - - return hwnd -} - -func RegisterClass(className string, wndproc uintptr) { - instance := GetAppInstance() - icon := w32.LoadIconWithResourceID(instance, w32.IDI_APPLICATION) - - var wc w32.WNDCLASSEX - wc.Size = uint32(unsafe.Sizeof(wc)) - wc.Style = w32.CS_HREDRAW | w32.CS_VREDRAW - wc.WndProc = wndproc - wc.Instance = instance - wc.Background = w32.COLOR_BTNFACE + 1 - wc.Icon = icon - wc.Cursor = w32.LoadCursorWithResourceID(0, w32.IDC_ARROW) - wc.ClassName = syscall.StringToUTF16Ptr(className) - wc.MenuName = nil - wc.IconSm = icon - - if ret := w32.RegisterClassEx(&wc); ret == 0 { - panic(syscall.GetLastError()) - } -} - -func RegisterWindowMessage(name string) uint32 { - n := syscall.StringToUTF16Ptr(name) - - ret := w32.RegisterWindowMessage(n) - if ret == 0 { - panic(syscall.GetLastError()) - } - return ret -} - -func getMonitorInfo(hwnd w32.HWND) *w32.MONITORINFO { - currentMonitor := w32.MonitorFromWindow(hwnd, w32.MONITOR_DEFAULTTONEAREST) - var info w32.MONITORINFO - info.CbSize = uint32(unsafe.Sizeof(info)) - w32.GetMonitorInfo(currentMonitor, &info) - return &info -} -func getWindowInfo(hwnd w32.HWND) *w32.WINDOWINFO { - var info w32.WINDOWINFO - info.CbSize = uint32(unsafe.Sizeof(info)) - w32.GetWindowInfo(hwnd, &info) - return &info -} - -func RegClassOnlyOnce(className string) { - isExists := false - for _, class := range gRegisteredClasses { - if class == className { - isExists = true - break - } - } - - if !isExists { - RegisterClass(className, GeneralWndprocCallBack) - gRegisteredClasses = append(gRegisteredClasses, className) - } -} - -func ScreenToClientRect(hwnd w32.HWND, rect *w32.RECT) *Rect { - l, t, r, b := rect.Left, rect.Top, rect.Right, rect.Bottom - l1, t1, _ := w32.ScreenToClient(hwnd, int(l), int(t)) - r1, b1, _ := w32.ScreenToClient(hwnd, int(r), int(b)) - return NewRect(l1, t1, r1, b1) -} - -// ScaleWithDPI scales the pixels from the default DPI-Space (96) to the target DPI-Space. -func ScaleWithDPI(pixels int, dpi uint) int { - return (pixels * int(dpi)) / 96 -} - -// ScaleToDefaultDPI scales the pixels from scaled DPI-Space to default DPI-Space (96). -func ScaleToDefaultDPI(pixels int, dpi uint) int { - return (pixels * 96) / int(dpi) -} diff --git a/v2/internal/frontend/desktop/windows/winc/w32/comctl32.go b/v2/internal/frontend/desktop/windows/winc/w32/comctl32.go deleted file mode 100644 index b66709f5f..000000000 --- a/v2/internal/frontend/desktop/windows/winc/w32/comctl32.go +++ /dev/null @@ -1,112 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved. - */ - -package w32 - -import ( - "syscall" - "unsafe" -) - -var ( - modcomctl32 = syscall.NewLazyDLL("comctl32.dll") - - procInitCommonControlsEx = modcomctl32.NewProc("InitCommonControlsEx") - procImageList_Create = modcomctl32.NewProc("ImageList_Create") - procImageList_Destroy = modcomctl32.NewProc("ImageList_Destroy") - procImageList_GetImageCount = modcomctl32.NewProc("ImageList_GetImageCount") - procImageList_SetImageCount = modcomctl32.NewProc("ImageList_SetImageCount") - procImageList_Add = modcomctl32.NewProc("ImageList_Add") - procImageList_ReplaceIcon = modcomctl32.NewProc("ImageList_ReplaceIcon") - procImageList_Remove = modcomctl32.NewProc("ImageList_Remove") - procTrackMouseEvent = modcomctl32.NewProc("_TrackMouseEvent") -) - -func InitCommonControlsEx(lpInitCtrls *INITCOMMONCONTROLSEX) bool { - ret, _, _ := procInitCommonControlsEx.Call( - uintptr(unsafe.Pointer(lpInitCtrls))) - - return ret != 0 -} - -func ImageList_Create(cx, cy int, flags uint, cInitial, cGrow int) HIMAGELIST { - ret, _, _ := procImageList_Create.Call( - uintptr(cx), - uintptr(cy), - uintptr(flags), - uintptr(cInitial), - uintptr(cGrow)) - - if ret == 0 { - panic("Create image list failed") - } - - return HIMAGELIST(ret) -} - -func ImageList_Destroy(himl HIMAGELIST) bool { - ret, _, _ := procImageList_Destroy.Call( - uintptr(himl)) - - return ret != 0 -} - -func ImageList_GetImageCount(himl HIMAGELIST) int { - ret, _, _ := procImageList_GetImageCount.Call( - uintptr(himl)) - - return int(ret) -} - -func ImageList_SetImageCount(himl HIMAGELIST, uNewCount uint) bool { - ret, _, _ := procImageList_SetImageCount.Call( - uintptr(himl), - uintptr(uNewCount)) - - return ret != 0 -} - -func ImageList_Add(himl HIMAGELIST, hbmImage, hbmMask HBITMAP) int { - ret, _, _ := procImageList_Add.Call( - uintptr(himl), - uintptr(hbmImage), - uintptr(hbmMask)) - - return int(ret) -} - -func ImageList_ReplaceIcon(himl HIMAGELIST, i int, hicon HICON) int { - ret, _, _ := procImageList_ReplaceIcon.Call( - uintptr(himl), - uintptr(i), - uintptr(hicon)) - - return int(ret) -} - -func ImageList_AddIcon(himl HIMAGELIST, hicon HICON) int { - return ImageList_ReplaceIcon(himl, -1, hicon) -} - -func ImageList_Remove(himl HIMAGELIST, i int) bool { - ret, _, _ := procImageList_Remove.Call( - uintptr(himl), - uintptr(i)) - - return ret != 0 -} - -func ImageList_RemoveAll(himl HIMAGELIST) bool { - return ImageList_Remove(himl, -1) -} - -func TrackMouseEvent(tme *TRACKMOUSEEVENT) bool { - ret, _, _ := procTrackMouseEvent.Call( - uintptr(unsafe.Pointer(tme))) - - return ret != 0 -} diff --git a/v2/internal/frontend/desktop/windows/winc/w32/comdlg32.go b/v2/internal/frontend/desktop/windows/winc/w32/comdlg32.go deleted file mode 100644 index d28922c33..000000000 --- a/v2/internal/frontend/desktop/windows/winc/w32/comdlg32.go +++ /dev/null @@ -1,40 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved. - */ -package w32 - -import ( - "syscall" - "unsafe" -) - -var ( - modcomdlg32 = syscall.NewLazyDLL("comdlg32.dll") - - procGetSaveFileName = modcomdlg32.NewProc("GetSaveFileNameW") - procGetOpenFileName = modcomdlg32.NewProc("GetOpenFileNameW") - procCommDlgExtendedError = modcomdlg32.NewProc("CommDlgExtendedError") -) - -func GetOpenFileName(ofn *OPENFILENAME) bool { - ret, _, _ := procGetOpenFileName.Call( - uintptr(unsafe.Pointer(ofn))) - - return ret != 0 -} - -func GetSaveFileName(ofn *OPENFILENAME) bool { - ret, _, _ := procGetSaveFileName.Call( - uintptr(unsafe.Pointer(ofn))) - - return ret != 0 -} - -func CommDlgExtendedError() uint { - ret, _, _ := procCommDlgExtendedError.Call() - - return uint(ret) -} diff --git a/v2/internal/frontend/desktop/windows/winc/w32/constants.go b/v2/internal/frontend/desktop/windows/winc/w32/constants.go deleted file mode 100644 index 49b507a23..000000000 --- a/v2/internal/frontend/desktop/windows/winc/w32/constants.go +++ /dev/null @@ -1,3526 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved. - */ -package w32 - -const ( - FALSE = 0 - TRUE = 1 -) - -const ( - NO_ERROR = 0 - ERROR_SUCCESS = 0 - ERROR_FILE_NOT_FOUND = 2 - ERROR_PATH_NOT_FOUND = 3 - ERROR_ACCESS_DENIED = 5 - ERROR_INVALID_HANDLE = 6 - ERROR_BAD_FORMAT = 11 - ERROR_INVALID_NAME = 123 - ERROR_MORE_DATA = 234 - ERROR_NO_MORE_ITEMS = 259 - ERROR_INVALID_SERVICE_CONTROL = 1052 - ERROR_SERVICE_REQUEST_TIMEOUT = 1053 - ERROR_SERVICE_NO_THREAD = 1054 - ERROR_SERVICE_DATABASE_LOCKED = 1055 - ERROR_SERVICE_ALREADY_RUNNING = 1056 - ERROR_SERVICE_DISABLED = 1058 - ERROR_SERVICE_DOES_NOT_EXIST = 1060 - ERROR_SERVICE_CANNOT_ACCEPT_CTRL = 1061 - ERROR_SERVICE_NOT_ACTIVE = 1062 - ERROR_DATABASE_DOES_NOT_EXIST = 1065 - ERROR_SERVICE_DEPENDENCY_FAIL = 1068 - ERROR_SERVICE_LOGON_FAILED = 1069 - ERROR_SERVICE_MARKED_FOR_DELETE = 1072 - ERROR_SERVICE_DEPENDENCY_DELETED = 1075 -) - -const ( - SE_ERR_FNF = 2 - SE_ERR_PNF = 3 - SE_ERR_ACCESSDENIED = 5 - SE_ERR_OOM = 8 - SE_ERR_DLLNOTFOUND = 32 - SE_ERR_SHARE = 26 - SE_ERR_ASSOCINCOMPLETE = 27 - SE_ERR_DDETIMEOUT = 28 - SE_ERR_DDEFAIL = 29 - SE_ERR_DDEBUSY = 30 - SE_ERR_NOASSOC = 31 -) - -const ( - CW_USEDEFAULT = ^0x7fffffff -) - -const ( - IMAGE_BITMAP = 0 - IMAGE_ICON = 1 - IMAGE_CURSOR = 2 - IMAGE_ENHMETAFILE = 3 -) - -// ShowWindow constants -const ( - SW_HIDE = 0 - SW_NORMAL = 1 - SW_SHOWNORMAL = 1 - SW_SHOWMINIMIZED = 2 - SW_MAXIMIZE = 3 - SW_SHOWMAXIMIZED = 3 - SW_SHOWNOACTIVATE = 4 - SW_SHOW = 5 - SW_MINIMIZE = 6 - SW_SHOWMINNOACTIVE = 7 - SW_SHOWNA = 8 - SW_RESTORE = 9 - SW_SHOWDEFAULT = 10 - SW_FORCEMINIMIZE = 11 -) - -// Window class styles -const ( - CS_VREDRAW = 0x00000001 - CS_HREDRAW = 0x00000002 - CS_KEYCVTWINDOW = 0x00000004 - CS_DBLCLKS = 0x00000008 - CS_OWNDC = 0x00000020 - CS_CLASSDC = 0x00000040 - CS_PARENTDC = 0x00000080 - CS_NOKEYCVT = 0x00000100 - CS_NOCLOSE = 0x00000200 - CS_SAVEBITS = 0x00000800 - CS_BYTEALIGNCLIENT = 0x00001000 - CS_BYTEALIGNWINDOW = 0x00002000 - CS_GLOBALCLASS = 0x00004000 - CS_IME = 0x00010000 - CS_DROPSHADOW = 0x00020000 -) - -// Predefined cursor constants -const ( - IDC_ARROW = 32512 - IDC_IBEAM = 32513 - IDC_WAIT = 32514 - IDC_CROSS = 32515 - IDC_UPARROW = 32516 - IDC_SIZENWSE = 32642 - IDC_SIZENESW = 32643 - IDC_SIZEWE = 32644 - IDC_SIZENS = 32645 - IDC_SIZEALL = 32646 - IDC_NO = 32648 - IDC_HAND = 32649 - IDC_APPSTARTING = 32650 - IDC_HELP = 32651 - IDC_ICON = 32641 - IDC_SIZE = 32640 -) - -// Predefined icon constants -const ( - IDI_APPLICATION = 32512 - IDI_HAND = 32513 - IDI_QUESTION = 32514 - IDI_EXCLAMATION = 32515 - IDI_ASTERISK = 32516 - IDI_WINLOGO = 32517 - IDI_WARNING = IDI_EXCLAMATION - IDI_ERROR = IDI_HAND - IDI_INFORMATION = IDI_ASTERISK -) - -// Button style constants -const ( - BS_3STATE = 5 - BS_AUTO3STATE = 6 - BS_AUTOCHECKBOX = 3 - BS_AUTORADIOBUTTON = 9 - BS_BITMAP = 128 - BS_BOTTOM = 0x800 - BS_CENTER = 0x300 - BS_CHECKBOX = 2 - BS_DEFPUSHBUTTON = 1 - BS_GROUPBOX = 7 - BS_ICON = 64 - BS_LEFT = 256 - BS_LEFTTEXT = 32 - BS_MULTILINE = 0x2000 - BS_NOTIFY = 0x4000 - BS_OWNERDRAW = 0xB - BS_PUSHBUTTON = 0 - BS_PUSHLIKE = 4096 - BS_RADIOBUTTON = 4 - BS_RIGHT = 512 - BS_RIGHTBUTTON = 32 - BS_TEXT = 0 - BS_TOP = 0x400 - BS_USERBUTTON = 8 - BS_VCENTER = 0xC00 - BS_FLAT = 0x8000 - BS_SPLITBUTTON = 0x000C // >= Vista - BS_DEFSPLITBUTTON = 0x000D // >= Vista -) - -// Button state constants -const ( - BST_CHECKED = 1 - BST_INDETERMINATE = 2 - BST_UNCHECKED = 0 - BST_FOCUS = 8 - BST_PUSHED = 4 -) - -// Predefined brushes constants -const ( - COLOR_3DDKSHADOW = 21 - COLOR_3DFACE = 15 - COLOR_3DHILIGHT = 20 - COLOR_3DHIGHLIGHT = 20 - COLOR_3DLIGHT = 22 - COLOR_BTNHILIGHT = 20 - COLOR_3DSHADOW = 16 - COLOR_ACTIVEBORDER = 10 - COLOR_ACTIVECAPTION = 2 - COLOR_APPWORKSPACE = 12 - COLOR_BACKGROUND = 1 - COLOR_DESKTOP = 1 - COLOR_BTNFACE = 15 - COLOR_BTNHIGHLIGHT = 20 - COLOR_BTNSHADOW = 16 - COLOR_BTNTEXT = 18 - COLOR_CAPTIONTEXT = 9 - COLOR_GRAYTEXT = 17 - COLOR_HIGHLIGHT = 13 - COLOR_HIGHLIGHTTEXT = 14 - COLOR_INACTIVEBORDER = 11 - COLOR_INACTIVECAPTION = 3 - COLOR_INACTIVECAPTIONTEXT = 19 - COLOR_INFOBK = 24 - COLOR_INFOTEXT = 23 - COLOR_MENU = 4 - COLOR_MENUTEXT = 7 - COLOR_SCROLLBAR = 0 - COLOR_WINDOW = 5 - COLOR_WINDOWFRAME = 6 - COLOR_WINDOWTEXT = 8 - COLOR_HOTLIGHT = 26 - COLOR_GRADIENTACTIVECAPTION = 27 - COLOR_GRADIENTINACTIVECAPTION = 28 -) - -// Button message constants -const ( - BM_CLICK = 245 - BM_GETCHECK = 240 - BM_GETIMAGE = 246 - BM_GETSTATE = 242 - BM_SETCHECK = 241 - BM_SETIMAGE = 247 - BM_SETSTATE = 243 - BM_SETSTYLE = 244 -) - -// Button notifications -const ( - BN_CLICKED = 0 - BN_PAINT = 1 - BN_HILITE = 2 - BN_PUSHED = BN_HILITE - BN_UNHILITE = 3 - BN_UNPUSHED = BN_UNHILITE - BN_DISABLE = 4 - BN_DOUBLECLICKED = 5 - BN_DBLCLK = BN_DOUBLECLICKED - BN_SETFOCUS = 6 - BN_KILLFOCUS = 7 -) - -// TrackPopupMenu[Ex] flags -const ( - TPM_CENTERALIGN = 0x0004 - TPM_LEFTALIGN = 0x0000 - TPM_RIGHTALIGN = 0x0008 - TPM_BOTTOMALIGN = 0x0020 - TPM_TOPALIGN = 0x0000 - TPM_VCENTERALIGN = 0x0010 - TPM_NONOTIFY = 0x0080 - TPM_RETURNCMD = 0x0100 - TPM_LEFTBUTTON = 0x0000 - TPM_RIGHTBUTTON = 0x0002 - TPM_HORNEGANIMATION = 0x0800 - TPM_HORPOSANIMATION = 0x0400 - TPM_NOANIMATION = 0x4000 - TPM_VERNEGANIMATION = 0x2000 - TPM_VERPOSANIMATION = 0x1000 - TPM_HORIZONTAL = 0x0000 - TPM_VERTICAL = 0x0040 -) - -// GetWindowLong and GetWindowLongPtr constants -const ( - GWL_EXSTYLE = -20 - GWL_STYLE = -16 - GWL_WNDPROC = -4 - GWLP_WNDPROC = -4 - GWL_HINSTANCE = -6 - GWLP_HINSTANCE = -6 - GWL_HWNDPARENT = -8 - GWLP_HWNDPARENT = -8 - GWL_ID = -12 - GWLP_ID = -12 - GWL_USERDATA = -21 - GWLP_USERDATA = -21 -) - -// Window style constants -const ( - WS_OVERLAPPED = 0x00000000 - WS_POPUP = 0x80000000 - WS_CHILD = 0x40000000 - WS_MINIMIZE = 0x20000000 - WS_VISIBLE = 0x10000000 - WS_DISABLED = 0x08000000 - WS_CLIPSIBLINGS = 0x04000000 - WS_CLIPCHILDREN = 0x02000000 - WS_MAXIMIZE = 0x01000000 - WS_CAPTION = 0x00C00000 - WS_BORDER = 0x00800000 - WS_DLGFRAME = 0x00400000 - WS_VSCROLL = 0x00200000 - WS_HSCROLL = 0x00100000 - WS_SYSMENU = 0x00080000 - WS_THICKFRAME = 0x00040000 - WS_GROUP = 0x00020000 - WS_TABSTOP = 0x00010000 - WS_MINIMIZEBOX = 0x00020000 - WS_MAXIMIZEBOX = 0x00010000 - WS_TILED = 0x00000000 - WS_ICONIC = 0x20000000 - WS_SIZEBOX = 0x00040000 - WS_OVERLAPPEDWINDOW = 0x00000000 | 0x00C00000 | 0x00080000 | 0x00040000 | 0x00020000 | 0x00010000 - WS_POPUPWINDOW = 0x80000000 | 0x00800000 | 0x00080000 - WS_CHILDWINDOW = 0x40000000 -) - -// Extended window style constants -const ( - WS_EX_DLGMODALFRAME = 0x00000001 - WS_EX_NOPARENTNOTIFY = 0x00000004 - WS_EX_TOPMOST = 0x00000008 - WS_EX_ACCEPTFILES = 0x00000010 - WS_EX_TRANSPARENT = 0x00000020 - WS_EX_MDICHILD = 0x00000040 - WS_EX_TOOLWINDOW = 0x00000080 - WS_EX_WINDOWEDGE = 0x00000100 - WS_EX_CLIENTEDGE = 0x00000200 - WS_EX_CONTEXTHELP = 0x00000400 - WS_EX_RIGHT = 0x00001000 - WS_EX_LEFT = 0x00000000 - WS_EX_RTLREADING = 0x00002000 - WS_EX_LTRREADING = 0x00000000 - WS_EX_LEFTSCROLLBAR = 0x00004000 - WS_EX_RIGHTSCROLLBAR = 0x00000000 - WS_EX_CONTROLPARENT = 0x00010000 - WS_EX_STATICEDGE = 0x00020000 - WS_EX_APPWINDOW = 0x00040000 - WS_EX_OVERLAPPEDWINDOW = 0x00000100 | 0x00000200 - WS_EX_PALETTEWINDOW = 0x00000100 | 0x00000080 | 0x00000008 - WS_EX_LAYERED = 0x00080000 - WS_EX_NOINHERITLAYOUT = 0x00100000 - WS_EX_NOREDIRECTIONBITMAP = 0x00200000 - WS_EX_LAYOUTRTL = 0x00400000 - WS_EX_NOACTIVATE = 0x08000000 -) - -// Window message constants -const ( - WM_APP = 32768 - WM_ACTIVATE = 6 - WM_ACTIVATEAPP = 28 - WM_AFXFIRST = 864 - WM_AFXLAST = 895 - WM_ASKCBFORMATNAME = 780 - WM_CANCELJOURNAL = 75 - WM_CANCELMODE = 31 - WM_CAPTURECHANGED = 533 - WM_CHANGECBCHAIN = 781 - WM_CHAR = 258 - WM_CHARTOITEM = 47 - WM_CHILDACTIVATE = 34 - WM_CLEAR = 771 - WM_CLOSE = 16 - WM_COMMAND = 273 - WM_COMMNOTIFY = 68 /* OBSOLETE */ - WM_COMPACTING = 65 - WM_COMPAREITEM = 57 - WM_CONTEXTMENU = 123 - WM_COPY = 769 - WM_COPYDATA = 74 - WM_CREATE = 1 - WM_CTLCOLORBTN = 309 - WM_CTLCOLORDLG = 310 - WM_CTLCOLOREDIT = 307 - WM_CTLCOLORLISTBOX = 308 - WM_CTLCOLORMSGBOX = 306 - WM_CTLCOLORSCROLLBAR = 311 - WM_CTLCOLORSTATIC = 312 - WM_CUT = 768 - WM_DEADCHAR = 259 - WM_DELETEITEM = 45 - WM_DESTROY = 2 - WM_DESTROYCLIPBOARD = 775 - WM_DEVICECHANGE = 537 - WM_DEVMODECHANGE = 27 - WM_DISPLAYCHANGE = 126 - WM_DRAWCLIPBOARD = 776 - WM_DRAWITEM = 43 - WM_DROPFILES = 563 - WM_ENABLE = 10 - WM_ENDSESSION = 22 - WM_ENTERIDLE = 289 - WM_ENTERMENULOOP = 529 - WM_ENTERSIZEMOVE = 561 - WM_ERASEBKGND = 20 - WM_EXITMENULOOP = 530 - WM_EXITSIZEMOVE = 562 - WM_FONTCHANGE = 29 - WM_GETDLGCODE = 135 - WM_GETFONT = 49 - WM_GETHOTKEY = 51 - WM_GETICON = 127 - WM_GETMINMAXINFO = 36 - WM_GETTEXT = 13 - WM_GETTEXTLENGTH = 14 - WM_HANDHELDFIRST = 856 - WM_HANDHELDLAST = 863 - WM_HELP = 83 - WM_HOTKEY = 786 - WM_HSCROLL = 276 - WM_HSCROLLCLIPBOARD = 782 - WM_ICONERASEBKGND = 39 - WM_INITDIALOG = 272 - WM_INITMENU = 278 - WM_INITMENUPOPUP = 279 - WM_INPUT = 0x00FF - WM_INPUTLANGCHANGE = 81 - WM_INPUTLANGCHANGEREQUEST = 80 - WM_KEYDOWN = 256 - WM_KEYUP = 257 - WM_KILLFOCUS = 8 - WM_MDIACTIVATE = 546 - WM_MDICASCADE = 551 - WM_MDICREATE = 544 - WM_MDIDESTROY = 545 - WM_MDIGETACTIVE = 553 - WM_MDIICONARRANGE = 552 - WM_MDIMAXIMIZE = 549 - WM_MDINEXT = 548 - WM_MDIREFRESHMENU = 564 - WM_MDIRESTORE = 547 - WM_MDISETMENU = 560 - WM_MDITILE = 550 - WM_MEASUREITEM = 44 - WM_GETOBJECT = 0x003D - WM_CHANGEUISTATE = 0x0127 - WM_UPDATEUISTATE = 0x0128 - WM_QUERYUISTATE = 0x0129 - WM_UNINITMENUPOPUP = 0x0125 - WM_MENURBUTTONUP = 290 - WM_MENUCOMMAND = 0x0126 - WM_MENUGETOBJECT = 0x0124 - WM_MENUDRAG = 0x0123 - WM_APPCOMMAND = 0x0319 - WM_MENUCHAR = 288 - WM_MENUSELECT = 287 - WM_MOVE = 3 - WM_MOVING = 534 - WM_NCACTIVATE = 134 - WM_NCCALCSIZE = 131 - WM_NCCREATE = 129 - WM_NCDESTROY = 130 - WM_NCHITTEST = 132 - WM_NCLBUTTONDBLCLK = 163 - WM_NCLBUTTONDOWN = 161 - WM_NCLBUTTONUP = 162 - WM_NCMBUTTONDBLCLK = 169 - WM_NCMBUTTONDOWN = 167 - WM_NCMBUTTONUP = 168 - WM_NCXBUTTONDOWN = 171 - WM_NCXBUTTONUP = 172 - WM_NCXBUTTONDBLCLK = 173 - WM_NCMOUSEHOVER = 0x02A0 - WM_NCMOUSELEAVE = 0x02A2 - WM_NCMOUSEMOVE = 160 - WM_NCPAINT = 133 - WM_NCRBUTTONDBLCLK = 166 - WM_NCRBUTTONDOWN = 164 - WM_NCRBUTTONUP = 165 - WM_NEXTDLGCTL = 40 - WM_NEXTMENU = 531 - WM_NOTIFY = 78 - WM_NOTIFYFORMAT = 85 - WM_NULL = 0 - WM_PAINT = 15 - WM_PAINTCLIPBOARD = 777 - WM_PAINTICON = 38 - WM_PALETTECHANGED = 785 - WM_PALETTEISCHANGING = 784 - WM_PARENTNOTIFY = 528 - WM_PASTE = 770 - WM_PENWINFIRST = 896 - WM_PENWINLAST = 911 - WM_POWER = 72 - WM_POWERBROADCAST = 536 - WM_PRINT = 791 - WM_PRINTCLIENT = 792 - WM_QUERYDRAGICON = 55 - WM_QUERYENDSESSION = 17 - WM_QUERYNEWPALETTE = 783 - WM_QUERYOPEN = 19 - WM_QUEUESYNC = 35 - WM_QUIT = 18 - WM_RENDERALLFORMATS = 774 - WM_RENDERFORMAT = 773 - WM_SETCURSOR = 32 - WM_SETFOCUS = 7 - WM_SETFONT = 48 - WM_SETHOTKEY = 50 - WM_SETICON = 128 - WM_SETREDRAW = 11 - WM_SETTEXT = 12 - WM_SETTINGCHANGE = 26 - WM_SHOWWINDOW = 24 - WM_SIZE = 5 - WM_SIZECLIPBOARD = 779 - WM_SIZING = 532 - WM_SPOOLERSTATUS = 42 - WM_STYLECHANGED = 125 - WM_STYLECHANGING = 124 - WM_SYSCHAR = 262 - WM_SYSCOLORCHANGE = 21 - WM_SYSCOMMAND = 274 - WM_SYSDEADCHAR = 263 - WM_SYSKEYDOWN = 260 - WM_SYSKEYUP = 261 - WM_TCARD = 82 - WM_THEMECHANGED = 794 - WM_TIMECHANGE = 30 - WM_TIMER = 275 - WM_UNDO = 772 - WM_USER = 1024 - WM_USERCHANGED = 84 - WM_VKEYTOITEM = 46 - WM_VSCROLL = 277 - WM_VSCROLLCLIPBOARD = 778 - WM_WINDOWPOSCHANGED = 71 - WM_WINDOWPOSCHANGING = 70 - WM_WININICHANGE = 26 - WM_KEYFIRST = 256 - WM_KEYLAST = 264 - WM_SYNCPAINT = 136 - WM_MOUSEACTIVATE = 33 - WM_MOUSEMOVE = 512 - WM_LBUTTONDOWN = 513 - WM_LBUTTONUP = 514 - WM_LBUTTONDBLCLK = 515 - WM_RBUTTONDOWN = 516 - WM_RBUTTONUP = 517 - WM_RBUTTONDBLCLK = 518 - WM_MBUTTONDOWN = 519 - WM_MBUTTONUP = 520 - WM_MBUTTONDBLCLK = 521 - WM_MOUSEWHEEL = 522 - WM_MOUSEFIRST = 512 - WM_XBUTTONDOWN = 523 - WM_XBUTTONUP = 524 - WM_XBUTTONDBLCLK = 525 - WM_MOUSELAST = 525 - WM_MOUSEHOVER = 0x2A1 - WM_MOUSELEAVE = 0x2A3 - WM_CLIPBOARDUPDATE = 0x031D -) - -// WM_ACTIVATE -const ( - WA_INACTIVE = 0 - WA_ACTIVE = 1 - WA_CLICKACTIVE = 2 -) - -const LF_FACESIZE = 32 - -// Font weight constants -const ( - FW_DONTCARE = 0 - FW_THIN = 100 - FW_EXTRALIGHT = 200 - FW_ULTRALIGHT = FW_EXTRALIGHT - FW_LIGHT = 300 - FW_NORMAL = 400 - FW_REGULAR = 400 - FW_MEDIUM = 500 - FW_SEMIBOLD = 600 - FW_DEMIBOLD = FW_SEMIBOLD - FW_BOLD = 700 - FW_EXTRABOLD = 800 - FW_ULTRABOLD = FW_EXTRABOLD - FW_HEAVY = 900 - FW_BLACK = FW_HEAVY -) - -// Charset constants -const ( - ANSI_CHARSET = 0 - DEFAULT_CHARSET = 1 - SYMBOL_CHARSET = 2 - SHIFTJIS_CHARSET = 128 - HANGEUL_CHARSET = 129 - HANGUL_CHARSET = 129 - GB2312_CHARSET = 134 - CHINESEBIG5_CHARSET = 136 - GREEK_CHARSET = 161 - TURKISH_CHARSET = 162 - HEBREW_CHARSET = 177 - ARABIC_CHARSET = 178 - BALTIC_CHARSET = 186 - RUSSIAN_CHARSET = 204 - THAI_CHARSET = 222 - EASTEUROPE_CHARSET = 238 - OEM_CHARSET = 255 - JOHAB_CHARSET = 130 - VIETNAMESE_CHARSET = 163 - MAC_CHARSET = 77 -) - -// Font output precision constants -const ( - OUT_DEFAULT_PRECIS = 0 - OUT_STRING_PRECIS = 1 - OUT_CHARACTER_PRECIS = 2 - OUT_STROKE_PRECIS = 3 - OUT_TT_PRECIS = 4 - OUT_DEVICE_PRECIS = 5 - OUT_RASTER_PRECIS = 6 - OUT_TT_ONLY_PRECIS = 7 - OUT_OUTLINE_PRECIS = 8 - OUT_PS_ONLY_PRECIS = 10 -) - -// Font clipping precision constants -const ( - CLIP_DEFAULT_PRECIS = 0 - CLIP_CHARACTER_PRECIS = 1 - CLIP_STROKE_PRECIS = 2 - CLIP_MASK = 15 - CLIP_LH_ANGLES = 16 - CLIP_TT_ALWAYS = 32 - CLIP_EMBEDDED = 128 -) - -// Font output quality constants -const ( - DEFAULT_QUALITY = 0 - DRAFT_QUALITY = 1 - PROOF_QUALITY = 2 - NONANTIALIASED_QUALITY = 3 - ANTIALIASED_QUALITY = 4 - CLEARTYPE_QUALITY = 5 -) - -// Font pitch constants -const ( - DEFAULT_PITCH = 0 - FIXED_PITCH = 1 - VARIABLE_PITCH = 2 -) - -// Font family constants -const ( - FF_DECORATIVE = 80 - FF_DONTCARE = 0 - FF_MODERN = 48 - FF_ROMAN = 16 - FF_SCRIPT = 64 - FF_SWISS = 32 -) - -// DeviceCapabilities capabilities -const ( - DC_FIELDS = 1 - DC_PAPERS = 2 - DC_PAPERSIZE = 3 - DC_MINEXTENT = 4 - DC_MAXEXTENT = 5 - DC_BINS = 6 - DC_DUPLEX = 7 - DC_SIZE = 8 - DC_EXTRA = 9 - DC_VERSION = 10 - DC_DRIVER = 11 - DC_BINNAMES = 12 - DC_ENUMRESOLUTIONS = 13 - DC_FILEDEPENDENCIES = 14 - DC_TRUETYPE = 15 - DC_PAPERNAMES = 16 - DC_ORIENTATION = 17 - DC_COPIES = 18 - DC_BINADJUST = 19 - DC_EMF_COMPLIANT = 20 - DC_DATATYPE_PRODUCED = 21 - DC_COLLATE = 22 - DC_MANUFACTURER = 23 - DC_MODEL = 24 - DC_PERSONALITY = 25 - DC_PRINTRATE = 26 - DC_PRINTRATEUNIT = 27 - DC_PRINTERMEM = 28 - DC_MEDIAREADY = 29 - DC_STAPLE = 30 - DC_PRINTRATEPPM = 31 - DC_COLORDEVICE = 32 - DC_NUP = 33 - DC_MEDIATYPENAMES = 34 - DC_MEDIATYPES = 35 -) - -// GetDeviceCaps index constants -const ( - DRIVERVERSION = 0 - TECHNOLOGY = 2 - HORZSIZE = 4 - VERTSIZE = 6 - HORZRES = 8 - VERTRES = 10 - LOGPIXELSX = 88 - LOGPIXELSY = 90 - BITSPIXEL = 12 - PLANES = 14 - NUMBRUSHES = 16 - NUMPENS = 18 - NUMFONTS = 22 - NUMCOLORS = 24 - NUMMARKERS = 20 - ASPECTX = 40 - ASPECTY = 42 - ASPECTXY = 44 - PDEVICESIZE = 26 - CLIPCAPS = 36 - SIZEPALETTE = 104 - NUMRESERVED = 106 - COLORRES = 108 - PHYSICALWIDTH = 110 - PHYSICALHEIGHT = 111 - PHYSICALOFFSETX = 112 - PHYSICALOFFSETY = 113 - SCALINGFACTORX = 114 - SCALINGFACTORY = 115 - VREFRESH = 116 - DESKTOPHORZRES = 118 - DESKTOPVERTRES = 117 - BLTALIGNMENT = 119 - SHADEBLENDCAPS = 120 - COLORMGMTCAPS = 121 - RASTERCAPS = 38 - CURVECAPS = 28 - LINECAPS = 30 - POLYGONALCAPS = 32 - TEXTCAPS = 34 -) - -// GetDeviceCaps TECHNOLOGY constants -const ( - DT_PLOTTER = 0 - DT_RASDISPLAY = 1 - DT_RASPRINTER = 2 - DT_RASCAMERA = 3 - DT_CHARSTREAM = 4 - DT_METAFILE = 5 - DT_DISPFILE = 6 -) - -// GetDeviceCaps SHADEBLENDCAPS constants -const ( - SB_NONE = 0x00 - SB_CONST_ALPHA = 0x01 - SB_PIXEL_ALPHA = 0x02 - SB_PREMULT_ALPHA = 0x04 - SB_GRAD_RECT = 0x10 - SB_GRAD_TRI = 0x20 -) - -// GetDeviceCaps COLORMGMTCAPS constants -const ( - CM_NONE = 0x00 - CM_DEVICE_ICM = 0x01 - CM_GAMMA_RAMP = 0x02 - CM_CMYK_COLOR = 0x04 -) - -// GetDeviceCaps RASTERCAPS constants -const ( - RC_BANDING = 2 - RC_BITBLT = 1 - RC_BITMAP64 = 8 - RC_DI_BITMAP = 128 - RC_DIBTODEV = 512 - RC_FLOODFILL = 4096 - RC_GDI20_OUTPUT = 16 - RC_PALETTE = 256 - RC_SCALING = 4 - RC_STRETCHBLT = 2048 - RC_STRETCHDIB = 8192 - RC_DEVBITS = 0x8000 - RC_OP_DX_OUTPUT = 0x4000 -) - -// GetDeviceCaps CURVECAPS constants -const ( - CC_NONE = 0 - CC_CIRCLES = 1 - CC_PIE = 2 - CC_CHORD = 4 - CC_ELLIPSES = 8 - CC_WIDE = 16 - CC_STYLED = 32 - CC_WIDESTYLED = 64 - CC_INTERIORS = 128 - CC_ROUNDRECT = 256 -) - -// GetDeviceCaps LINECAPS constants -const ( - LC_NONE = 0 - LC_POLYLINE = 2 - LC_MARKER = 4 - LC_POLYMARKER = 8 - LC_WIDE = 16 - LC_STYLED = 32 - LC_WIDESTYLED = 64 - LC_INTERIORS = 128 -) - -// GetDeviceCaps POLYGONALCAPS constants -const ( - PC_NONE = 0 - PC_POLYGON = 1 - PC_POLYPOLYGON = 256 - PC_PATHS = 512 - PC_RECTANGLE = 2 - PC_WINDPOLYGON = 4 - PC_SCANLINE = 8 - PC_TRAPEZOID = 4 - PC_WIDE = 16 - PC_STYLED = 32 - PC_WIDESTYLED = 64 - PC_INTERIORS = 128 -) - -// GetDeviceCaps TEXTCAPS constants -const ( - TC_OP_CHARACTER = 1 - TC_OP_STROKE = 2 - TC_CP_STROKE = 4 - TC_CR_90 = 8 - TC_CR_ANY = 16 - TC_SF_X_YINDEP = 32 - TC_SA_DOUBLE = 64 - TC_SA_INTEGER = 128 - TC_SA_CONTIN = 256 - TC_EA_DOUBLE = 512 - TC_IA_ABLE = 1024 - TC_UA_ABLE = 2048 - TC_SO_ABLE = 4096 - TC_RA_ABLE = 8192 - TC_VA_ABLE = 16384 - TC_RESERVED = 32768 - TC_SCROLLBLT = 65536 -) - -// Static control styles -const ( - SS_BITMAP = 14 - SS_BLACKFRAME = 7 - SS_BLACKRECT = 4 - SS_CENTER = 1 - SS_CENTERIMAGE = 512 - SS_EDITCONTROL = 0x2000 - SS_ENHMETAFILE = 15 - SS_ETCHEDFRAME = 18 - SS_ETCHEDHORZ = 16 - SS_ETCHEDVERT = 17 - SS_GRAYFRAME = 8 - SS_GRAYRECT = 5 - SS_ICON = 3 - SS_LEFT = 0 - SS_LEFTNOWORDWRAP = 0xc - SS_NOPREFIX = 128 - SS_NOTIFY = 256 - SS_OWNERDRAW = 0xd - SS_REALSIZECONTROL = 0x040 - SS_REALSIZEIMAGE = 0x800 - SS_RIGHT = 2 - SS_RIGHTJUST = 0x400 - SS_SIMPLE = 11 - SS_SUNKEN = 4096 - SS_WHITEFRAME = 9 - SS_WHITERECT = 6 - SS_USERITEM = 10 - SS_TYPEMASK = 0x0000001F - SS_ENDELLIPSIS = 0x00004000 - SS_PATHELLIPSIS = 0x00008000 - SS_WORDELLIPSIS = 0x0000C000 - SS_ELLIPSISMASK = 0x0000C000 -) - -// Edit styles -const ( - ES_LEFT = 0x0000 - ES_CENTER = 0x0001 - ES_RIGHT = 0x0002 - ES_MULTILINE = 0x0004 - ES_UPPERCASE = 0x0008 - ES_LOWERCASE = 0x0010 - ES_PASSWORD = 0x0020 - ES_AUTOVSCROLL = 0x0040 - ES_AUTOHSCROLL = 0x0080 - ES_NOHIDESEL = 0x0100 - ES_OEMCONVERT = 0x0400 - ES_READONLY = 0x0800 - ES_WANTRETURN = 0x1000 - ES_NUMBER = 0x2000 -) - -// Edit notifications -const ( - EN_SETFOCUS = 0x0100 - EN_KILLFOCUS = 0x0200 - EN_CHANGE = 0x0300 - EN_UPDATE = 0x0400 - EN_ERRSPACE = 0x0500 - EN_MAXTEXT = 0x0501 - EN_HSCROLL = 0x0601 - EN_VSCROLL = 0x0602 - EN_ALIGN_LTR_EC = 0x0700 - EN_ALIGN_RTL_EC = 0x0701 -) - -// Edit messages -const ( - EM_GETSEL = 0x00B0 - EM_SETSEL = 0x00B1 - EM_GETRECT = 0x00B2 - EM_SETRECT = 0x00B3 - EM_SETRECTNP = 0x00B4 - EM_SCROLL = 0x00B5 - EM_LINESCROLL = 0x00B6 - EM_SCROLLCARET = 0x00B7 - EM_GETMODIFY = 0x00B8 - EM_SETMODIFY = 0x00B9 - EM_GETLINECOUNT = 0x00BA - EM_LINEINDEX = 0x00BB - EM_SETHANDLE = 0x00BC - EM_GETHANDLE = 0x00BD - EM_GETTHUMB = 0x00BE - EM_LINELENGTH = 0x00C1 - EM_REPLACESEL = 0x00C2 - EM_GETLINE = 0x00C4 - EM_LIMITTEXT = 0x00C5 - EM_CANUNDO = 0x00C6 - EM_UNDO = 0x00C7 - EM_FMTLINES = 0x00C8 - EM_LINEFROMCHAR = 0x00C9 - EM_SETTABSTOPS = 0x00CB - EM_SETPASSWORDCHAR = 0x00CC - EM_EMPTYUNDOBUFFER = 0x00CD - EM_GETFIRSTVISIBLELINE = 0x00CE - EM_SETREADONLY = 0x00CF - EM_SETWORDBREAKPROC = 0x00D0 - EM_GETWORDBREAKPROC = 0x00D1 - EM_GETPASSWORDCHAR = 0x00D2 - EM_SETMARGINS = 0x00D3 - EM_GETMARGINS = 0x00D4 - EM_SETLIMITTEXT = EM_LIMITTEXT - EM_GETLIMITTEXT = 0x00D5 - EM_POSFROMCHAR = 0x00D6 - EM_CHARFROMPOS = 0x00D7 - EM_SETIMESTATUS = 0x00D8 - EM_GETIMESTATUS = 0x00D9 - EM_SETCUEBANNER = 0x1501 - EM_GETCUEBANNER = 0x1502 -) - -const ( - CCM_FIRST = 0x2000 - CCM_LAST = CCM_FIRST + 0x200 - CCM_SETBKCOLOR = 8193 - CCM_SETCOLORSCHEME = 8194 - CCM_GETCOLORSCHEME = 8195 - CCM_GETDROPTARGET = 8196 - CCM_SETUNICODEFORMAT = 8197 - CCM_GETUNICODEFORMAT = 8198 - CCM_SETVERSION = 0x2007 - CCM_GETVERSION = 0x2008 - CCM_SETNOTIFYWINDOW = 0x2009 - CCM_SETWINDOWTHEME = 0x200b - CCM_DPISCALE = 0x200c -) - -// Common controls styles -const ( - CCS_TOP = 1 - CCS_NOMOVEY = 2 - CCS_BOTTOM = 3 - CCS_NORESIZE = 4 - CCS_NOPARENTALIGN = 8 - CCS_ADJUSTABLE = 32 - CCS_NODIVIDER = 64 - CCS_VERT = 128 - CCS_LEFT = 129 - CCS_NOMOVEX = 130 - CCS_RIGHT = 131 -) - -// ProgressBar messages -const ( - PROGRESS_CLASS = "msctls_progress32" - PBM_SETPOS = WM_USER + 2 - PBM_DELTAPOS = WM_USER + 3 - PBM_SETSTEP = WM_USER + 4 - PBM_STEPIT = WM_USER + 5 - PBM_SETRANGE32 = 1030 - PBM_GETRANGE = 1031 - PBM_GETPOS = 1032 - PBM_SETBARCOLOR = 1033 - PBM_SETBKCOLOR = CCM_SETBKCOLOR - PBS_SMOOTH = 1 - PBS_VERTICAL = 4 -) - -// Trackbar messages and constants -const ( - TBS_AUTOTICKS = 1 - TBS_VERT = 2 - TBS_HORZ = 0 - TBS_TOP = 4 - TBS_BOTTOM = 0 - TBS_LEFT = 4 - TBS_RIGHT = 0 - TBS_BOTH = 8 - TBS_NOTICKS = 16 - TBS_ENABLESELRANGE = 32 - TBS_FIXEDLENGTH = 64 - TBS_NOTHUMB = 128 - TBS_TOOLTIPS = 0x0100 -) - -const ( - TBM_GETPOS = (WM_USER) - TBM_GETRANGEMIN = (WM_USER + 1) - TBM_GETRANGEMAX = (WM_USER + 2) - TBM_GETTIC = (WM_USER + 3) - TBM_SETTIC = (WM_USER + 4) - TBM_SETPOS = (WM_USER + 5) - TBM_SETRANGE = (WM_USER + 6) - TBM_SETRANGEMIN = (WM_USER + 7) - TBM_SETRANGEMAX = (WM_USER + 8) - TBM_CLEARTICS = (WM_USER + 9) - TBM_SETSEL = (WM_USER + 10) - TBM_SETSELSTART = (WM_USER + 11) - TBM_SETSELEND = (WM_USER + 12) - TBM_GETPTICS = (WM_USER + 14) - TBM_GETTICPOS = (WM_USER + 15) - TBM_GETNUMTICS = (WM_USER + 16) - TBM_GETSELSTART = (WM_USER + 17) - TBM_GETSELEND = (WM_USER + 18) - TBM_CLEARSEL = (WM_USER + 19) - TBM_SETTICFREQ = (WM_USER + 20) - TBM_SETPAGESIZE = (WM_USER + 21) - TBM_GETPAGESIZE = (WM_USER + 22) - TBM_SETLINESIZE = (WM_USER + 23) - TBM_GETLINESIZE = (WM_USER + 24) - TBM_GETTHUMBRECT = (WM_USER + 25) - TBM_GETCHANNELRECT = (WM_USER + 26) - TBM_SETTHUMBLENGTH = (WM_USER + 27) - TBM_GETTHUMBLENGTH = (WM_USER + 28) - TBM_SETTOOLTIPS = (WM_USER + 29) - TBM_GETTOOLTIPS = (WM_USER + 30) - TBM_SETTIPSIDE = (WM_USER + 31) - TBM_SETBUDDY = (WM_USER + 32) - TBM_GETBUDDY = (WM_USER + 33) -) - -const ( - TB_LINEUP = 0 - TB_LINEDOWN = 1 - TB_PAGEUP = 2 - TB_PAGEDOWN = 3 - TB_THUMBPOSITION = 4 - TB_THUMBTRACK = 5 - TB_TOP = 6 - TB_BOTTOM = 7 - TB_ENDTRACK = 8 -) - -// GetOpenFileName and GetSaveFileName extended flags -const ( - OFN_EX_NOPLACESBAR = 0x00000001 -) - -// GetOpenFileName and GetSaveFileName flags -const ( - OFN_ALLOWMULTISELECT = 0x00000200 - OFN_CREATEPROMPT = 0x00002000 - OFN_DONTADDTORECENT = 0x02000000 - OFN_ENABLEHOOK = 0x00000020 - OFN_ENABLEINCLUDENOTIFY = 0x00400000 - OFN_ENABLESIZING = 0x00800000 - OFN_ENABLETEMPLATE = 0x00000040 - OFN_ENABLETEMPLATEHANDLE = 0x00000080 - OFN_EXPLORER = 0x00080000 - OFN_EXTENSIONDIFFERENT = 0x00000400 - OFN_FILEMUSTEXIST = 0x00001000 - OFN_FORCESHOWHIDDEN = 0x10000000 - OFN_HIDEREADONLY = 0x00000004 - OFN_LONGNAMES = 0x00200000 - OFN_NOCHANGEDIR = 0x00000008 - OFN_NODEREFERENCELINKS = 0x00100000 - OFN_NOLONGNAMES = 0x00040000 - OFN_NONETWORKBUTTON = 0x00020000 - OFN_NOREADONLYRETURN = 0x00008000 - OFN_NOTESTFILECREATE = 0x00010000 - OFN_NOVALIDATE = 0x00000100 - OFN_OVERWRITEPROMPT = 0x00000002 - OFN_PATHMUSTEXIST = 0x00000800 - OFN_READONLY = 0x00000001 - OFN_SHAREAWARE = 0x00004000 - OFN_SHOWHELP = 0x00000010 -) - -// SHBrowseForFolder flags -const ( - BIF_RETURNONLYFSDIRS = 0x00000001 - BIF_DONTGOBELOWDOMAIN = 0x00000002 - BIF_STATUSTEXT = 0x00000004 - BIF_RETURNFSANCESTORS = 0x00000008 - BIF_EDITBOX = 0x00000010 - BIF_VALIDATE = 0x00000020 - BIF_NEWDIALOGSTYLE = 0x00000040 - BIF_BROWSEINCLUDEURLS = 0x00000080 - BIF_USENEWUI = BIF_EDITBOX | BIF_NEWDIALOGSTYLE - BIF_UAHINT = 0x00000100 - BIF_NONEWFOLDERBUTTON = 0x00000200 - BIF_NOTRANSLATETARGETS = 0x00000400 - BIF_BROWSEFORCOMPUTER = 0x00001000 - BIF_BROWSEFORPRINTER = 0x00002000 - BIF_BROWSEINCLUDEFILES = 0x00004000 - BIF_SHAREABLE = 0x00008000 - BIF_BROWSEFILEJUNCTIONS = 0x00010000 -) - -// MessageBox flags -const ( - MB_OK = 0x00000000 - MB_OKCANCEL = 0x00000001 - MB_ABORTRETRYIGNORE = 0x00000002 - MB_YESNOCANCEL = 0x00000003 - MB_YESNO = 0x00000004 - MB_RETRYCANCEL = 0x00000005 - MB_CANCELTRYCONTINUE = 0x00000006 - MB_ICONHAND = 0x00000010 - MB_ICONQUESTION = 0x00000020 - MB_ICONEXCLAMATION = 0x00000030 - MB_ICONASTERISK = 0x00000040 - MB_USERICON = 0x00000080 - MB_ICONWARNING = MB_ICONEXCLAMATION - MB_ICONERROR = MB_ICONHAND - MB_ICONINFORMATION = MB_ICONASTERISK - MB_ICONSTOP = MB_ICONHAND - MB_DEFBUTTON1 = 0x00000000 - MB_DEFBUTTON2 = 0x00000100 - MB_DEFBUTTON3 = 0x00000200 - MB_DEFBUTTON4 = 0x00000300 -) - -// COM -const ( - E_INVALIDARG = 0x80070057 - E_OUTOFMEMORY = 0x8007000E - E_UNEXPECTED = 0x8000FFFF -) - -const ( - S_OK = 0 - S_FALSE = 0x0001 - RPC_E_CHANGED_MODE = 0x80010106 -) - -// GetSystemMetrics constants -const ( - SM_CXSCREEN = 0 - SM_CYSCREEN = 1 - SM_CXVSCROLL = 2 - SM_CYHSCROLL = 3 - SM_CYCAPTION = 4 - SM_CXBORDER = 5 - SM_CYBORDER = 6 - SM_CXDLGFRAME = 7 - SM_CYDLGFRAME = 8 - SM_CYVTHUMB = 9 - SM_CXHTHUMB = 10 - SM_CXICON = 11 - SM_CYICON = 12 - SM_CXCURSOR = 13 - SM_CYCURSOR = 14 - SM_CYMENU = 15 - SM_CXFULLSCREEN = 16 - SM_CYFULLSCREEN = 17 - SM_CYKANJIWINDOW = 18 - SM_MOUSEPRESENT = 19 - SM_CYVSCROLL = 20 - SM_CXHSCROLL = 21 - SM_DEBUG = 22 - SM_SWAPBUTTON = 23 - SM_RESERVED1 = 24 - SM_RESERVED2 = 25 - SM_RESERVED3 = 26 - SM_RESERVED4 = 27 - SM_CXMIN = 28 - SM_CYMIN = 29 - SM_CXSIZE = 30 - SM_CYSIZE = 31 - SM_CXFRAME = 32 - SM_CYFRAME = 33 - SM_CXMINTRACK = 34 - SM_CYMINTRACK = 35 - SM_CXDOUBLECLK = 36 - SM_CYDOUBLECLK = 37 - SM_CXICONSPACING = 38 - SM_CYICONSPACING = 39 - SM_MENUDROPALIGNMENT = 40 - SM_PENWINDOWS = 41 - SM_DBCSENABLED = 42 - SM_CMOUSEBUTTONS = 43 - SM_CXFIXEDFRAME = SM_CXDLGFRAME - SM_CYFIXEDFRAME = SM_CYDLGFRAME - SM_CXSIZEFRAME = SM_CXFRAME - SM_CYSIZEFRAME = SM_CYFRAME - SM_SECURE = 44 - SM_CXEDGE = 45 - SM_CYEDGE = 46 - SM_CXMINSPACING = 47 - SM_CYMINSPACING = 48 - SM_CXSMICON = 49 - SM_CYSMICON = 50 - SM_CYSMCAPTION = 51 - SM_CXSMSIZE = 52 - SM_CYSMSIZE = 53 - SM_CXMENUSIZE = 54 - SM_CYMENUSIZE = 55 - SM_ARRANGE = 56 - SM_CXMINIMIZED = 57 - SM_CYMINIMIZED = 58 - SM_CXMAXTRACK = 59 - SM_CYMAXTRACK = 60 - SM_CXMAXIMIZED = 61 - SM_CYMAXIMIZED = 62 - SM_NETWORK = 63 - SM_CLEANBOOT = 67 - SM_CXDRAG = 68 - SM_CYDRAG = 69 - SM_SHOWSOUNDS = 70 - SM_CXMENUCHECK = 71 - SM_CYMENUCHECK = 72 - SM_SLOWMACHINE = 73 - SM_MIDEASTENABLED = 74 - SM_MOUSEWHEELPRESENT = 75 - SM_XVIRTUALSCREEN = 76 - SM_YVIRTUALSCREEN = 77 - SM_CXVIRTUALSCREEN = 78 - SM_CYVIRTUALSCREEN = 79 - SM_CMONITORS = 80 - SM_SAMEDISPLAYFORMAT = 81 - SM_IMMENABLED = 82 - SM_CXFOCUSBORDER = 83 - SM_CYFOCUSBORDER = 84 - SM_TABLETPC = 86 - SM_MEDIACENTER = 87 - SM_STARTER = 88 - SM_SERVERR2 = 89 - SM_CMETRICS = 91 - SM_REMOTESESSION = 0x1000 - SM_SHUTTINGDOWN = 0x2000 - SM_REMOTECONTROL = 0x2001 - SM_CARETBLINKINGENABLED = 0x2002 -) - -const ( - CLSCTX_INPROC_SERVER = 1 - CLSCTX_INPROC_HANDLER = 2 - CLSCTX_LOCAL_SERVER = 4 - CLSCTX_INPROC_SERVER16 = 8 - CLSCTX_REMOTE_SERVER = 16 - CLSCTX_ALL = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER - CLSCTX_INPROC = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER - CLSCTX_SERVER = CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER -) - -const ( - COINIT_APARTMENTTHREADED = 0x2 - COINIT_MULTITHREADED = 0x0 - COINIT_DISABLE_OLE1DDE = 0x4 - COINIT_SPEED_OVER_MEMORY = 0x8 -) - -const ( - DISPATCH_METHOD = 1 - DISPATCH_PROPERTYGET = 2 - DISPATCH_PROPERTYPUT = 4 - DISPATCH_PROPERTYPUTREF = 8 -) - -const ( - CC_FASTCALL = iota - CC_CDECL - CC_MSCPASCAL - CC_PASCAL = CC_MSCPASCAL - CC_MACPASCAL - CC_STDCALL - CC_FPFASTCALL - CC_SYSCALL - CC_MPWCDECL - CC_MPWPASCAL - CC_MAX = CC_MPWPASCAL -) - -const ( - VT_EMPTY = 0x0 - VT_NULL = 0x1 - VT_I2 = 0x2 - VT_I4 = 0x3 - VT_R4 = 0x4 - VT_R8 = 0x5 - VT_CY = 0x6 - VT_DATE = 0x7 - VT_BSTR = 0x8 - VT_DISPATCH = 0x9 - VT_ERROR = 0xa - VT_BOOL = 0xb - VT_VARIANT = 0xc - VT_UNKNOWN = 0xd - VT_DECIMAL = 0xe - VT_I1 = 0x10 - VT_UI1 = 0x11 - VT_UI2 = 0x12 - VT_UI4 = 0x13 - VT_I8 = 0x14 - VT_UI8 = 0x15 - VT_INT = 0x16 - VT_UINT = 0x17 - VT_VOID = 0x18 - VT_HRESULT = 0x19 - VT_PTR = 0x1a - VT_SAFEARRAY = 0x1b - VT_CARRAY = 0x1c - VT_USERDEFINED = 0x1d - VT_LPSTR = 0x1e - VT_LPWSTR = 0x1f - VT_RECORD = 0x24 - VT_INT_PTR = 0x25 - VT_UINT_PTR = 0x26 - VT_FILETIME = 0x40 - VT_BLOB = 0x41 - VT_STREAM = 0x42 - VT_STORAGE = 0x43 - VT_STREAMED_OBJECT = 0x44 - VT_STORED_OBJECT = 0x45 - VT_BLOB_OBJECT = 0x46 - VT_CF = 0x47 - VT_CLSID = 0x48 - VT_BSTR_BLOB = 0xfff - VT_VECTOR = 0x1000 - VT_ARRAY = 0x2000 - VT_BYREF = 0x4000 - VT_RESERVED = 0x8000 - VT_ILLEGAL = 0xffff - VT_ILLEGALMASKED = 0xfff - VT_TYPEMASK = 0xfff -) - -const ( - DISPID_UNKNOWN = -1 - DISPID_VALUE = 0 - DISPID_PROPERTYPUT = -3 - DISPID_NEWENUM = -4 - DISPID_EVALUATE = -5 - DISPID_CONSTRUCTOR = -6 - DISPID_DESTRUCTOR = -7 - DISPID_COLLECT = -8 -) - -const ( - MONITOR_DEFAULTTONULL = 0x00000000 - MONITOR_DEFAULTTOPRIMARY = 0x00000001 - MONITOR_DEFAULTTONEAREST = 0x00000002 - - MONITORINFOF_PRIMARY = 0x00000001 -) - -const ( - CCHDEVICENAME = 32 - CCHFORMNAME = 32 -) - -const ( - IDOK = 1 - IDCANCEL = 2 - IDABORT = 3 - IDRETRY = 4 - IDIGNORE = 5 - IDYES = 6 - IDNO = 7 - IDCLOSE = 8 - IDHELP = 9 - IDTRYAGAIN = 10 - IDCONTINUE = 11 - IDTIMEOUT = 32000 -) - -// Generic WM_NOTIFY notification codes -const ( - NM_FIRST = 0 - NM_OUTOFMEMORY = NM_FIRST - 1 - NM_CLICK = NM_FIRST - 2 - NM_DBLCLK = NM_FIRST - 3 - NM_RETURN = NM_FIRST - 4 - NM_RCLICK = NM_FIRST - 5 - NM_RDBLCLK = NM_FIRST - 6 - NM_SETFOCUS = NM_FIRST - 7 - NM_KILLFOCUS = NM_FIRST - 8 - NM_CUSTOMDRAW = NM_FIRST - 12 - NM_HOVER = NM_FIRST - 13 - NM_NCHITTEST = NM_FIRST - 14 - NM_KEYDOWN = NM_FIRST - 15 - NM_RELEASEDCAPTURE = NM_FIRST - 16 - NM_SETCURSOR = NM_FIRST - 17 - NM_CHAR = NM_FIRST - 18 - NM_TOOLTIPSCREATED = NM_FIRST - 19 - NM_LAST = NM_FIRST - 99 -) - -// ListView messages -const ( - LVM_FIRST = 0x1000 - LVM_GETITEMCOUNT = LVM_FIRST + 4 - LVM_SETIMAGELIST = LVM_FIRST + 3 - LVM_GETIMAGELIST = LVM_FIRST + 2 - LVM_GETITEM = LVM_FIRST + 75 - LVM_SETITEM = LVM_FIRST + 76 - LVM_INSERTITEM = LVM_FIRST + 77 - LVM_DELETEITEM = LVM_FIRST + 8 - LVM_DELETEALLITEMS = LVM_FIRST + 9 - LVM_GETCALLBACKMASK = LVM_FIRST + 10 - LVM_SETCALLBACKMASK = LVM_FIRST + 11 - LVM_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT - LVM_GETNEXTITEM = LVM_FIRST + 12 - LVM_FINDITEM = LVM_FIRST + 83 - LVM_GETITEMRECT = LVM_FIRST + 14 - LVM_GETSTRINGWIDTH = LVM_FIRST + 87 - LVM_HITTEST = LVM_FIRST + 18 - LVM_ENSUREVISIBLE = LVM_FIRST + 19 - LVM_SCROLL = LVM_FIRST + 20 - LVM_REDRAWITEMS = LVM_FIRST + 21 - LVM_ARRANGE = LVM_FIRST + 22 - LVM_EDITLABEL = LVM_FIRST + 118 - LVM_GETEDITCONTROL = LVM_FIRST + 24 - LVM_GETCOLUMN = LVM_FIRST + 95 - LVM_SETCOLUMN = LVM_FIRST + 96 - LVM_INSERTCOLUMN = LVM_FIRST + 97 - LVM_DELETECOLUMN = LVM_FIRST + 28 - LVM_GETCOLUMNWIDTH = LVM_FIRST + 29 - LVM_SETCOLUMNWIDTH = LVM_FIRST + 30 - LVM_GETHEADER = LVM_FIRST + 31 - LVM_CREATEDRAGIMAGE = LVM_FIRST + 33 - LVM_GETVIEWRECT = LVM_FIRST + 34 - LVM_GETTEXTCOLOR = LVM_FIRST + 35 - LVM_SETTEXTCOLOR = LVM_FIRST + 36 - LVM_GETTEXTBKCOLOR = LVM_FIRST + 37 - LVM_SETTEXTBKCOLOR = LVM_FIRST + 38 - LVM_GETTOPINDEX = LVM_FIRST + 39 - LVM_GETCOUNTPERPAGE = LVM_FIRST + 40 - LVM_GETORIGIN = LVM_FIRST + 41 - LVM_UPDATE = LVM_FIRST + 42 - LVM_SETITEMSTATE = LVM_FIRST + 43 - LVM_GETITEMSTATE = LVM_FIRST + 44 - LVM_GETITEMTEXT = LVM_FIRST + 115 - LVM_SETITEMTEXT = LVM_FIRST + 116 - LVM_SETITEMCOUNT = LVM_FIRST + 47 - LVM_SORTITEMS = LVM_FIRST + 48 - LVM_SETITEMPOSITION32 = LVM_FIRST + 49 - LVM_GETSELECTEDCOUNT = LVM_FIRST + 50 - LVM_GETITEMSPACING = LVM_FIRST + 51 - LVM_GETISEARCHSTRING = LVM_FIRST + 117 - LVM_SETICONSPACING = LVM_FIRST + 53 - LVM_SETEXTENDEDLISTVIEWSTYLE = LVM_FIRST + 54 - LVM_GETEXTENDEDLISTVIEWSTYLE = LVM_FIRST + 55 - LVM_GETSUBITEMRECT = LVM_FIRST + 56 - LVM_SUBITEMHITTEST = LVM_FIRST + 57 - LVM_SETCOLUMNORDERARRAY = LVM_FIRST + 58 - LVM_GETCOLUMNORDERARRAY = LVM_FIRST + 59 - LVM_SETHOTITEM = LVM_FIRST + 60 - LVM_GETHOTITEM = LVM_FIRST + 61 - LVM_SETHOTCURSOR = LVM_FIRST + 62 - LVM_GETHOTCURSOR = LVM_FIRST + 63 - LVM_APPROXIMATEVIEWRECT = LVM_FIRST + 64 - LVM_SETWORKAREAS = LVM_FIRST + 65 - LVM_GETWORKAREAS = LVM_FIRST + 70 - LVM_GETNUMBEROFWORKAREAS = LVM_FIRST + 73 - LVM_GETSELECTIONMARK = LVM_FIRST + 66 - LVM_SETSELECTIONMARK = LVM_FIRST + 67 - LVM_SETHOVERTIME = LVM_FIRST + 71 - LVM_GETHOVERTIME = LVM_FIRST + 72 - LVM_SETTOOLTIPS = LVM_FIRST + 74 - LVM_GETTOOLTIPS = LVM_FIRST + 78 - LVM_SORTITEMSEX = LVM_FIRST + 81 - LVM_SETBKIMAGE = LVM_FIRST + 138 - LVM_GETBKIMAGE = LVM_FIRST + 139 - LVM_SETSELECTEDCOLUMN = LVM_FIRST + 140 - LVM_SETVIEW = LVM_FIRST + 142 - LVM_GETVIEW = LVM_FIRST + 143 - LVM_INSERTGROUP = LVM_FIRST + 145 - LVM_SETGROUPINFO = LVM_FIRST + 147 - LVM_GETGROUPINFO = LVM_FIRST + 149 - LVM_REMOVEGROUP = LVM_FIRST + 150 - LVM_MOVEGROUP = LVM_FIRST + 151 - LVM_GETGROUPCOUNT = LVM_FIRST + 152 - LVM_GETGROUPINFOBYINDEX = LVM_FIRST + 153 - LVM_MOVEITEMTOGROUP = LVM_FIRST + 154 - LVM_GETGROUPRECT = LVM_FIRST + 98 - LVM_SETGROUPMETRICS = LVM_FIRST + 155 - LVM_GETGROUPMETRICS = LVM_FIRST + 156 - LVM_ENABLEGROUPVIEW = LVM_FIRST + 157 - LVM_SORTGROUPS = LVM_FIRST + 158 - LVM_INSERTGROUPSORTED = LVM_FIRST + 159 - LVM_REMOVEALLGROUPS = LVM_FIRST + 160 - LVM_HASGROUP = LVM_FIRST + 161 - LVM_GETGROUPSTATE = LVM_FIRST + 92 - LVM_GETFOCUSEDGROUP = LVM_FIRST + 93 - LVM_SETTILEVIEWINFO = LVM_FIRST + 162 - LVM_GETTILEVIEWINFO = LVM_FIRST + 163 - LVM_SETTILEINFO = LVM_FIRST + 164 - LVM_GETTILEINFO = LVM_FIRST + 165 - LVM_SETINSERTMARK = LVM_FIRST + 166 - LVM_GETINSERTMARK = LVM_FIRST + 167 - LVM_INSERTMARKHITTEST = LVM_FIRST + 168 - LVM_GETINSERTMARKRECT = LVM_FIRST + 169 - LVM_SETINSERTMARKCOLOR = LVM_FIRST + 170 - LVM_GETINSERTMARKCOLOR = LVM_FIRST + 171 - LVM_SETINFOTIP = LVM_FIRST + 173 - LVM_GETSELECTEDCOLUMN = LVM_FIRST + 174 - LVM_ISGROUPVIEWENABLED = LVM_FIRST + 175 - LVM_GETOUTLINECOLOR = LVM_FIRST + 176 - LVM_SETOUTLINECOLOR = LVM_FIRST + 177 - LVM_CANCELEDITLABEL = LVM_FIRST + 179 - LVM_MAPINDEXTOID = LVM_FIRST + 180 - LVM_MAPIDTOINDEX = LVM_FIRST + 181 - LVM_ISITEMVISIBLE = LVM_FIRST + 182 - LVM_GETNEXTITEMINDEX = LVM_FIRST + 211 -) - -// ListView notifications -const ( - LVN_FIRST = -100 - - LVN_ITEMCHANGING = LVN_FIRST - 0 - LVN_ITEMCHANGED = LVN_FIRST - 1 - LVN_INSERTITEM = LVN_FIRST - 2 - LVN_DELETEITEM = LVN_FIRST - 3 - LVN_DELETEALLITEMS = LVN_FIRST - 4 - LVN_BEGINLABELEDITA = LVN_FIRST - 5 - LVN_BEGINLABELEDITW = LVN_FIRST - 75 - LVN_ENDLABELEDITA = LVN_FIRST - 6 - LVN_ENDLABELEDITW = LVN_FIRST - 76 - LVN_COLUMNCLICK = LVN_FIRST - 8 - LVN_BEGINDRAG = LVN_FIRST - 9 - LVN_BEGINRDRAG = LVN_FIRST - 11 - LVN_ODCACHEHINT = LVN_FIRST - 13 - LVN_ODFINDITEMA = LVN_FIRST - 52 - LVN_ODFINDITEMW = LVN_FIRST - 79 - LVN_ITEMACTIVATE = LVN_FIRST - 14 - LVN_ODSTATECHANGED = LVN_FIRST - 15 - LVN_HOTTRACK = LVN_FIRST - 21 - LVN_GETDISPINFO = LVN_FIRST - 77 - LVN_SETDISPINFO = LVN_FIRST - 78 - LVN_KEYDOWN = LVN_FIRST - 55 - LVN_MARQUEEBEGIN = LVN_FIRST - 56 - LVN_GETINFOTIP = LVN_FIRST - 58 - LVN_INCREMENTALSEARCH = LVN_FIRST - 63 - LVN_BEGINSCROLL = LVN_FIRST - 80 - LVN_ENDSCROLL = LVN_FIRST - 81 -) - -const ( - LVSCW_AUTOSIZE = ^uintptr(0) - LVSCW_AUTOSIZE_USEHEADER = ^uintptr(1) -) - -// ListView LVNI constants -const ( - LVNI_ALL = 0 - LVNI_FOCUSED = 1 - LVNI_SELECTED = 2 - LVNI_CUT = 4 - LVNI_DROPHILITED = 8 - LVNI_ABOVE = 256 - LVNI_BELOW = 512 - LVNI_TOLEFT = 1024 - LVNI_TORIGHT = 2048 -) - -// ListView styles -const ( - LVS_ICON = 0x0000 - LVS_REPORT = 0x0001 - LVS_SMALLICON = 0x0002 - LVS_LIST = 0x0003 - LVS_TYPEMASK = 0x0003 - LVS_SINGLESEL = 0x0004 - LVS_SHOWSELALWAYS = 0x0008 - LVS_SORTASCENDING = 0x0010 - LVS_SORTDESCENDING = 0x0020 - LVS_SHAREIMAGELISTS = 0x0040 - LVS_NOLABELWRAP = 0x0080 - LVS_AUTOARRANGE = 0x0100 - LVS_EDITLABELS = 0x0200 - LVS_OWNERDATA = 0x1000 - LVS_NOSCROLL = 0x2000 - LVS_TYPESTYLEMASK = 0xfc00 - LVS_ALIGNTOP = 0x0000 - LVS_ALIGNLEFT = 0x0800 - LVS_ALIGNMASK = 0x0c00 - LVS_OWNERDRAWFIXED = 0x0400 - LVS_NOCOLUMNHEADER = 0x4000 - LVS_NOSORTHEADER = 0x8000 -) - -// ListView extended styles -const ( - LVS_EX_GRIDLINES = 0x00000001 - LVS_EX_SUBITEMIMAGES = 0x00000002 - LVS_EX_CHECKBOXES = 0x00000004 - LVS_EX_TRACKSELECT = 0x00000008 - LVS_EX_HEADERDRAGDROP = 0x00000010 - LVS_EX_FULLROWSELECT = 0x00000020 - LVS_EX_ONECLICKACTIVATE = 0x00000040 - LVS_EX_TWOCLICKACTIVATE = 0x00000080 - LVS_EX_FLATSB = 0x00000100 - LVS_EX_REGIONAL = 0x00000200 - LVS_EX_INFOTIP = 0x00000400 - LVS_EX_UNDERLINEHOT = 0x00000800 - LVS_EX_UNDERLINECOLD = 0x00001000 - LVS_EX_MULTIWORKAREAS = 0x00002000 - LVS_EX_LABELTIP = 0x00004000 - LVS_EX_BORDERSELECT = 0x00008000 - LVS_EX_DOUBLEBUFFER = 0x00010000 - LVS_EX_HIDELABELS = 0x00020000 - LVS_EX_SINGLEROW = 0x00040000 - LVS_EX_SNAPTOGRID = 0x00080000 - LVS_EX_SIMPLESELECT = 0x00100000 -) - -// ListView column flags -const ( - LVCF_FMT = 0x0001 - LVCF_WIDTH = 0x0002 - LVCF_TEXT = 0x0004 - LVCF_SUBITEM = 0x0008 - LVCF_IMAGE = 0x0010 - LVCF_ORDER = 0x0020 -) - -// ListView column format constants -const ( - LVCFMT_LEFT = 0x0000 - LVCFMT_RIGHT = 0x0001 - LVCFMT_CENTER = 0x0002 - LVCFMT_JUSTIFYMASK = 0x0003 - LVCFMT_IMAGE = 0x0800 - LVCFMT_BITMAP_ON_RIGHT = 0x1000 - LVCFMT_COL_HAS_IMAGES = 0x8000 -) - -// ListView item flags -const ( - LVIF_TEXT = 0x00000001 - LVIF_IMAGE = 0x00000002 - LVIF_PARAM = 0x00000004 - LVIF_STATE = 0x00000008 - LVIF_INDENT = 0x00000010 - LVIF_NORECOMPUTE = 0x00000800 - LVIF_GROUPID = 0x00000100 - LVIF_COLUMNS = 0x00000200 -) - -const LVFI_PARAM = 0x0001 - -// ListView item states -const ( - LVIS_FOCUSED = 1 - LVIS_SELECTED = 2 - LVIS_CUT = 4 - LVIS_DROPHILITED = 8 - LVIS_OVERLAYMASK = 0xF00 - LVIS_STATEIMAGEMASK = 0xF000 -) - -// ListView hit test constants -const ( - LVHT_NOWHERE = 0x00000001 - LVHT_ONITEMICON = 0x00000002 - LVHT_ONITEMLABEL = 0x00000004 - LVHT_ONITEMSTATEICON = 0x00000008 - LVHT_ONITEM = LVHT_ONITEMICON | LVHT_ONITEMLABEL | LVHT_ONITEMSTATEICON - - LVHT_ABOVE = 0x00000008 - LVHT_BELOW = 0x00000010 - LVHT_TORIGHT = 0x00000020 - LVHT_TOLEFT = 0x00000040 -) - -// ListView image list types -const ( - LVSIL_NORMAL = 0 - LVSIL_SMALL = 1 - LVSIL_STATE = 2 - LVSIL_GROUPHEADER = 3 -) - -// InitCommonControlsEx flags -const ( - ICC_LISTVIEW_CLASSES = 1 - ICC_TREEVIEW_CLASSES = 2 - ICC_BAR_CLASSES = 4 - ICC_TAB_CLASSES = 8 - ICC_UPDOWN_CLASS = 16 - ICC_PROGRESS_CLASS = 32 - ICC_HOTKEY_CLASS = 64 - ICC_ANIMATE_CLASS = 128 - ICC_WIN95_CLASSES = 255 - ICC_DATE_CLASSES = 256 - ICC_USEREX_CLASSES = 512 - ICC_COOL_CLASSES = 1024 - ICC_INTERNET_CLASSES = 2048 - ICC_PAGESCROLLER_CLASS = 4096 - ICC_NATIVEFNTCTL_CLASS = 8192 - INFOTIPSIZE = 1024 - ICC_STANDARD_CLASSES = 0x00004000 - ICC_LINK_CLASS = 0x00008000 -) - -// Dialog Codes -const ( - DLGC_WANTARROWS = 0x0001 - DLGC_WANTTAB = 0x0002 - DLGC_WANTALLKEYS = 0x0004 - DLGC_WANTMESSAGE = 0x0004 - DLGC_HASSETSEL = 0x0008 - DLGC_DEFPUSHBUTTON = 0x0010 - DLGC_UNDEFPUSHBUTTON = 0x0020 - DLGC_RADIOBUTTON = 0x0040 - DLGC_WANTCHARS = 0x0080 - DLGC_STATIC = 0x0100 - DLGC_BUTTON = 0x2000 -) - -// Get/SetWindowWord/Long offsets for use with WC_DIALOG windows -const ( - DWL_MSGRESULT = 0 - DWL_DLGPROC = 4 - DWL_USER = 8 -) - -// Registry predefined keys -const ( - HKEY_CLASSES_ROOT HKEY = 0x80000000 - HKEY_CURRENT_USER HKEY = 0x80000001 - HKEY_LOCAL_MACHINE HKEY = 0x80000002 - HKEY_USERS HKEY = 0x80000003 - HKEY_PERFORMANCE_DATA HKEY = 0x80000004 - HKEY_CURRENT_CONFIG HKEY = 0x80000005 - HKEY_DYN_DATA HKEY = 0x80000006 -) - -// Registry Key Security and Access Rights -const ( - KEY_ALL_ACCESS = 0xF003F - KEY_CREATE_SUB_KEY = 0x0004 - KEY_ENUMERATE_SUB_KEYS = 0x0008 - KEY_NOTIFY = 0x0010 - KEY_QUERY_VALUE = 0x0001 - KEY_SET_VALUE = 0x0002 - KEY_READ = 0x20019 - KEY_WRITE = 0x20006 -) - -const ( - NFR_ANSI = 1 - NFR_UNICODE = 2 - NF_QUERY = 3 - NF_REQUERY = 4 -) - -// Registry value types -const ( - RRF_RT_REG_NONE = 0x00000001 - RRF_RT_REG_SZ = 0x00000002 - RRF_RT_REG_EXPAND_SZ = 0x00000004 - RRF_RT_REG_BINARY = 0x00000008 - RRF_RT_REG_DWORD = 0x00000010 - RRF_RT_REG_MULTI_SZ = 0x00000020 - RRF_RT_REG_QWORD = 0x00000040 - RRF_RT_DWORD = (RRF_RT_REG_BINARY | RRF_RT_REG_DWORD) - RRF_RT_QWORD = (RRF_RT_REG_BINARY | RRF_RT_REG_QWORD) - RRF_RT_ANY = 0x0000ffff - RRF_NOEXPAND = 0x10000000 - RRF_ZEROONFAILURE = 0x20000000 - REG_PROCESS_APPKEY = 0x00000001 - REG_MUI_STRING_TRUNCATE = 0x00000001 -) - -// PeekMessage wRemoveMsg value -const ( - PM_NOREMOVE = 0x000 - PM_REMOVE = 0x001 - PM_NOYIELD = 0x002 -) - -// ImageList flags -const ( - ILC_MASK = 0x00000001 - ILC_COLOR = 0x00000000 - ILC_COLORDDB = 0x000000FE - ILC_COLOR4 = 0x00000004 - ILC_COLOR8 = 0x00000008 - ILC_COLOR16 = 0x00000010 - ILC_COLOR24 = 0x00000018 - ILC_COLOR32 = 0x00000020 - ILC_PALETTE = 0x00000800 - ILC_MIRROR = 0x00002000 - ILC_PERITEMMIRROR = 0x00008000 - ILC_ORIGINALSIZE = 0x00010000 - ILC_HIGHQUALITYSCALE = 0x00020000 -) - -// Keystroke Message Flags -const ( - KF_EXTENDED = 0x0100 - KF_DLGMODE = 0x0800 - KF_MENUMODE = 0x1000 - KF_ALTDOWN = 0x2000 - KF_REPEAT = 0x4000 - KF_UP = 0x8000 -) - -// Virtual-Key Codes -/* -const ( - VK_LBUTTON = 0x01 - VK_RBUTTON = 0x02 - VK_CANCEL = 0x03 - VK_MBUTTON = 0x04 - VK_XBUTTON1 = 0x05 - VK_XBUTTON2 = 0x06 - VK_BACK = 0x08 - VK_TAB = 0x09 - VK_CLEAR = 0x0C - VK_RETURN = 0x0D - VK_SHIFT = 0x10 - VK_CONTROL = 0x11 - VK_MENU = 0x12 - VK_PAUSE = 0x13 - VK_CAPITAL = 0x14 - VK_KANA = 0x15 - VK_HANGEUL = 0x15 - VK_HANGUL = 0x15 - VK_JUNJA = 0x17 - VK_FINAL = 0x18 - VK_HANJA = 0x19 - VK_KANJI = 0x19 - VK_ESCAPE = 0x1B - VK_CONVERT = 0x1C - VK_NONCONVERT = 0x1D - VK_ACCEPT = 0x1E - VK_MODECHANGE = 0x1F - VK_SPACE = 0x20 - VK_PRIOR = 0x21 - VK_NEXT = 0x22 - VK_END = 0x23 - VK_HOME = 0x24 - VK_LEFT = 0x25 - VK_UP = 0x26 - VK_RIGHT = 0x27 - VK_DOWN = 0x28 - VK_SELECT = 0x29 - VK_PRINT = 0x2A - VK_EXECUTE = 0x2B - VK_SNAPSHOT = 0x2C - VK_INSERT = 0x2D - VK_DELETE = 0x2E - VK_HELP = 0x2F - VK_LWIN = 0x5B - VK_RWIN = 0x5C - VK_APPS = 0x5D - VK_SLEEP = 0x5F - VK_NUMPAD0 = 0x60 - VK_NUMPAD1 = 0x61 - VK_NUMPAD2 = 0x62 - VK_NUMPAD3 = 0x63 - VK_NUMPAD4 = 0x64 - VK_NUMPAD5 = 0x65 - VK_NUMPAD6 = 0x66 - VK_NUMPAD7 = 0x67 - VK_NUMPAD8 = 0x68 - VK_NUMPAD9 = 0x69 - VK_MULTIPLY = 0x6A - VK_ADD = 0x6B - VK_SEPARATOR = 0x6C - VK_SUBTRACT = 0x6D - VK_DECIMAL = 0x6E - VK_DIVIDE = 0x6F - VK_F1 = 0x70 - VK_F2 = 0x71 - VK_F3 = 0x72 - VK_F4 = 0x73 - VK_F5 = 0x74 - VK_F6 = 0x75 - VK_F7 = 0x76 - VK_F8 = 0x77 - VK_F9 = 0x78 - VK_F10 = 0x79 - VK_F11 = 0x7A - VK_F12 = 0x7B - VK_F13 = 0x7C - VK_F14 = 0x7D - VK_F15 = 0x7E - VK_F16 = 0x7F - VK_F17 = 0x80 - VK_F18 = 0x81 - VK_F19 = 0x82 - VK_F20 = 0x83 - VK_F21 = 0x84 - VK_F22 = 0x85 - VK_F23 = 0x86 - VK_F24 = 0x87 - VK_NUMLOCK = 0x90 - VK_SCROLL = 0x91 - VK_OEM_NEC_EQUAL = 0x92 - VK_OEM_FJ_JISHO = 0x92 - VK_OEM_FJ_MASSHOU = 0x93 - VK_OEM_FJ_TOUROKU = 0x94 - VK_OEM_FJ_LOYA = 0x95 - VK_OEM_FJ_ROYA = 0x96 - VK_LSHIFT = 0xA0 - VK_RSHIFT = 0xA1 - VK_LCONTROL = 0xA2 - VK_RCONTROL = 0xA3 - VK_LMENU = 0xA4 - VK_RMENU = 0xA5 - VK_BROWSER_BACK = 0xA6 - VK_BROWSER_FORWARD = 0xA7 - VK_BROWSER_REFRESH = 0xA8 - VK_BROWSER_STOP = 0xA9 - VK_BROWSER_SEARCH = 0xAA - VK_BROWSER_FAVORITES = 0xAB - VK_BROWSER_HOME = 0xAC - VK_VOLUME_MUTE = 0xAD - VK_VOLUME_DOWN = 0xAE - VK_VOLUME_UP = 0xAF - VK_MEDIA_NEXT_TRACK = 0xB0 - VK_MEDIA_PREV_TRACK = 0xB1 - VK_MEDIA_STOP = 0xB2 - VK_MEDIA_PLAY_PAUSE = 0xB3 - VK_LAUNCH_MAIL = 0xB4 - VK_LAUNCH_MEDIA_SELECT = 0xB5 - VK_LAUNCH_APP1 = 0xB6 - VK_LAUNCH_APP2 = 0xB7 - VK_OEM_1 = 0xBA - VK_OEM_PLUS = 0xBB - VK_OEM_COMMA = 0xBC - VK_OEM_MINUS = 0xBD - VK_OEM_PERIOD = 0xBE - VK_OEM_2 = 0xBF - VK_OEM_3 = 0xC0 - VK_OEM_4 = 0xDB - VK_OEM_5 = 0xDC - VK_OEM_6 = 0xDD - VK_OEM_7 = 0xDE - VK_OEM_8 = 0xDF - VK_OEM_AX = 0xE1 - VK_OEM_102 = 0xE2 - VK_ICO_HELP = 0xE3 - VK_ICO_00 = 0xE4 - VK_PROCESSKEY = 0xE5 - VK_ICO_CLEAR = 0xE6 - VK_OEM_RESET = 0xE9 - VK_OEM_JUMP = 0xEA - VK_OEM_PA1 = 0xEB - VK_OEM_PA2 = 0xEC - VK_OEM_PA3 = 0xED - VK_OEM_WSCTRL = 0xEE - VK_OEM_CUSEL = 0xEF - VK_OEM_ATTN = 0xF0 - VK_OEM_FINISH = 0xF1 - VK_OEM_COPY = 0xF2 - VK_OEM_AUTO = 0xF3 - VK_OEM_ENLW = 0xF4 - VK_OEM_BACKTAB = 0xF5 - VK_ATTN = 0xF6 - VK_CRSEL = 0xF7 - VK_EXSEL = 0xF8 - VK_EREOF = 0xF9 - VK_PLAY = 0xFA - VK_ZOOM = 0xFB - VK_NONAME = 0xFC - VK_PA1 = 0xFD - VK_OEM_CLEAR = 0xFE -)*/ - -// Registry Value Types -const ( - REG_NONE = 0 - REG_SZ = 1 - REG_EXPAND_SZ = 2 - REG_BINARY = 3 - REG_DWORD = 4 - REG_DWORD_LITTLE_ENDIAN = 4 - REG_DWORD_BIG_ENDIAN = 5 - REG_LINK = 6 - REG_MULTI_SZ = 7 - REG_RESOURCE_LIST = 8 - REG_FULL_RESOURCE_DESCRIPTOR = 9 - REG_RESOURCE_REQUIREMENTS_LIST = 10 - REG_QWORD = 11 - REG_QWORD_LITTLE_ENDIAN = 11 -) - -// Tooltip styles -const ( - TTS_ALWAYSTIP = 0x01 - TTS_NOPREFIX = 0x02 - TTS_NOANIMATE = 0x10 - TTS_NOFADE = 0x20 - TTS_BALLOON = 0x40 - TTS_CLOSE = 0x80 - TTS_USEVISUALSTYLE = 0x100 -) - -// Tooltip messages -const ( - TTM_ACTIVATE = (WM_USER + 1) - TTM_SETDELAYTIME = (WM_USER + 3) - TTM_ADDTOOL = (WM_USER + 50) - TTM_DELTOOL = (WM_USER + 51) - TTM_NEWTOOLRECT = (WM_USER + 52) - TTM_RELAYEVENT = (WM_USER + 7) - TTM_GETTOOLINFO = (WM_USER + 53) - TTM_SETTOOLINFO = (WM_USER + 54) - TTM_HITTEST = (WM_USER + 55) - TTM_GETTEXT = (WM_USER + 56) - TTM_UPDATETIPTEXT = (WM_USER + 57) - TTM_GETTOOLCOUNT = (WM_USER + 13) - TTM_ENUMTOOLS = (WM_USER + 58) - TTM_GETCURRENTTOOL = (WM_USER + 59) - TTM_WINDOWFROMPOINT = (WM_USER + 16) - TTM_TRACKACTIVATE = (WM_USER + 17) - TTM_TRACKPOSITION = (WM_USER + 18) - TTM_SETTIPBKCOLOR = (WM_USER + 19) - TTM_SETTIPTEXTCOLOR = (WM_USER + 20) - TTM_GETDELAYTIME = (WM_USER + 21) - TTM_GETTIPBKCOLOR = (WM_USER + 22) - TTM_GETTIPTEXTCOLOR = (WM_USER + 23) - TTM_SETMAXTIPWIDTH = (WM_USER + 24) - TTM_GETMAXTIPWIDTH = (WM_USER + 25) - TTM_SETMARGIN = (WM_USER + 26) - TTM_GETMARGIN = (WM_USER + 27) - TTM_POP = (WM_USER + 28) - TTM_UPDATE = (WM_USER + 29) - TTM_GETBUBBLESIZE = (WM_USER + 30) - TTM_ADJUSTRECT = (WM_USER + 31) - TTM_SETTITLE = (WM_USER + 33) - TTM_POPUP = (WM_USER + 34) - TTM_GETTITLE = (WM_USER + 35) -) - -// Tooltip icons -const ( - TTI_NONE = 0 - TTI_INFO = 1 - TTI_WARNING = 2 - TTI_ERROR = 3 - TTI_INFO_LARGE = 4 - TTI_WARNING_LARGE = 5 - TTI_ERROR_LARGE = 6 -) - -// Tooltip notifications -const ( - TTN_FIRST = -520 - TTN_LAST = -549 - TTN_GETDISPINFO = (TTN_FIRST - 10) - TTN_SHOW = (TTN_FIRST - 1) - TTN_POP = (TTN_FIRST - 2) - TTN_LINKCLICK = (TTN_FIRST - 3) - TTN_NEEDTEXT = TTN_GETDISPINFO -) - -const ( - TTF_IDISHWND = 0x0001 - TTF_CENTERTIP = 0x0002 - TTF_RTLREADING = 0x0004 - TTF_SUBCLASS = 0x0010 - TTF_TRACK = 0x0020 - TTF_ABSOLUTE = 0x0080 - TTF_TRANSPARENT = 0x0100 - TTF_PARSELINKS = 0x1000 - TTF_DI_SETITEM = 0x8000 -) - -const ( - SWP_NOSIZE = 0x0001 - SWP_NOMOVE = 0x0002 - SWP_NOZORDER = 0x0004 - SWP_NOREDRAW = 0x0008 - SWP_NOACTIVATE = 0x0010 - SWP_FRAMECHANGED = 0x0020 - SWP_SHOWWINDOW = 0x0040 - SWP_HIDEWINDOW = 0x0080 - SWP_NOCOPYBITS = 0x0100 - SWP_NOOWNERZORDER = 0x0200 - SWP_NOSENDCHANGING = 0x0400 - SWP_DRAWFRAME = SWP_FRAMECHANGED - SWP_NOREPOSITION = SWP_NOOWNERZORDER - SWP_DEFERERASE = 0x2000 - SWP_ASYNCWINDOWPOS = 0x4000 -) - -// Predefined window handles -const ( - HWND_BROADCAST = HWND(0xFFFF) - HWND_BOTTOM = HWND(1) - HWND_NOTOPMOST = ^HWND(1) // -2 - HWND_TOP = HWND(0) - HWND_TOPMOST = ^HWND(0) // -1 - HWND_DESKTOP = HWND(0) - HWND_MESSAGE = ^HWND(2) // -3 -) - -// Pen types -const ( - PS_COSMETIC = 0x00000000 - PS_GEOMETRIC = 0x00010000 - PS_TYPE_MASK = 0x000F0000 -) - -// Pen styles -const ( - PS_SOLID = 0 - PS_DASH = 1 - PS_DOT = 2 - PS_DASHDOT = 3 - PS_DASHDOTDOT = 4 - PS_NULL = 5 - PS_INSIDEFRAME = 6 - PS_USERSTYLE = 7 - PS_ALTERNATE = 8 - PS_STYLE_MASK = 0x0000000F -) - -// Pen cap types -const ( - PS_ENDCAP_ROUND = 0x00000000 - PS_ENDCAP_SQUARE = 0x00000100 - PS_ENDCAP_FLAT = 0x00000200 - PS_ENDCAP_MASK = 0x00000F00 -) - -// Pen join types -const ( - PS_JOIN_ROUND = 0x00000000 - PS_JOIN_BEVEL = 0x00001000 - PS_JOIN_MITER = 0x00002000 - PS_JOIN_MASK = 0x0000F000 -) - -// Hatch styles -const ( - HS_HORIZONTAL = 0 - HS_VERTICAL = 1 - HS_FDIAGONAL = 2 - HS_BDIAGONAL = 3 - HS_CROSS = 4 - HS_DIAGCROSS = 5 -) - -// Stock Logical Objects -const ( - WHITE_BRUSH = 0 - LTGRAY_BRUSH = 1 - GRAY_BRUSH = 2 - DKGRAY_BRUSH = 3 - BLACK_BRUSH = 4 - NULL_BRUSH = 5 - HOLLOW_BRUSH = NULL_BRUSH - WHITE_PEN = 6 - BLACK_PEN = 7 - NULL_PEN = 8 - OEM_FIXED_FONT = 10 - ANSI_FIXED_FONT = 11 - ANSI_VAR_FONT = 12 - SYSTEM_FONT = 13 - DEVICE_DEFAULT_FONT = 14 - DEFAULT_PALETTE = 15 - SYSTEM_FIXED_FONT = 16 - DEFAULT_GUI_FONT = 17 - DC_BRUSH = 18 - DC_PEN = 19 -) - -// Brush styles -const ( - BS_SOLID = 0 - BS_NULL = 1 - BS_HOLLOW = BS_NULL - BS_HATCHED = 2 - BS_PATTERN = 3 - BS_INDEXED = 4 - BS_DIBPATTERN = 5 - BS_DIBPATTERNPT = 6 - BS_PATTERN8X8 = 7 - BS_DIBPATTERN8X8 = 8 - BS_MONOPATTERN = 9 -) - -// TRACKMOUSEEVENT flags -const ( - TME_HOVER = 0x00000001 - TME_LEAVE = 0x00000002 - TME_NONCLIENT = 0x00000010 - TME_QUERY = 0x40000000 - TME_CANCEL = 0x80000000 - - HOVER_DEFAULT = 0xFFFFFFFF -) - -// WM_NCHITTEST and MOUSEHOOKSTRUCT Mouse Position Codes -const ( - HTERROR = (-2) - HTTRANSPARENT = (-1) - HTNOWHERE = 0 - HTCLIENT = 1 - HTCAPTION = 2 - HTSYSMENU = 3 - HTGROWBOX = 4 - HTSIZE = HTGROWBOX - HTMENU = 5 - HTHSCROLL = 6 - HTVSCROLL = 7 - HTMINBUTTON = 8 - HTMAXBUTTON = 9 - HTLEFT = 10 - HTRIGHT = 11 - HTTOP = 12 - HTTOPLEFT = 13 - HTTOPRIGHT = 14 - HTBOTTOM = 15 - HTBOTTOMLEFT = 16 - HTBOTTOMRIGHT = 17 - HTBORDER = 18 - HTREDUCE = HTMINBUTTON - HTZOOM = HTMAXBUTTON - HTSIZEFIRST = HTLEFT - HTSIZELAST = HTBOTTOMRIGHT - HTOBJECT = 19 - HTCLOSE = 20 - HTHELP = 21 -) - -// DrawText[Ex] format flags -const ( - DT_TOP = 0x00000000 - DT_LEFT = 0x00000000 - DT_CENTER = 0x00000001 - DT_RIGHT = 0x00000002 - DT_VCENTER = 0x00000004 - DT_BOTTOM = 0x00000008 - DT_WORDBREAK = 0x00000010 - DT_SINGLELINE = 0x00000020 - DT_EXPANDTABS = 0x00000040 - DT_TABSTOP = 0x00000080 - DT_NOCLIP = 0x00000100 - DT_EXTERNALLEADING = 0x00000200 - DT_CALCRECT = 0x00000400 - DT_NOPREFIX = 0x00000800 - DT_INTERNAL = 0x00001000 - DT_EDITCONTROL = 0x00002000 - DT_PATH_ELLIPSIS = 0x00004000 - DT_END_ELLIPSIS = 0x00008000 - DT_MODIFYSTRING = 0x00010000 - DT_RTLREADING = 0x00020000 - DT_WORD_ELLIPSIS = 0x00040000 - DT_NOFULLWIDTHCHARBREAK = 0x00080000 - DT_HIDEPREFIX = 0x00100000 - DT_PREFIXONLY = 0x00200000 -) - -const CLR_INVALID = 0xFFFFFFFF - -// Background Modes -const ( - TRANSPARENT = 1 - OPAQUE = 2 - BKMODE_LAST = 2 -) - -// Global Memory Flags -const ( - GMEM_FIXED = 0x0000 - GMEM_MOVEABLE = 0x0002 - GMEM_NOCOMPACT = 0x0010 - GMEM_NODISCARD = 0x0020 - GMEM_ZEROINIT = 0x0040 - GMEM_MODIFY = 0x0080 - GMEM_DISCARDABLE = 0x0100 - GMEM_NOT_BANKED = 0x1000 - GMEM_SHARE = 0x2000 - GMEM_DDESHARE = 0x2000 - GMEM_NOTIFY = 0x4000 - GMEM_LOWER = GMEM_NOT_BANKED - GMEM_VALID_FLAGS = 0x7F72 - GMEM_INVALID_HANDLE = 0x8000 - GHND = (GMEM_MOVEABLE | GMEM_ZEROINIT) - GPTR = (GMEM_FIXED | GMEM_ZEROINIT) -) - -// Ternary raster operations -const ( - SRCCOPY = 0x00CC0020 - SRCPAINT = 0x00EE0086 - SRCAND = 0x008800C6 - SRCINVERT = 0x00660046 - SRCERASE = 0x00440328 - NOTSRCCOPY = 0x00330008 - NOTSRCERASE = 0x001100A6 - MERGECOPY = 0x00C000CA - MERGEPAINT = 0x00BB0226 - PATCOPY = 0x00F00021 - PATPAINT = 0x00FB0A09 - PATINVERT = 0x005A0049 - DSTINVERT = 0x00550009 - BLACKNESS = 0x00000042 - WHITENESS = 0x00FF0062 - NOMIRRORBITMAP = 0x80000000 - CAPTUREBLT = 0x40000000 -) - -// Clipboard formats -const ( - CF_TEXT = 1 - CF_BITMAP = 2 - CF_METAFILEPICT = 3 - CF_SYLK = 4 - CF_DIF = 5 - CF_TIFF = 6 - CF_OEMTEXT = 7 - CF_DIB = 8 - CF_PALETTE = 9 - CF_PENDATA = 10 - CF_RIFF = 11 - CF_WAVE = 12 - CF_UNICODETEXT = 13 - CF_ENHMETAFILE = 14 - CF_HDROP = 15 - CF_LOCALE = 16 - CF_DIBV5 = 17 - CF_MAX = 18 - CF_OWNERDISPLAY = 0x0080 - CF_DSPTEXT = 0x0081 - CF_DSPBITMAP = 0x0082 - CF_DSPMETAFILEPICT = 0x0083 - CF_DSPENHMETAFILE = 0x008E - CF_PRIVATEFIRST = 0x0200 - CF_PRIVATELAST = 0x02FF - CF_GDIOBJFIRST = 0x0300 - CF_GDIOBJLAST = 0x03FF -) - -// Bitmap compression formats -const ( - BI_RGB = 0 - BI_RLE8 = 1 - BI_RLE4 = 2 - BI_BITFIELDS = 3 - BI_JPEG = 4 - BI_PNG = 5 -) - -// SetDIBitsToDevice fuColorUse -const ( - DIB_PAL_COLORS = 1 - DIB_RGB_COLORS = 0 -) - -const ( - STANDARD_RIGHTS_REQUIRED = 0x000F -) - -// Service Control Manager object specific access types -const ( - SC_MANAGER_CONNECT = 0x0001 - SC_MANAGER_CREATE_SERVICE = 0x0002 - SC_MANAGER_ENUMERATE_SERVICE = 0x0004 - SC_MANAGER_LOCK = 0x0008 - SC_MANAGER_QUERY_LOCK_STATUS = 0x0010 - SC_MANAGER_MODIFY_BOOT_CONFIG = 0x0020 - SC_MANAGER_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_LOCK | SC_MANAGER_QUERY_LOCK_STATUS | SC_MANAGER_MODIFY_BOOT_CONFIG -) - -// Service Types (Bit Mask) -const ( - SERVICE_KERNEL_DRIVER = 0x00000001 - SERVICE_FILE_SYSTEM_DRIVER = 0x00000002 - SERVICE_ADAPTER = 0x00000004 - SERVICE_RECOGNIZER_DRIVER = 0x00000008 - SERVICE_DRIVER = SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER | SERVICE_RECOGNIZER_DRIVER - SERVICE_WIN32_OWN_PROCESS = 0x00000010 - SERVICE_WIN32_SHARE_PROCESS = 0x00000020 - SERVICE_WIN32 = SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS - SERVICE_INTERACTIVE_PROCESS = 0x00000100 - SERVICE_TYPE_ALL = SERVICE_WIN32 | SERVICE_ADAPTER | SERVICE_DRIVER | SERVICE_INTERACTIVE_PROCESS -) - -// Service State -- for CurrentState -const ( - SERVICE_STOPPED = 0x00000001 - SERVICE_START_PENDING = 0x00000002 - SERVICE_STOP_PENDING = 0x00000003 - SERVICE_RUNNING = 0x00000004 - SERVICE_CONTINUE_PENDING = 0x00000005 - SERVICE_PAUSE_PENDING = 0x00000006 - SERVICE_PAUSED = 0x00000007 -) - -// Controls Accepted (Bit Mask) -const ( - SERVICE_ACCEPT_STOP = 0x00000001 - SERVICE_ACCEPT_PAUSE_CONTINUE = 0x00000002 - SERVICE_ACCEPT_SHUTDOWN = 0x00000004 - SERVICE_ACCEPT_PARAMCHANGE = 0x00000008 - SERVICE_ACCEPT_NETBINDCHANGE = 0x00000010 - SERVICE_ACCEPT_HARDWAREPROFILECHANGE = 0x00000020 - SERVICE_ACCEPT_POWEREVENT = 0x00000040 - SERVICE_ACCEPT_SESSIONCHANGE = 0x00000080 - SERVICE_ACCEPT_PRESHUTDOWN = 0x00000100 - SERVICE_ACCEPT_TIMECHANGE = 0x00000200 - SERVICE_ACCEPT_TRIGGEREVENT = 0x00000400 -) - -// Service object specific access type -const ( - SERVICE_QUERY_CONFIG = 0x0001 - SERVICE_CHANGE_CONFIG = 0x0002 - SERVICE_QUERY_STATUS = 0x0004 - SERVICE_ENUMERATE_DEPENDENTS = 0x0008 - SERVICE_START = 0x0010 - SERVICE_STOP = 0x0020 - SERVICE_PAUSE_CONTINUE = 0x0040 - SERVICE_INTERROGATE = 0x0080 - SERVICE_USER_DEFINED_CONTROL = 0x0100 - - SERVICE_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | - SERVICE_QUERY_CONFIG | - SERVICE_CHANGE_CONFIG | - SERVICE_QUERY_STATUS | - SERVICE_ENUMERATE_DEPENDENTS | - SERVICE_START | - SERVICE_STOP | - SERVICE_PAUSE_CONTINUE | - SERVICE_INTERROGATE | - SERVICE_USER_DEFINED_CONTROL -) - -// MapVirtualKey maptypes -const ( - MAPVK_VK_TO_CHAR = 2 - MAPVK_VK_TO_VSC = 0 - MAPVK_VSC_TO_VK = 1 - MAPVK_VSC_TO_VK_EX = 3 -) - -// ReadEventLog Flags -const ( - EVENTLOG_SEEK_READ = 0x0002 - EVENTLOG_SEQUENTIAL_READ = 0x0001 - EVENTLOG_FORWARDS_READ = 0x0004 - EVENTLOG_BACKWARDS_READ = 0x0008 -) - -// CreateToolhelp32Snapshot flags -const ( - TH32CS_SNAPHEAPLIST = 0x00000001 - TH32CS_SNAPPROCESS = 0x00000002 - TH32CS_SNAPTHREAD = 0x00000004 - TH32CS_SNAPMODULE = 0x00000008 - TH32CS_SNAPMODULE32 = 0x00000010 - TH32CS_INHERIT = 0x80000000 - TH32CS_SNAPALL = TH32CS_SNAPHEAPLIST | TH32CS_SNAPMODULE | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD -) - -const ( - MAX_MODULE_NAME32 = 255 - MAX_PATH = 260 -) - -const ( - FOREGROUND_BLUE = 0x0001 - FOREGROUND_GREEN = 0x0002 - FOREGROUND_RED = 0x0004 - FOREGROUND_INTENSITY = 0x0008 - BACKGROUND_BLUE = 0x0010 - BACKGROUND_GREEN = 0x0020 - BACKGROUND_RED = 0x0040 - BACKGROUND_INTENSITY = 0x0080 - COMMON_LVB_LEADING_BYTE = 0x0100 - COMMON_LVB_TRAILING_BYTE = 0x0200 - COMMON_LVB_GRID_HORIZONTAL = 0x0400 - COMMON_LVB_GRID_LVERTICAL = 0x0800 - COMMON_LVB_GRID_RVERTICAL = 0x1000 - COMMON_LVB_REVERSE_VIDEO = 0x4000 - COMMON_LVB_UNDERSCORE = 0x8000 -) - -// Flags used by the DWM_BLURBEHIND structure to indicate -// which of its members contain valid information. -const ( - DWM_BB_ENABLE = 0x00000001 // A value for the fEnable member has been specified. - DWM_BB_BLURREGION = 0x00000002 // A value for the hRgnBlur member has been specified. - DWM_BB_TRANSITIONONMAXIMIZED = 0x00000004 // A value for the fTransitionOnMaximized member has been specified. -) - -// Flags used by the DwmEnableComposition function -// to change the state of Desktop Window Manager (DWM) composition. -const ( - DWM_EC_DISABLECOMPOSITION = 0 // Disable composition - DWM_EC_ENABLECOMPOSITION = 1 // Enable composition -) - -// enum-lite implementation for the following constant structure -type DWM_SHOWCONTACT int32 - -const ( - DWMSC_DOWN = 0x00000001 - DWMSC_UP = 0x00000002 - DWMSC_DRAG = 0x00000004 - DWMSC_HOLD = 0x00000008 - DWMSC_PENBARREL = 0x00000010 - DWMSC_NONE = 0x00000000 - DWMSC_ALL = 0xFFFFFFFF -) - -// enum-lite implementation for the following constant structure -type DWM_SOURCE_FRAME_SAMPLING int32 - -// TODO: need to verify this construction -// Flags used by the DwmSetPresentParameters function -// to specify the frame sampling type -const ( - DWM_SOURCE_FRAME_SAMPLING_POINT = iota + 1 - DWM_SOURCE_FRAME_SAMPLING_COVERAGE - DWM_SOURCE_FRAME_SAMPLING_LAST -) - -// Flags used by the DWM_THUMBNAIL_PROPERTIES structure to -// indicate which of its members contain valid information. -const ( - DWM_TNP_RECTDESTINATION = 0x00000001 // A value for the rcDestination member has been specified - DWM_TNP_RECTSOURCE = 0x00000002 // A value for the rcSource member has been specified - DWM_TNP_OPACITY = 0x00000004 // A value for the opacity member has been specified - DWM_TNP_VISIBLE = 0x00000008 // A value for the fVisible member has been specified - DWM_TNP_SOURCECLIENTAREAONLY = 0x00000010 // A value for the fSourceClientAreaOnly member has been specified -) - -// enum-lite implementation for the following constant structure -type DWMFLIP3DWINDOWPOLICY int32 - -// TODO: need to verify this construction -// Flags used by the DwmSetWindowAttribute function -// to specify the Flip3D window policy -const ( - DWMFLIP3D_DEFAULT = iota + 1 - DWMFLIP3D_EXCLUDEBELOW - DWMFLIP3D_EXCLUDEABOVE - DWMFLIP3D_LAST -) - -// enum-lite implementation for the following constant structure -type DWMNCRENDERINGPOLICY int32 - -// TODO: need to verify this construction -// Flags used by the DwmSetWindowAttribute function -// to specify the non-client area rendering policy -const ( - DWMNCRP_USEWINDOWSTYLE = iota + 1 - DWMNCRP_DISABLED - DWMNCRP_ENABLED - DWMNCRP_LAST -) - -// enum-lite implementation for the following constant structure -type DWMTRANSITION_OWNEDWINDOW_TARGET int32 - -const ( - DWMTRANSITION_OWNEDWINDOW_NULL = -1 - DWMTRANSITION_OWNEDWINDOW_REPOSITION = 0 -) - -// enum-lite implementation for the following constant structure -type DWMWINDOWATTRIBUTE int32 - -// TODO: need to verify this construction -// Flags used by the DwmGetWindowAttribute and DwmSetWindowAttribute functions -// to specify window attributes for non-client rendering -const ( - DWMWA_NCRENDERING_ENABLED = iota + 1 - DWMWA_NCRENDERING_POLICY - DWMWA_TRANSITIONS_FORCEDISABLED - DWMWA_ALLOW_NCPAINT - DWMWA_CAPTION_BUTTON_BOUNDS - DWMWA_NONCLIENT_RTL_LAYOUT - DWMWA_FORCE_ICONIC_REPRESENTATION - DWMWA_FLIP3D_POLICY - DWMWA_EXTENDED_FRAME_BOUNDS - DWMWA_HAS_ICONIC_BITMAP - DWMWA_DISALLOW_PEEK - DWMWA_EXCLUDED_FROM_PEEK - DWMWA_CLOAK - DWMWA_CLOAKED - DWMWA_FREEZE_REPRESENTATION - DWMWA_LAST -) - -// enum-lite implementation for the following constant structure -type GESTURE_TYPE int32 - -// TODO: use iota? -// Identifies the gesture type -const ( - GT_PEN_TAP = 0 - GT_PEN_DOUBLETAP = 1 - GT_PEN_RIGHTTAP = 2 - GT_PEN_PRESSANDHOLD = 3 - GT_PEN_PRESSANDHOLDABORT = 4 - GT_TOUCH_TAP = 5 - GT_TOUCH_DOUBLETAP = 6 - GT_TOUCH_RIGHTTAP = 7 - GT_TOUCH_PRESSANDHOLD = 8 - GT_TOUCH_PRESSANDHOLDABORT = 9 - GT_TOUCH_PRESSANDTAP = 10 -) - -// Icons -const ( - ICON_SMALL = 0 - ICON_BIG = 1 - ICON_SMALL2 = 2 -) - -const ( - SIZE_RESTORED = 0 - SIZE_MINIMIZED = 1 - SIZE_MAXIMIZED = 2 - SIZE_MAXSHOW = 3 - SIZE_MAXHIDE = 4 -) - -// XButton values -const ( - XBUTTON1 = 1 - XBUTTON2 = 2 -) - -// Devmode -const ( - DM_SPECVERSION = 0x0401 - - DM_ORIENTATION = 0x00000001 - DM_PAPERSIZE = 0x00000002 - DM_PAPERLENGTH = 0x00000004 - DM_PAPERWIDTH = 0x00000008 - DM_SCALE = 0x00000010 - DM_POSITION = 0x00000020 - DM_NUP = 0x00000040 - DM_DISPLAYORIENTATION = 0x00000080 - DM_COPIES = 0x00000100 - DM_DEFAULTSOURCE = 0x00000200 - DM_PRINTQUALITY = 0x00000400 - DM_COLOR = 0x00000800 - DM_DUPLEX = 0x00001000 - DM_YRESOLUTION = 0x00002000 - DM_TTOPTION = 0x00004000 - DM_COLLATE = 0x00008000 - DM_FORMNAME = 0x00010000 - DM_LOGPIXELS = 0x00020000 - DM_BITSPERPEL = 0x00040000 - DM_PELSWIDTH = 0x00080000 - DM_PELSHEIGHT = 0x00100000 - DM_DISPLAYFLAGS = 0x00200000 - DM_DISPLAYFREQUENCY = 0x00400000 - DM_ICMMETHOD = 0x00800000 - DM_ICMINTENT = 0x01000000 - DM_MEDIATYPE = 0x02000000 - DM_DITHERTYPE = 0x04000000 - DM_PANNINGWIDTH = 0x08000000 - DM_PANNINGHEIGHT = 0x10000000 - DM_DISPLAYFIXEDOUTPUT = 0x20000000 -) - -// ChangeDisplaySettings -const ( - CDS_UPDATEREGISTRY = 0x00000001 - CDS_TEST = 0x00000002 - CDS_FULLSCREEN = 0x00000004 - CDS_GLOBAL = 0x00000008 - CDS_SET_PRIMARY = 0x00000010 - CDS_VIDEOPARAMETERS = 0x00000020 - CDS_RESET = 0x40000000 - CDS_NORESET = 0x10000000 - - DISP_CHANGE_SUCCESSFUL = 0 - DISP_CHANGE_RESTART = 1 - DISP_CHANGE_FAILED = -1 - DISP_CHANGE_BADMODE = -2 - DISP_CHANGE_NOTUPDATED = -3 - DISP_CHANGE_BADFLAGS = -4 - DISP_CHANGE_BADPARAM = -5 - DISP_CHANGE_BADDUALVIEW = -6 -) - -const ( - ENUM_CURRENT_SETTINGS = 0xFFFFFFFF - ENUM_REGISTRY_SETTINGS = 0xFFFFFFFE -) - -// PIXELFORMATDESCRIPTOR -const ( - PFD_TYPE_RGBA = 0 - PFD_TYPE_COLORINDEX = 1 - - PFD_MAIN_PLANE = 0 - PFD_OVERLAY_PLANE = 1 - PFD_UNDERLAY_PLANE = -1 - - PFD_DOUBLEBUFFER = 0x00000001 - PFD_STEREO = 0x00000002 - PFD_DRAW_TO_WINDOW = 0x00000004 - PFD_DRAW_TO_BITMAP = 0x00000008 - PFD_SUPPORT_GDI = 0x00000010 - PFD_SUPPORT_OPENGL = 0x00000020 - PFD_GENERIC_FORMAT = 0x00000040 - PFD_NEED_PALETTE = 0x00000080 - PFD_NEED_SYSTEM_PALETTE = 0x00000100 - PFD_SWAP_EXCHANGE = 0x00000200 - PFD_SWAP_COPY = 0x00000400 - PFD_SWAP_LAYER_BUFFERS = 0x00000800 - PFD_GENERIC_ACCELERATED = 0x00001000 - PFD_SUPPORT_DIRECTDRAW = 0x00002000 - PFD_DIRECT3D_ACCELERATED = 0x00004000 - PFD_SUPPORT_COMPOSITION = 0x00008000 - - PFD_DEPTH_DONTCARE = 0x20000000 - PFD_DOUBLEBUFFER_DONTCARE = 0x40000000 - PFD_STEREO_DONTCARE = 0x80000000 -) - -const ( - INPUT_MOUSE = 0 - INPUT_KEYBOARD = 1 - INPUT_HARDWARE = 2 -) - -const ( - MOUSEEVENTF_ABSOLUTE = 0x8000 - MOUSEEVENTF_HWHEEL = 0x01000 - MOUSEEVENTF_MOVE = 0x0001 - MOUSEEVENTF_MOVE_NOCOALESCE = 0x2000 - MOUSEEVENTF_LEFTDOWN = 0x0002 - MOUSEEVENTF_LEFTUP = 0x0004 - MOUSEEVENTF_RIGHTDOWN = 0x0008 - MOUSEEVENTF_RIGHTUP = 0x0010 - MOUSEEVENTF_MIDDLEDOWN = 0x0020 - MOUSEEVENTF_MIDDLEUP = 0x0040 - MOUSEEVENTF_VIRTUALDESK = 0x4000 - MOUSEEVENTF_WHEEL = 0x0800 - MOUSEEVENTF_XDOWN = 0x0080 - MOUSEEVENTF_XUP = 0x0100 -) - -// Windows Hooks (WH_*) -// http://msdn.microsoft.com/en-us/library/windows/desktop/ms644990(v=vs.85).aspx -const ( - WH_CALLWNDPROC = 4 - WH_CALLWNDPROCRET = 12 - WH_CBT = 5 - WH_DEBUG = 9 - WH_FOREGROUNDIDLE = 11 - WH_GETMESSAGE = 3 - WH_JOURNALPLAYBACK = 1 - WH_JOURNALRECORD = 0 - WH_KEYBOARD = 2 - WH_KEYBOARD_LL = 13 - WH_MOUSE = 7 - WH_MOUSE_LL = 14 - WH_MSGFILTER = -1 - WH_SHELL = 10 - WH_SYSMSGFILTER = 6 -) - -// ComboBox return values -const ( - CB_OKAY = 0 - CB_ERR = ^uintptr(0) // -1 - CB_ERRSPACE = ^uintptr(1) // -2 -) - -// ComboBox notifications -const ( - CBN_ERRSPACE = -1 - CBN_SELCHANGE = 1 - CBN_DBLCLK = 2 - CBN_SETFOCUS = 3 - CBN_KILLFOCUS = 4 - CBN_EDITCHANGE = 5 - CBN_EDITUPDATE = 6 - CBN_DROPDOWN = 7 - CBN_CLOSEUP = 8 - CBN_SELENDOK = 9 - CBN_SELENDCANCEL = 10 -) - -// ComboBox styles -const ( - CBS_SIMPLE = 0x0001 - CBS_DROPDOWN = 0x0002 - CBS_DROPDOWNLIST = 0x0003 - CBS_OWNERDRAWFIXED = 0x0010 - CBS_OWNERDRAWVARIABLE = 0x0020 - CBS_AUTOHSCROLL = 0x0040 - CBS_OEMCONVERT = 0x0080 - CBS_SORT = 0x0100 - CBS_HASSTRINGS = 0x0200 - CBS_NOINTEGRALHEIGHT = 0x0400 - CBS_DISABLENOSCROLL = 0x0800 - CBS_UPPERCASE = 0x2000 - CBS_LOWERCASE = 0x4000 -) - -// ComboBox messages -const ( - CB_GETEDITSEL = 0x0140 - CB_LIMITTEXT = 0x0141 - CB_SETEDITSEL = 0x0142 - CB_ADDSTRING = 0x0143 - CB_DELETESTRING = 0x0144 - CB_DIR = 0x0145 - CB_GETCOUNT = 0x0146 - CB_GETCURSEL = 0x0147 - CB_GETLBTEXT = 0x0148 - CB_GETLBTEXTLEN = 0x0149 - CB_INSERTSTRING = 0x014A - CB_RESETCONTENT = 0x014B - CB_FINDSTRING = 0x014C - CB_SELECTSTRING = 0x014D - CB_SETCURSEL = 0x014E - CB_SHOWDROPDOWN = 0x014F - CB_GETITEMDATA = 0x0150 - CB_SETITEMDATA = 0x0151 - CB_GETDROPPEDCONTROLRECT = 0x0152 - CB_SETITEMHEIGHT = 0x0153 - CB_GETITEMHEIGHT = 0x0154 - CB_SETEXTENDEDUI = 0x0155 - CB_GETEXTENDEDUI = 0x0156 - CB_GETDROPPEDSTATE = 0x0157 - CB_FINDSTRINGEXACT = 0x0158 - CB_SETLOCALE = 0x0159 - CB_GETLOCALE = 0x015A - CB_GETTOPINDEX = 0x015b - CB_SETTOPINDEX = 0x015c - CB_GETHORIZONTALEXTENT = 0x015d - CB_SETHORIZONTALEXTENT = 0x015e - CB_GETDROPPEDWIDTH = 0x015f - CB_SETDROPPEDWIDTH = 0x0160 - CB_INITSTORAGE = 0x0161 - CB_MULTIPLEADDSTRING = 0x0163 - CB_GETCOMBOBOXINFO = 0x0164 -) - -// TreeView styles -const ( - TVS_HASBUTTONS = 0x0001 - TVS_HASLINES = 0x0002 - TVS_LINESATROOT = 0x0004 - TVS_EDITLABELS = 0x0008 - TVS_DISABLEDRAGDROP = 0x0010 - TVS_SHOWSELALWAYS = 0x0020 - TVS_RTLREADING = 0x0040 - TVS_NOTOOLTIPS = 0x0080 - TVS_CHECKBOXES = 0x0100 - TVS_TRACKSELECT = 0x0200 - TVS_SINGLEEXPAND = 0x0400 - TVS_INFOTIP = 0x0800 - TVS_FULLROWSELECT = 0x1000 - TVS_NOSCROLL = 0x2000 - TVS_NONEVENHEIGHT = 0x4000 - TVS_NOHSCROLL = 0x8000 -) - -const ( - TVS_EX_NOSINGLECOLLAPSE = 0x0001 - TVS_EX_MULTISELECT = 0x0002 - TVS_EX_DOUBLEBUFFER = 0x0004 - TVS_EX_NOINDENTSTATE = 0x0008 - TVS_EX_RICHTOOLTIP = 0x0010 - TVS_EX_AUTOHSCROLL = 0x0020 - TVS_EX_FADEINOUTEXPANDOS = 0x0040 - TVS_EX_PARTIALCHECKBOXES = 0x0080 - TVS_EX_EXCLUSIONCHECKBOXES = 0x0100 - TVS_EX_DIMMEDCHECKBOXES = 0x0200 - TVS_EX_DRAWIMAGEASYNC = 0x0400 -) - -const ( - TVIF_TEXT = 0x0001 - TVIF_IMAGE = 0x0002 - TVIF_PARAM = 0x0004 - TVIF_STATE = 0x0008 - TVIF_HANDLE = 0x0010 - TVIF_SELECTEDIMAGE = 0x0020 - TVIF_CHILDREN = 0x0040 - TVIF_INTEGRAL = 0x0080 - TVIF_STATEEX = 0x0100 - TVIF_EXPANDEDIMAGE = 0x0200 -) - -const ( - TVIS_SELECTED = 0x0002 - TVIS_CUT = 0x0004 - TVIS_DROPHILITED = 0x0008 - TVIS_BOLD = 0x0010 - TVIS_EXPANDED = 0x0020 - TVIS_EXPANDEDONCE = 0x0040 - TVIS_EXPANDPARTIAL = 0x0080 - TVIS_OVERLAYMASK = 0x0F00 - TVIS_STATEIMAGEMASK = 0xF000 - TVIS_USERMASK = 0xF000 -) - -const ( - TVIS_EX_FLAT = 0x0001 - TVIS_EX_DISABLED = 0x0002 - TVIS_EX_ALL = 0x0002 -) - -const ( - TVI_ROOT = ^HTREEITEM(0xffff) - TVI_FIRST = ^HTREEITEM(0xfffe) - TVI_LAST = ^HTREEITEM(0xfffd) - TVI_SORT = ^HTREEITEM(0xfffc) -) - -// TVM_EXPAND action flags -const ( - TVE_COLLAPSE = 0x0001 - TVE_EXPAND = 0x0002 - TVE_TOGGLE = 0x0003 - TVE_EXPANDPARTIAL = 0x4000 - TVE_COLLAPSERESET = 0x8000 -) - -const ( - TVGN_CARET = 9 -) - -// TreeView messages -const ( - TV_FIRST = 0x1100 - - TVM_INSERTITEM = TV_FIRST + 50 - TVM_DELETEITEM = TV_FIRST + 1 - TVM_EXPAND = TV_FIRST + 2 - TVM_GETITEMRECT = TV_FIRST + 4 - TVM_GETCOUNT = TV_FIRST + 5 - TVM_GETINDENT = TV_FIRST + 6 - TVM_SETINDENT = TV_FIRST + 7 - TVM_GETIMAGELIST = TV_FIRST + 8 - TVM_SETIMAGELIST = TV_FIRST + 9 - TVM_GETNEXTITEM = TV_FIRST + 10 - TVM_SELECTITEM = TV_FIRST + 11 - TVM_GETITEM = TV_FIRST + 62 - TVM_SETITEM = TV_FIRST + 63 - TVM_EDITLABEL = TV_FIRST + 65 - TVM_GETEDITCONTROL = TV_FIRST + 15 - TVM_GETVISIBLECOUNT = TV_FIRST + 16 - TVM_HITTEST = TV_FIRST + 17 - TVM_CREATEDRAGIMAGE = TV_FIRST + 18 - TVM_SORTCHILDREN = TV_FIRST + 19 - TVM_ENSUREVISIBLE = TV_FIRST + 20 - TVM_SORTCHILDRENCB = TV_FIRST + 21 - TVM_ENDEDITLABELNOW = TV_FIRST + 22 - TVM_GETISEARCHSTRING = TV_FIRST + 64 - TVM_SETTOOLTIPS = TV_FIRST + 24 - TVM_GETTOOLTIPS = TV_FIRST + 25 - TVM_SETINSERTMARK = TV_FIRST + 26 - TVM_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT - TVM_GETUNICODEFORMAT = CCM_GETUNICODEFORMAT - TVM_SETITEMHEIGHT = TV_FIRST + 27 - TVM_GETITEMHEIGHT = TV_FIRST + 28 - TVM_SETBKCOLOR = TV_FIRST + 29 - TVM_SETTEXTCOLOR = TV_FIRST + 30 - TVM_GETBKCOLOR = TV_FIRST + 31 - TVM_GETTEXTCOLOR = TV_FIRST + 32 - TVM_SETSCROLLTIME = TV_FIRST + 33 - TVM_GETSCROLLTIME = TV_FIRST + 34 - TVM_SETINSERTMARKCOLOR = TV_FIRST + 37 - TVM_GETINSERTMARKCOLOR = TV_FIRST + 38 - TVM_GETITEMSTATE = TV_FIRST + 39 - TVM_SETLINECOLOR = TV_FIRST + 40 - TVM_GETLINECOLOR = TV_FIRST + 41 - TVM_MAPACCIDTOHTREEITEM = TV_FIRST + 42 - TVM_MAPHTREEITEMTOACCID = TV_FIRST + 43 - TVM_SETEXTENDEDSTYLE = TV_FIRST + 44 - TVM_GETEXTENDEDSTYLE = TV_FIRST + 45 - TVM_SETAUTOSCROLLINFO = TV_FIRST + 59 -) - -// TreeView notifications -const ( - TVN_FIRST = ^uint32(399) - - TVN_SELCHANGING = TVN_FIRST - 50 - TVN_SELCHANGED = TVN_FIRST - 51 - TVN_GETDISPINFO = TVN_FIRST - 52 - TVN_ITEMEXPANDING = TVN_FIRST - 54 - TVN_ITEMEXPANDED = TVN_FIRST - 55 - TVN_BEGINDRAG = TVN_FIRST - 56 - TVN_BEGINRDRAG = TVN_FIRST - 57 - TVN_DELETEITEM = TVN_FIRST - 58 - TVN_BEGINLABELEDIT = TVN_FIRST - 59 - TVN_ENDLABELEDIT = TVN_FIRST - 60 - TVN_KEYDOWN = TVN_FIRST - 12 - TVN_GETINFOTIP = TVN_FIRST - 14 - TVN_SINGLEEXPAND = TVN_FIRST - 15 - TVN_ITEMCHANGING = TVN_FIRST - 17 - TVN_ITEMCHANGED = TVN_FIRST - 19 - TVN_ASYNCDRAW = TVN_FIRST - 20 -) - -// TreeView hit test constants -const ( - TVHT_NOWHERE = 1 - TVHT_ONITEMICON = 2 - TVHT_ONITEMLABEL = 4 - TVHT_ONITEM = TVHT_ONITEMICON | TVHT_ONITEMLABEL | TVHT_ONITEMSTATEICON - TVHT_ONITEMINDENT = 8 - TVHT_ONITEMBUTTON = 16 - TVHT_ONITEMRIGHT = 32 - TVHT_ONITEMSTATEICON = 64 - TVHT_ABOVE = 256 - TVHT_BELOW = 512 - TVHT_TORIGHT = 1024 - TVHT_TOLEFT = 2048 -) - -type HTREEITEM HANDLE - -type TVITEM struct { - Mask uint32 - HItem HTREEITEM - State uint32 - StateMask uint32 - PszText uintptr - CchTextMax int32 - IImage int32 - ISelectedImage int32 - CChildren int32 - LParam uintptr -} - -/*type TVITEMEX struct { - mask UINT - hItem HTREEITEM - state UINT - stateMask UINT - pszText LPWSTR - cchTextMax int - iImage int - iSelectedImage int - cChildren int - lParam LPARAM - iIntegral int - uStateEx UINT - hwnd HWND - iExpandedImage int -}*/ - -type TVINSERTSTRUCT struct { - HParent HTREEITEM - HInsertAfter HTREEITEM - Item TVITEM - // itemex TVITEMEX -} - -type NMTREEVIEW struct { - Hdr NMHDR - Action uint32 - ItemOld TVITEM - ItemNew TVITEM - PtDrag POINT -} - -type NMTVDISPINFO struct { - Hdr NMHDR - Item TVITEM -} - -type NMTVKEYDOWN struct { - Hdr NMHDR - WVKey uint16 - Flags uint32 -} - -type TVHITTESTINFO struct { - Pt POINT - Flags uint32 - HItem HTREEITEM -} - -// TabPage support - -const TCM_FIRST = 0x1300 -const TCN_FIRST = -550 - -const ( - TCS_SCROLLOPPOSITE = 0x0001 - TCS_BOTTOM = 0x0002 - TCS_RIGHT = 0x0002 - TCS_MULTISELECT = 0x0004 - TCS_FLATBUTTONS = 0x0008 - TCS_FORCEICONLEFT = 0x0010 - TCS_FORCELABELLEFT = 0x0020 - TCS_HOTTRACK = 0x0040 - TCS_VERTICAL = 0x0080 - TCS_TABS = 0x0000 - TCS_BUTTONS = 0x0100 - TCS_SINGLELINE = 0x0000 - TCS_MULTILINE = 0x0200 - TCS_RIGHTJUSTIFY = 0x0000 - TCS_FIXEDWIDTH = 0x0400 - TCS_RAGGEDRIGHT = 0x0800 - TCS_FOCUSONBUTTONDOWN = 0x1000 - TCS_OWNERDRAWFIXED = 0x2000 - TCS_TOOLTIPS = 0x4000 - TCS_FOCUSNEVER = 0x8000 -) - -const ( - TCS_EX_FLATSEPARATORS = 0x00000001 - TCS_EX_REGISTERDROP = 0x00000002 -) - -const ( - TCM_GETIMAGELIST = TCM_FIRST + 2 - TCM_SETIMAGELIST = TCM_FIRST + 3 - TCM_GETITEMCOUNT = TCM_FIRST + 4 - TCM_GETITEM = TCM_FIRST + 60 - TCM_SETITEM = TCM_FIRST + 61 - TCM_INSERTITEM = TCM_FIRST + 62 - TCM_DELETEITEM = TCM_FIRST + 8 - TCM_DELETEALLITEMS = TCM_FIRST + 9 - TCM_GETITEMRECT = TCM_FIRST + 10 - TCM_GETCURSEL = TCM_FIRST + 11 - TCM_SETCURSEL = TCM_FIRST + 12 - TCM_HITTEST = TCM_FIRST + 13 - TCM_SETITEMEXTRA = TCM_FIRST + 14 - TCM_ADJUSTRECT = TCM_FIRST + 40 - TCM_SETITEMSIZE = TCM_FIRST + 41 - TCM_REMOVEIMAGE = TCM_FIRST + 42 - TCM_SETPADDING = TCM_FIRST + 43 - TCM_GETROWCOUNT = TCM_FIRST + 44 - TCM_GETTOOLTIPS = TCM_FIRST + 45 - TCM_SETTOOLTIPS = TCM_FIRST + 46 - TCM_GETCURFOCUS = TCM_FIRST + 47 - TCM_SETCURFOCUS = TCM_FIRST + 48 - TCM_SETMINTABWIDTH = TCM_FIRST + 49 - TCM_DESELECTALL = TCM_FIRST + 50 - TCM_HIGHLIGHTITEM = TCM_FIRST + 51 - TCM_SETEXTENDEDSTYLE = TCM_FIRST + 52 - TCM_GETEXTENDEDSTYLE = TCM_FIRST + 53 - TCM_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT - TCM_GETUNICODEFORMAT = CCM_GETUNICODEFORMAT -) - -const ( - TCIF_TEXT = 0x0001 - TCIF_IMAGE = 0x0002 - TCIF_RTLREADING = 0x0004 - TCIF_PARAM = 0x0008 - TCIF_STATE = 0x0010 -) - -const ( - TCIS_BUTTONPRESSED = 0x0001 - TCIS_HIGHLIGHTED = 0x0002 -) - -const ( - TCHT_NOWHERE = 0x0001 - TCHT_ONITEMICON = 0x0002 - TCHT_ONITEMLABEL = 0x0004 - TCHT_ONITEM = TCHT_ONITEMICON | TCHT_ONITEMLABEL -) - -const ( - TCN_KEYDOWN = TCN_FIRST - 0 - TCN_SELCHANGE = TCN_FIRST - 1 - TCN_SELCHANGING = TCN_FIRST - 2 - TCN_GETOBJECT = TCN_FIRST - 3 - TCN_FOCUSCHANGE = TCN_FIRST - 4 -) - -type TCITEMHEADER struct { - Mask uint32 - LpReserved1 uint32 - LpReserved2 uint32 - PszText *uint16 - CchTextMax int32 - IImage int32 -} - -type TCITEM struct { - Mask uint32 - DwState uint32 - DwStateMask uint32 - PszText *uint16 - CchTextMax int32 - IImage int32 - LParam uintptr -} - -type TCHITTESTINFO struct { - Pt POINT - flags uint32 -} - -type NMTCKEYDOWN struct { - Hdr NMHDR - WVKey uint16 - Flags uint32 -} - -// Menu support constants - -// Constants for MENUITEMINFO.fMask -const ( - MIIM_STATE = 1 - MIIM_ID = 2 - MIIM_SUBMENU = 4 - MIIM_CHECKMARKS = 8 - MIIM_TYPE = 16 - MIIM_DATA = 32 - MIIM_STRING = 64 - MIIM_BITMAP = 128 - MIIM_FTYPE = 256 -) - -// Constants for MENUITEMINFO.fType -const ( - MFT_BITMAP = 4 - MFT_MENUBARBREAK = 32 - MFT_MENUBREAK = 64 - MFT_OWNERDRAW = 256 - MFT_RADIOCHECK = 512 - MFT_RIGHTJUSTIFY = 0x4000 - MFT_SEPARATOR = 0x800 - MFT_RIGHTORDER = 0x2000 - MFT_STRING = 0 -) - -// Constants for MENUITEMINFO.fState -const ( - MFS_CHECKED = 8 - MFS_DEFAULT = 4096 - MFS_DISABLED = 3 - MFS_ENABLED = 0 - MFS_GRAYED = 3 - MFS_HILITE = 128 - MFS_UNCHECKED = 0 - MFS_UNHILITE = 0 -) - -// Constants for MENUITEMINFO.hbmp* -const ( - HBMMENU_CALLBACK = -1 - HBMMENU_SYSTEM = 1 - HBMMENU_MBAR_RESTORE = 2 - HBMMENU_MBAR_MINIMIZE = 3 - HBMMENU_MBAR_CLOSE = 5 - HBMMENU_MBAR_CLOSE_D = 6 - HBMMENU_MBAR_MINIMIZE_D = 7 - HBMMENU_POPUP_CLOSE = 8 - HBMMENU_POPUP_RESTORE = 9 - HBMMENU_POPUP_MAXIMIZE = 10 - HBMMENU_POPUP_MINIMIZE = 11 -) - -// MENUINFO mask constants -const ( - MIM_APPLYTOSUBMENUS = 0x80000000 - MIM_BACKGROUND = 0x00000002 - MIM_HELPID = 0x00000004 - MIM_MAXHEIGHT = 0x00000001 - MIM_MENUDATA = 0x00000008 - MIM_STYLE = 0x00000010 -) - -// MENUINFO style constants -const ( - MNS_AUTODISMISS = 0x10000000 - MNS_CHECKORBMP = 0x04000000 - MNS_DRAGDROP = 0x20000000 - MNS_MODELESS = 0x40000000 - MNS_NOCHECK = 0x80000000 - MNS_NOTIFYBYPOS = 0x08000000 -) - -const ( - MF_BYCOMMAND = 0x00000000 - MF_BYPOSITION = 0x00000400 -) - -type MENUITEMINFO struct { - CbSize uint32 - FMask uint32 - FType uint32 - FState uint32 - WID uint32 - HSubMenu HMENU - HbmpChecked HBITMAP - HbmpUnchecked HBITMAP - DwItemData uintptr - DwTypeData *uint16 - Cch uint32 - HbmpItem HBITMAP -} - -type MENUINFO struct { - CbSize uint32 - FMask uint32 - DwStyle uint32 - CyMax uint32 - HbrBack HBRUSH - DwContextHelpID uint32 - DwMenuData uintptr -} - -// UI state constants -const ( - UIS_SET = 1 - UIS_CLEAR = 2 - UIS_INITIALIZE = 3 -) - -// UI state constants -const ( - UISF_HIDEFOCUS = 0x1 - UISF_HIDEACCEL = 0x2 - UISF_ACTIVE = 0x4 -) - -// Virtual key codes -const ( - VK_LBUTTON = 1 - VK_RBUTTON = 2 - VK_CANCEL = 3 - VK_MBUTTON = 4 - VK_XBUTTON1 = 5 - VK_XBUTTON2 = 6 - VK_BACK = 8 - VK_TAB = 9 - VK_CLEAR = 12 - VK_RETURN = 13 - VK_SHIFT = 16 - VK_CONTROL = 17 - VK_MENU = 18 - VK_PAUSE = 19 - VK_CAPITAL = 20 - VK_KANA = 0x15 - VK_HANGEUL = 0x15 - VK_HANGUL = 0x15 - VK_JUNJA = 0x17 - VK_FINAL = 0x18 - VK_HANJA = 0x19 - VK_KANJI = 0x19 - VK_ESCAPE = 0x1B - VK_CONVERT = 0x1C - VK_NONCONVERT = 0x1D - VK_ACCEPT = 0x1E - VK_MODECHANGE = 0x1F - VK_SPACE = 32 - VK_PRIOR = 33 - VK_NEXT = 34 - VK_END = 35 - VK_HOME = 36 - VK_LEFT = 37 - VK_UP = 38 - VK_RIGHT = 39 - VK_DOWN = 40 - VK_SELECT = 41 - VK_PRINT = 42 - VK_EXECUTE = 43 - VK_SNAPSHOT = 44 - VK_INSERT = 45 - VK_DELETE = 46 - VK_HELP = 47 - VK_LWIN = 0x5B - VK_RWIN = 0x5C - VK_APPS = 0x5D - VK_SLEEP = 0x5F - VK_NUMPAD0 = 0x60 - VK_NUMPAD1 = 0x61 - VK_NUMPAD2 = 0x62 - VK_NUMPAD3 = 0x63 - VK_NUMPAD4 = 0x64 - VK_NUMPAD5 = 0x65 - VK_NUMPAD6 = 0x66 - VK_NUMPAD7 = 0x67 - VK_NUMPAD8 = 0x68 - VK_NUMPAD9 = 0x69 - VK_MULTIPLY = 0x6A - VK_ADD = 0x6B - VK_SEPARATOR = 0x6C - VK_SUBTRACT = 0x6D - VK_DECIMAL = 0x6E - VK_DIVIDE = 0x6F - VK_F1 = 0x70 - VK_F2 = 0x71 - VK_F3 = 0x72 - VK_F4 = 0x73 - VK_F5 = 0x74 - VK_F6 = 0x75 - VK_F7 = 0x76 - VK_F8 = 0x77 - VK_F9 = 0x78 - VK_F10 = 0x79 - VK_F11 = 0x7A - VK_F12 = 0x7B - VK_F13 = 0x7C - VK_F14 = 0x7D - VK_F15 = 0x7E - VK_F16 = 0x7F - VK_F17 = 0x80 - VK_F18 = 0x81 - VK_F19 = 0x82 - VK_F20 = 0x83 - VK_F21 = 0x84 - VK_F22 = 0x85 - VK_F23 = 0x86 - VK_F24 = 0x87 - VK_NUMLOCK = 0x90 - VK_SCROLL = 0x91 - VK_LSHIFT = 0xA0 - VK_RSHIFT = 0xA1 - VK_LCONTROL = 0xA2 - VK_RCONTROL = 0xA3 - VK_LMENU = 0xA4 - VK_RMENU = 0xA5 - VK_BROWSER_BACK = 0xA6 - VK_BROWSER_FORWARD = 0xA7 - VK_BROWSER_REFRESH = 0xA8 - VK_BROWSER_STOP = 0xA9 - VK_BROWSER_SEARCH = 0xAA - VK_BROWSER_FAVORITES = 0xAB - VK_BROWSER_HOME = 0xAC - VK_VOLUME_MUTE = 0xAD - VK_VOLUME_DOWN = 0xAE - VK_VOLUME_UP = 0xAF - VK_MEDIA_NEXT_TRACK = 0xB0 - VK_MEDIA_PREV_TRACK = 0xB1 - VK_MEDIA_STOP = 0xB2 - VK_MEDIA_PLAY_PAUSE = 0xB3 - VK_LAUNCH_MAIL = 0xB4 - VK_LAUNCH_MEDIA_SELECT = 0xB5 - VK_LAUNCH_APP1 = 0xB6 - VK_LAUNCH_APP2 = 0xB7 - VK_OEM_1 = 0xBA - VK_OEM_PLUS = 0xBB - VK_OEM_COMMA = 0xBC - VK_OEM_MINUS = 0xBD - VK_OEM_PERIOD = 0xBE - VK_OEM_2 = 0xBF - VK_OEM_3 = 0xC0 - VK_OEM_4 = 0xDB - VK_OEM_5 = 0xDC - VK_OEM_6 = 0xDD - VK_OEM_7 = 0xDE - VK_OEM_8 = 0xDF - VK_OEM_102 = 0xE2 - VK_PROCESSKEY = 0xE5 - VK_PACKET = 0xE7 - VK_ATTN = 0xF6 - VK_CRSEL = 0xF7 - VK_EXSEL = 0xF8 - VK_EREOF = 0xF9 - VK_PLAY = 0xFA - VK_ZOOM = 0xFB - VK_NONAME = 0xFC - VK_PA1 = 0xFD - VK_OEM_CLEAR = 0xFE -) - -// ScrollBar constants -const ( - SB_HORZ = 0 - SB_VERT = 1 - SB_CTL = 2 - SB_BOTH = 3 -) - -// ScrollBar commands -const ( - SB_LINEUP = 0 - SB_LINELEFT = 0 - SB_LINEDOWN = 1 - SB_LINERIGHT = 1 - SB_PAGEUP = 2 - SB_PAGELEFT = 2 - SB_PAGEDOWN = 3 - SB_PAGERIGHT = 3 - SB_THUMBPOSITION = 4 - SB_THUMBTRACK = 5 - SB_TOP = 6 - SB_LEFT = 6 - SB_BOTTOM = 7 - SB_RIGHT = 7 - SB_ENDSCROLL = 8 -) - -// [Get|Set]ScrollInfo mask constants -const ( - SIF_RANGE = 1 - SIF_PAGE = 2 - SIF_POS = 4 - SIF_DISABLENOSCROLL = 8 - SIF_TRACKPOS = 16 - SIF_ALL = SIF_RANGE + SIF_PAGE + SIF_POS + SIF_TRACKPOS -) diff --git a/v2/internal/frontend/desktop/windows/winc/w32/dwmapi.go b/v2/internal/frontend/desktop/windows/winc/w32/dwmapi.go deleted file mode 100644 index f5c1b7559..000000000 --- a/v2/internal/frontend/desktop/windows/winc/w32/dwmapi.go +++ /dev/null @@ -1,20 +0,0 @@ -//go:build windows - -package w32 - -import "syscall" - -var ( - moddwmapi = syscall.NewLazyDLL("dwmapi.dll") - - procDwmSetWindowAttribute = moddwmapi.NewProc("DwmSetWindowAttribute") -) - -func DwmSetWindowAttribute(hwnd HWND, dwAttribute DWMWINDOWATTRIBUTE, pvAttribute LPCVOID, cbAttribute uint32) HRESULT { - ret, _, _ := procDwmSetWindowAttribute.Call( - hwnd, - uintptr(dwAttribute), - uintptr(pvAttribute), - uintptr(cbAttribute)) - return HRESULT(ret) -} diff --git a/v2/internal/frontend/desktop/windows/winc/w32/gdi32.go b/v2/internal/frontend/desktop/windows/winc/w32/gdi32.go deleted file mode 100644 index b4b9053e6..000000000 --- a/v2/internal/frontend/desktop/windows/winc/w32/gdi32.go +++ /dev/null @@ -1,526 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved. - */ -package w32 - -import ( - "syscall" - "unsafe" -) - -var ( - modgdi32 = syscall.NewLazyDLL("gdi32.dll") - - procGetDeviceCaps = modgdi32.NewProc("GetDeviceCaps") - procDeleteObject = modgdi32.NewProc("DeleteObject") - procCreateFontIndirect = modgdi32.NewProc("CreateFontIndirectW") - procAbortDoc = modgdi32.NewProc("AbortDoc") - procBitBlt = modgdi32.NewProc("BitBlt") - procPatBlt = modgdi32.NewProc("PatBlt") - procCloseEnhMetaFile = modgdi32.NewProc("CloseEnhMetaFile") - procCopyEnhMetaFile = modgdi32.NewProc("CopyEnhMetaFileW") - procCreateBrushIndirect = modgdi32.NewProc("CreateBrushIndirect") - procCreateCompatibleDC = modgdi32.NewProc("CreateCompatibleDC") - procCreateDC = modgdi32.NewProc("CreateDCW") - procCreateDIBSection = modgdi32.NewProc("CreateDIBSection") - procCreateEnhMetaFile = modgdi32.NewProc("CreateEnhMetaFileW") - procCreateIC = modgdi32.NewProc("CreateICW") - procDeleteDC = modgdi32.NewProc("DeleteDC") - procDeleteEnhMetaFile = modgdi32.NewProc("DeleteEnhMetaFile") - procEllipse = modgdi32.NewProc("Ellipse") - procEndDoc = modgdi32.NewProc("EndDoc") - procEndPage = modgdi32.NewProc("EndPage") - procExtCreatePen = modgdi32.NewProc("ExtCreatePen") - procGetEnhMetaFile = modgdi32.NewProc("GetEnhMetaFileW") - procGetEnhMetaFileHeader = modgdi32.NewProc("GetEnhMetaFileHeader") - procGetObject = modgdi32.NewProc("GetObjectW") - procGetStockObject = modgdi32.NewProc("GetStockObject") - procGetTextExtentExPoint = modgdi32.NewProc("GetTextExtentExPointW") - procGetTextExtentPoint32 = modgdi32.NewProc("GetTextExtentPoint32W") - procGetTextMetrics = modgdi32.NewProc("GetTextMetricsW") - procLineTo = modgdi32.NewProc("LineTo") - procMoveToEx = modgdi32.NewProc("MoveToEx") - procPlayEnhMetaFile = modgdi32.NewProc("PlayEnhMetaFile") - procRectangle = modgdi32.NewProc("Rectangle") - procResetDC = modgdi32.NewProc("ResetDCW") - procSelectObject = modgdi32.NewProc("SelectObject") - procSetBkMode = modgdi32.NewProc("SetBkMode") - procSetBrushOrgEx = modgdi32.NewProc("SetBrushOrgEx") - procSetStretchBltMode = modgdi32.NewProc("SetStretchBltMode") - procSetTextColor = modgdi32.NewProc("SetTextColor") - procSetBkColor = modgdi32.NewProc("SetBkColor") - procStartDoc = modgdi32.NewProc("StartDocW") - procStartPage = modgdi32.NewProc("StartPage") - procStretchBlt = modgdi32.NewProc("StretchBlt") - procSetDIBitsToDevice = modgdi32.NewProc("SetDIBitsToDevice") - procChoosePixelFormat = modgdi32.NewProc("ChoosePixelFormat") - procDescribePixelFormat = modgdi32.NewProc("DescribePixelFormat") - procGetEnhMetaFilePixelFormat = modgdi32.NewProc("GetEnhMetaFilePixelFormat") - procGetPixelFormat = modgdi32.NewProc("GetPixelFormat") - procSetPixelFormat = modgdi32.NewProc("SetPixelFormat") - procSwapBuffers = modgdi32.NewProc("SwapBuffers") -) - -func GetDeviceCaps(hdc HDC, index int) int { - ret, _, _ := procGetDeviceCaps.Call( - uintptr(hdc), - uintptr(index)) - - return int(ret) -} - -func DeleteObject(hObject HGDIOBJ) bool { - ret, _, _ := procDeleteObject.Call( - uintptr(hObject)) - - return ret != 0 -} - -func CreateFontIndirect(logFont *LOGFONT) HFONT { - ret, _, _ := procCreateFontIndirect.Call( - uintptr(unsafe.Pointer(logFont))) - - return HFONT(ret) -} - -func AbortDoc(hdc HDC) int { - ret, _, _ := procAbortDoc.Call( - uintptr(hdc)) - - return int(ret) -} - -func BitBlt(hdcDest HDC, nXDest, nYDest, nWidth, nHeight int, hdcSrc HDC, nXSrc, nYSrc int, dwRop uint) { - ret, _, _ := procBitBlt.Call( - uintptr(hdcDest), - uintptr(nXDest), - uintptr(nYDest), - uintptr(nWidth), - uintptr(nHeight), - uintptr(hdcSrc), - uintptr(nXSrc), - uintptr(nYSrc), - uintptr(dwRop)) - - if ret == 0 { - panic("BitBlt failed") - } -} - -func PatBlt(hdc HDC, nXLeft, nYLeft, nWidth, nHeight int, dwRop uint) { - ret, _, _ := procPatBlt.Call( - uintptr(hdc), - uintptr(nXLeft), - uintptr(nYLeft), - uintptr(nWidth), - uintptr(nHeight), - uintptr(dwRop)) - - if ret == 0 { - panic("PatBlt failed") - } -} - -func CloseEnhMetaFile(hdc HDC) HENHMETAFILE { - ret, _, _ := procCloseEnhMetaFile.Call( - uintptr(hdc)) - - return HENHMETAFILE(ret) -} - -func CopyEnhMetaFile(hemfSrc HENHMETAFILE, lpszFile *uint16) HENHMETAFILE { - ret, _, _ := procCopyEnhMetaFile.Call( - uintptr(hemfSrc), - uintptr(unsafe.Pointer(lpszFile))) - - return HENHMETAFILE(ret) -} - -func CreateBrushIndirect(lplb *LOGBRUSH) HBRUSH { - ret, _, _ := procCreateBrushIndirect.Call( - uintptr(unsafe.Pointer(lplb))) - - return HBRUSH(ret) -} - -func CreateCompatibleDC(hdc HDC) HDC { - ret, _, _ := procCreateCompatibleDC.Call( - uintptr(hdc)) - - if ret == 0 { - panic("Create compatible DC failed") - } - - return HDC(ret) -} - -func CreateDC(lpszDriver, lpszDevice, lpszOutput *uint16, lpInitData *DEVMODE) HDC { - ret, _, _ := procCreateDC.Call( - uintptr(unsafe.Pointer(lpszDriver)), - uintptr(unsafe.Pointer(lpszDevice)), - uintptr(unsafe.Pointer(lpszOutput)), - uintptr(unsafe.Pointer(lpInitData))) - - return HDC(ret) -} - -func CreateDIBSection(hdc HDC, pbmi *BITMAPINFO, iUsage uint, ppvBits *unsafe.Pointer, hSection HANDLE, dwOffset uint) HBITMAP { - ret, _, _ := procCreateDIBSection.Call( - uintptr(hdc), - uintptr(unsafe.Pointer(pbmi)), - uintptr(iUsage), - uintptr(unsafe.Pointer(ppvBits)), - uintptr(hSection), - uintptr(dwOffset)) - - return HBITMAP(ret) -} - -func CreateEnhMetaFile(hdcRef HDC, lpFilename *uint16, lpRect *RECT, lpDescription *uint16) HDC { - ret, _, _ := procCreateEnhMetaFile.Call( - uintptr(hdcRef), - uintptr(unsafe.Pointer(lpFilename)), - uintptr(unsafe.Pointer(lpRect)), - uintptr(unsafe.Pointer(lpDescription))) - - return HDC(ret) -} - -func CreateIC(lpszDriver, lpszDevice, lpszOutput *uint16, lpdvmInit *DEVMODE) HDC { - ret, _, _ := procCreateIC.Call( - uintptr(unsafe.Pointer(lpszDriver)), - uintptr(unsafe.Pointer(lpszDevice)), - uintptr(unsafe.Pointer(lpszOutput)), - uintptr(unsafe.Pointer(lpdvmInit))) - - return HDC(ret) -} - -func DeleteDC(hdc HDC) bool { - ret, _, _ := procDeleteDC.Call( - uintptr(hdc)) - - return ret != 0 -} - -func DeleteEnhMetaFile(hemf HENHMETAFILE) bool { - ret, _, _ := procDeleteEnhMetaFile.Call( - uintptr(hemf)) - - return ret != 0 -} - -func Ellipse(hdc HDC, nLeftRect, nTopRect, nRightRect, nBottomRect int32) bool { - ret, _, _ := procEllipse.Call( - uintptr(hdc), - uintptr(nLeftRect), - uintptr(nTopRect), - uintptr(nRightRect), - uintptr(nBottomRect)) - - return ret != 0 -} - -func EndDoc(hdc HDC) int { - ret, _, _ := procEndDoc.Call( - uintptr(hdc)) - - return int(ret) -} - -func EndPage(hdc HDC) int { - ret, _, _ := procEndPage.Call( - uintptr(hdc)) - - return int(ret) -} - -func ExtCreatePen(dwPenStyle, dwWidth uint, lplb *LOGBRUSH, dwStyleCount uint, lpStyle *uint) HPEN { - ret, _, _ := procExtCreatePen.Call( - uintptr(dwPenStyle), - uintptr(dwWidth), - uintptr(unsafe.Pointer(lplb)), - uintptr(dwStyleCount), - uintptr(unsafe.Pointer(lpStyle))) - - return HPEN(ret) -} - -func GetEnhMetaFile(lpszMetaFile *uint16) HENHMETAFILE { - ret, _, _ := procGetEnhMetaFile.Call( - uintptr(unsafe.Pointer(lpszMetaFile))) - - return HENHMETAFILE(ret) -} - -func GetEnhMetaFileHeader(hemf HENHMETAFILE, cbBuffer uint, lpemh *ENHMETAHEADER) uint { - ret, _, _ := procGetEnhMetaFileHeader.Call( - uintptr(hemf), - uintptr(cbBuffer), - uintptr(unsafe.Pointer(lpemh))) - - return uint(ret) -} - -func GetObject(hgdiobj HGDIOBJ, cbBuffer uintptr, lpvObject unsafe.Pointer) int { - ret, _, _ := procGetObject.Call( - uintptr(hgdiobj), - uintptr(cbBuffer), - uintptr(lpvObject)) - - return int(ret) -} - -func GetStockObject(fnObject int) HGDIOBJ { - ret, _, _ := procGetDeviceCaps.Call( - uintptr(fnObject)) - - return HGDIOBJ(ret) -} - -func GetTextExtentExPoint(hdc HDC, lpszStr *uint16, cchString, nMaxExtent int, lpnFit, alpDx *int, lpSize *SIZE) bool { - ret, _, _ := procGetTextExtentExPoint.Call( - uintptr(hdc), - uintptr(unsafe.Pointer(lpszStr)), - uintptr(cchString), - uintptr(nMaxExtent), - uintptr(unsafe.Pointer(lpnFit)), - uintptr(unsafe.Pointer(alpDx)), - uintptr(unsafe.Pointer(lpSize))) - - return ret != 0 -} - -func GetTextExtentPoint32(hdc HDC, lpString *uint16, c int, lpSize *SIZE) bool { - ret, _, _ := procGetTextExtentPoint32.Call( - uintptr(hdc), - uintptr(unsafe.Pointer(lpString)), - uintptr(c), - uintptr(unsafe.Pointer(lpSize))) - - return ret != 0 -} - -func GetTextMetrics(hdc HDC, lptm *TEXTMETRIC) bool { - ret, _, _ := procGetTextMetrics.Call( - uintptr(hdc), - uintptr(unsafe.Pointer(lptm))) - - return ret != 0 -} - -func LineTo(hdc HDC, nXEnd, nYEnd int32) bool { - ret, _, _ := procLineTo.Call( - uintptr(hdc), - uintptr(nXEnd), - uintptr(nYEnd)) - - return ret != 0 -} - -func MoveToEx(hdc HDC, x, y int, lpPoint *POINT) bool { - ret, _, _ := procMoveToEx.Call( - uintptr(hdc), - uintptr(x), - uintptr(y), - uintptr(unsafe.Pointer(lpPoint))) - - return ret != 0 -} - -func PlayEnhMetaFile(hdc HDC, hemf HENHMETAFILE, lpRect *RECT) bool { - ret, _, _ := procPlayEnhMetaFile.Call( - uintptr(hdc), - uintptr(hemf), - uintptr(unsafe.Pointer(lpRect))) - - return ret != 0 -} - -func Rectangle(hdc HDC, nLeftRect, nTopRect, nRightRect, nBottomRect int32) bool { - ret, _, _ := procRectangle.Call( - uintptr(hdc), - uintptr(nLeftRect), - uintptr(nTopRect), - uintptr(nRightRect), - uintptr(nBottomRect)) - - return ret != 0 -} - -func ResetDC(hdc HDC, lpInitData *DEVMODE) HDC { - ret, _, _ := procResetDC.Call( - uintptr(hdc), - uintptr(unsafe.Pointer(lpInitData))) - - return HDC(ret) -} - -func SelectObject(hdc HDC, hgdiobj HGDIOBJ) HGDIOBJ { - ret, _, _ := procSelectObject.Call( - uintptr(hdc), - uintptr(hgdiobj)) - - if ret == 0 { - panic("SelectObject failed") - } - - return HGDIOBJ(ret) -} - -func SetBkMode(hdc HDC, iBkMode int) int { - ret, _, _ := procSetBkMode.Call( - uintptr(hdc), - uintptr(iBkMode)) - - if ret == 0 { - panic("SetBkMode failed") - } - - return int(ret) -} - -func SetBrushOrgEx(hdc HDC, nXOrg, nYOrg int, lppt *POINT) bool { - ret, _, _ := procSetBrushOrgEx.Call( - uintptr(hdc), - uintptr(nXOrg), - uintptr(nYOrg), - uintptr(unsafe.Pointer(lppt))) - - return ret != 0 -} - -func SetStretchBltMode(hdc HDC, iStretchMode int) int { - ret, _, _ := procSetStretchBltMode.Call( - uintptr(hdc), - uintptr(iStretchMode)) - - return int(ret) -} - -func SetTextColor(hdc HDC, crColor COLORREF) COLORREF { - ret, _, _ := procSetTextColor.Call( - uintptr(hdc), - uintptr(crColor)) - - if ret == CLR_INVALID { - panic("SetTextColor failed") - } - - return COLORREF(ret) -} - -func SetBkColor(hdc HDC, crColor COLORREF) COLORREF { - ret, _, _ := procSetBkColor.Call( - uintptr(hdc), - uintptr(crColor)) - - if ret == CLR_INVALID { - panic("SetBkColor failed") - } - - return COLORREF(ret) -} - -func StartDoc(hdc HDC, lpdi *DOCINFO) int { - ret, _, _ := procStartDoc.Call( - uintptr(hdc), - uintptr(unsafe.Pointer(lpdi))) - - return int(ret) -} - -func StartPage(hdc HDC) int { - ret, _, _ := procStartPage.Call( - uintptr(hdc)) - - return int(ret) -} - -func StretchBlt(hdcDest HDC, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest int, hdcSrc HDC, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc int, dwRop uint) { - ret, _, _ := procStretchBlt.Call( - uintptr(hdcDest), - uintptr(nXOriginDest), - uintptr(nYOriginDest), - uintptr(nWidthDest), - uintptr(nHeightDest), - uintptr(hdcSrc), - uintptr(nXOriginSrc), - uintptr(nYOriginSrc), - uintptr(nWidthSrc), - uintptr(nHeightSrc), - uintptr(dwRop)) - - if ret == 0 { - panic("StretchBlt failed") - } -} - -func SetDIBitsToDevice(hdc HDC, xDest, yDest, dwWidth, dwHeight, xSrc, ySrc int, uStartScan, cScanLines uint, lpvBits []byte, lpbmi *BITMAPINFO, fuColorUse uint) int { - ret, _, _ := procSetDIBitsToDevice.Call( - uintptr(hdc), - uintptr(xDest), - uintptr(yDest), - uintptr(dwWidth), - uintptr(dwHeight), - uintptr(xSrc), - uintptr(ySrc), - uintptr(uStartScan), - uintptr(cScanLines), - uintptr(unsafe.Pointer(&lpvBits[0])), - uintptr(unsafe.Pointer(lpbmi)), - uintptr(fuColorUse)) - - return int(ret) -} - -func ChoosePixelFormat(hdc HDC, pfd *PIXELFORMATDESCRIPTOR) int { - ret, _, _ := procChoosePixelFormat.Call( - uintptr(hdc), - uintptr(unsafe.Pointer(pfd)), - ) - return int(ret) -} - -func DescribePixelFormat(hdc HDC, iPixelFormat int, nBytes uint, pfd *PIXELFORMATDESCRIPTOR) int { - ret, _, _ := procDescribePixelFormat.Call( - uintptr(hdc), - uintptr(iPixelFormat), - uintptr(nBytes), - uintptr(unsafe.Pointer(pfd)), - ) - return int(ret) -} - -func GetEnhMetaFilePixelFormat(hemf HENHMETAFILE, cbBuffer uint32, pfd *PIXELFORMATDESCRIPTOR) uint { - ret, _, _ := procGetEnhMetaFilePixelFormat.Call( - uintptr(hemf), - uintptr(cbBuffer), - uintptr(unsafe.Pointer(pfd)), - ) - return uint(ret) -} - -func GetPixelFormat(hdc HDC) int { - ret, _, _ := procGetPixelFormat.Call( - uintptr(hdc), - ) - return int(ret) -} - -func SetPixelFormat(hdc HDC, iPixelFormat int, pfd *PIXELFORMATDESCRIPTOR) bool { - ret, _, _ := procSetPixelFormat.Call( - uintptr(hdc), - uintptr(iPixelFormat), - uintptr(unsafe.Pointer(pfd)), - ) - return ret == TRUE -} - -func SwapBuffers(hdc HDC) bool { - ret, _, _ := procSwapBuffers.Call(uintptr(hdc)) - return ret == TRUE -} diff --git a/v2/internal/frontend/desktop/windows/winc/w32/gdiplus.go b/v2/internal/frontend/desktop/windows/winc/w32/gdiplus.go deleted file mode 100644 index 2591ed71b..000000000 --- a/v2/internal/frontend/desktop/windows/winc/w32/gdiplus.go +++ /dev/null @@ -1,177 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved. - */ -package w32 - -import ( - "errors" - "fmt" - "syscall" - "unsafe" -) - -const ( - Ok = 0 - GenericError = 1 - InvalidParameter = 2 - OutOfMemory = 3 - ObjectBusy = 4 - InsufficientBuffer = 5 - NotImplemented = 6 - Win32Error = 7 - WrongState = 8 - Aborted = 9 - FileNotFound = 10 - ValueOverflow = 11 - AccessDenied = 12 - UnknownImageFormat = 13 - FontFamilyNotFound = 14 - FontStyleNotFound = 15 - NotTrueTypeFont = 16 - UnsupportedGdiplusVersion = 17 - GdiplusNotInitialized = 18 - PropertyNotFound = 19 - PropertyNotSupported = 20 - ProfileNotFound = 21 -) - -func GetGpStatus(s int32) string { - switch s { - case Ok: - return "Ok" - case GenericError: - return "GenericError" - case InvalidParameter: - return "InvalidParameter" - case OutOfMemory: - return "OutOfMemory" - case ObjectBusy: - return "ObjectBusy" - case InsufficientBuffer: - return "InsufficientBuffer" - case NotImplemented: - return "NotImplemented" - case Win32Error: - return "Win32Error" - case WrongState: - return "WrongState" - case Aborted: - return "Aborted" - case FileNotFound: - return "FileNotFound" - case ValueOverflow: - return "ValueOverflow" - case AccessDenied: - return "AccessDenied" - case UnknownImageFormat: - return "UnknownImageFormat" - case FontFamilyNotFound: - return "FontFamilyNotFound" - case FontStyleNotFound: - return "FontStyleNotFound" - case NotTrueTypeFont: - return "NotTrueTypeFont" - case UnsupportedGdiplusVersion: - return "UnsupportedGdiplusVersion" - case GdiplusNotInitialized: - return "GdiplusNotInitialized" - case PropertyNotFound: - return "PropertyNotFound" - case PropertyNotSupported: - return "PropertyNotSupported" - case ProfileNotFound: - return "ProfileNotFound" - } - return "Unknown Status Value" -} - -var ( - token uintptr - - modgdiplus = syscall.NewLazyDLL("gdiplus.dll") - - procGdipCreateBitmapFromFile = modgdiplus.NewProc("GdipCreateBitmapFromFile") - procGdipCreateBitmapFromHBITMAP = modgdiplus.NewProc("GdipCreateBitmapFromHBITMAP") - procGdipCreateHBITMAPFromBitmap = modgdiplus.NewProc("GdipCreateHBITMAPFromBitmap") - procGdipCreateBitmapFromResource = modgdiplus.NewProc("GdipCreateBitmapFromResource") - procGdipCreateBitmapFromStream = modgdiplus.NewProc("GdipCreateBitmapFromStream") - procGdipDisposeImage = modgdiplus.NewProc("GdipDisposeImage") - procGdiplusShutdown = modgdiplus.NewProc("GdiplusShutdown") - procGdiplusStartup = modgdiplus.NewProc("GdiplusStartup") -) - -func GdipCreateBitmapFromFile(filename string) (*uintptr, error) { - var bitmap *uintptr - ret, _, _ := procGdipCreateBitmapFromFile.Call( - uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(filename))), - uintptr(unsafe.Pointer(&bitmap))) - - if ret != Ok { - return nil, errors.New(fmt.Sprintf("GdipCreateBitmapFromFile failed with status '%s' for file '%s'", GetGpStatus(int32(ret)), filename)) - } - - return bitmap, nil -} - -func GdipCreateBitmapFromResource(instance HINSTANCE, resId *uint16) (*uintptr, error) { - var bitmap *uintptr - ret, _, _ := procGdipCreateBitmapFromResource.Call( - uintptr(instance), - uintptr(unsafe.Pointer(resId)), - uintptr(unsafe.Pointer(&bitmap))) - - if ret != Ok { - return nil, errors.New(fmt.Sprintf("GdiCreateBitmapFromResource failed with status '%s'", GetGpStatus(int32(ret)))) - } - - return bitmap, nil -} - -func GdipCreateBitmapFromStream(stream *IStream) (*uintptr, error) { - var bitmap *uintptr - ret, _, _ := procGdipCreateBitmapFromStream.Call( - uintptr(unsafe.Pointer(stream)), - uintptr(unsafe.Pointer(&bitmap))) - - if ret != Ok { - return nil, errors.New(fmt.Sprintf("GdipCreateBitmapFromStream failed with status '%s'", GetGpStatus(int32(ret)))) - } - - return bitmap, nil -} - -func GdipCreateHBITMAPFromBitmap(bitmap *uintptr, background uint32) (HBITMAP, error) { - var hbitmap HBITMAP - ret, _, _ := procGdipCreateHBITMAPFromBitmap.Call( - uintptr(unsafe.Pointer(bitmap)), - uintptr(unsafe.Pointer(&hbitmap)), - uintptr(background)) - - if ret != Ok { - return 0, errors.New(fmt.Sprintf("GdipCreateHBITMAPFromBitmap failed with status '%s'", GetGpStatus(int32(ret)))) - } - - return hbitmap, nil -} - -func GdipDisposeImage(image *uintptr) { - procGdipDisposeImage.Call(uintptr(unsafe.Pointer(image))) -} - -func GdiplusShutdown() { - procGdiplusShutdown.Call(token) -} - -func GdiplusStartup(input *GdiplusStartupInput, output *GdiplusStartupOutput) { - ret, _, _ := procGdiplusStartup.Call( - uintptr(unsafe.Pointer(&token)), - uintptr(unsafe.Pointer(input)), - uintptr(unsafe.Pointer(output))) - - if ret != Ok { - panic("GdiplusStartup failed with status " + GetGpStatus(int32(ret))) - } -} diff --git a/v2/internal/frontend/desktop/windows/winc/w32/idispatch.go b/v2/internal/frontend/desktop/windows/winc/w32/idispatch.go deleted file mode 100644 index 4f610f3ff..000000000 --- a/v2/internal/frontend/desktop/windows/winc/w32/idispatch.go +++ /dev/null @@ -1,45 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved. - */ -package w32 - -import ( - "unsafe" -) - -type pIDispatchVtbl struct { - pQueryInterface uintptr - pAddRef uintptr - pRelease uintptr - pGetTypeInfoCount uintptr - pGetTypeInfo uintptr - pGetIDsOfNames uintptr - pInvoke uintptr -} - -type IDispatch struct { - lpVtbl *pIDispatchVtbl -} - -func (this *IDispatch) QueryInterface(id *GUID) *IDispatch { - return ComQueryInterface((*IUnknown)(unsafe.Pointer(this)), id) -} - -func (this *IDispatch) AddRef() int32 { - return ComAddRef((*IUnknown)(unsafe.Pointer(this))) -} - -func (this *IDispatch) Release() int32 { - return ComRelease((*IUnknown)(unsafe.Pointer(this))) -} - -func (this *IDispatch) GetIDsOfName(names []string) []int32 { - return ComGetIDsOfName(this, names) -} - -func (this *IDispatch) Invoke(dispid int32, dispatch int16, params ...interface{}) *VARIANT { - return ComInvoke(this, dispid, dispatch, params...) -} diff --git a/v2/internal/frontend/desktop/windows/winc/w32/istream.go b/v2/internal/frontend/desktop/windows/winc/w32/istream.go deleted file mode 100644 index a47fbbce1..000000000 --- a/v2/internal/frontend/desktop/windows/winc/w32/istream.go +++ /dev/null @@ -1,33 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved. - * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved. - */ -package w32 - -import ( - "unsafe" -) - -type pIStreamVtbl struct { - pQueryInterface uintptr - pAddRef uintptr - pRelease uintptr -} - -type IStream struct { - lpVtbl *pIStreamVtbl -} - -func (this *IStream) QueryInterface(id *GUID) *IDispatch { - return ComQueryInterface((*IUnknown)(unsafe.Pointer(this)), id) -} - -func (this *IStream) AddRef() int32 { - return ComAddRef((*IUnknown)(unsafe.Pointer(this))) -} - -func (this *IStream) Release() int32 { - return ComRelease((*IUnknown)(unsafe.Pointer(this))) -} diff --git a/v2/internal/frontend/desktop/windows/winc/w32/iunknown.go b/v2/internal/frontend/desktop/windows/winc/w32/iunknown.go deleted file mode 100644 index 8ddc605cc..000000000 --- a/v2/internal/frontend/desktop/windows/winc/w32/iunknown.go +++ /dev/null @@ -1,29 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved. - * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved. - */ -package w32 - -type pIUnknownVtbl struct { - pQueryInterface uintptr - pAddRef uintptr - pRelease uintptr -} - -type IUnknown struct { - lpVtbl *pIUnknownVtbl -} - -func (this *IUnknown) QueryInterface(id *GUID) *IDispatch { - return ComQueryInterface(this, id) -} - -func (this *IUnknown) AddRef() int32 { - return ComAddRef(this) -} - -func (this *IUnknown) Release() int32 { - return ComRelease(this) -} diff --git a/v2/internal/frontend/desktop/windows/winc/w32/kernel32.go b/v2/internal/frontend/desktop/windows/winc/w32/kernel32.go deleted file mode 100644 index 063a1b0ea..000000000 --- a/v2/internal/frontend/desktop/windows/winc/w32/kernel32.go +++ /dev/null @@ -1,332 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved. - * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved. - */ -package w32 - -import ( - "syscall" - "unsafe" -) - -var ( - modkernel32 = syscall.NewLazyDLL("kernel32.dll") - - procGetModuleHandle = modkernel32.NewProc("GetModuleHandleW") - procMulDiv = modkernel32.NewProc("MulDiv") - procGetConsoleWindow = modkernel32.NewProc("GetConsoleWindow") - procGetCurrentThread = modkernel32.NewProc("GetCurrentThread") - procGetCurrentThreadId = modkernel32.NewProc("GetCurrentThreadId") - procGetLogicalDrives = modkernel32.NewProc("GetLogicalDrives") - procGetLogicalDriveStrings = modkernel32.NewProc("GetLogicalDriveStringsW") - procGetUserDefaultLCID = modkernel32.NewProc("GetUserDefaultLCID") - procLstrlen = modkernel32.NewProc("lstrlenW") - procLstrcpy = modkernel32.NewProc("lstrcpyW") - procGlobalAlloc = modkernel32.NewProc("GlobalAlloc") - procGlobalFree = modkernel32.NewProc("GlobalFree") - procGlobalLock = modkernel32.NewProc("GlobalLock") - procGlobalUnlock = modkernel32.NewProc("GlobalUnlock") - procMoveMemory = modkernel32.NewProc("RtlMoveMemory") - procFindResource = modkernel32.NewProc("FindResourceW") - procSizeofResource = modkernel32.NewProc("SizeofResource") - procLockResource = modkernel32.NewProc("LockResource") - procLoadResource = modkernel32.NewProc("LoadResource") - procGetLastError = modkernel32.NewProc("GetLastError") - procOpenProcess = modkernel32.NewProc("OpenProcess") - procTerminateProcess = modkernel32.NewProc("TerminateProcess") - procCloseHandle = modkernel32.NewProc("CloseHandle") - procCreateToolhelp32Snapshot = modkernel32.NewProc("CreateToolhelp32Snapshot") - procModule32First = modkernel32.NewProc("Module32FirstW") - procModule32Next = modkernel32.NewProc("Module32NextW") - procGetSystemTimes = modkernel32.NewProc("GetSystemTimes") - procGetConsoleScreenBufferInfo = modkernel32.NewProc("GetConsoleScreenBufferInfo") - procSetConsoleTextAttribute = modkernel32.NewProc("SetConsoleTextAttribute") - procGetDiskFreeSpaceEx = modkernel32.NewProc("GetDiskFreeSpaceExW") - procGetProcessTimes = modkernel32.NewProc("GetProcessTimes") - procSetSystemTime = modkernel32.NewProc("SetSystemTime") - procGetSystemTime = modkernel32.NewProc("GetSystemTime") -) - -func GetModuleHandle(modulename string) HINSTANCE { - var mn uintptr - if modulename == "" { - mn = 0 - } else { - mn = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(modulename))) - } - ret, _, _ := procGetModuleHandle.Call(mn) - return HINSTANCE(ret) -} - -func MulDiv(number, numerator, denominator int) int { - ret, _, _ := procMulDiv.Call( - uintptr(number), - uintptr(numerator), - uintptr(denominator)) - - return int(ret) -} - -func GetConsoleWindow() HWND { - ret, _, _ := procGetConsoleWindow.Call() - - return HWND(ret) -} - -func GetCurrentThread() HANDLE { - ret, _, _ := procGetCurrentThread.Call() - - return HANDLE(ret) -} - -func GetCurrentThreadId() HANDLE { - ret, _, _ := procGetCurrentThreadId.Call() - - return HANDLE(ret) -} - -func GetLogicalDrives() uint32 { - ret, _, _ := procGetLogicalDrives.Call() - - return uint32(ret) -} - -func GetUserDefaultLCID() uint32 { - ret, _, _ := procGetUserDefaultLCID.Call() - - return uint32(ret) -} - -func Lstrlen(lpString *uint16) int { - ret, _, _ := procLstrlen.Call(uintptr(unsafe.Pointer(lpString))) - - return int(ret) -} - -func Lstrcpy(buf []uint16, lpString *uint16) { - procLstrcpy.Call( - uintptr(unsafe.Pointer(&buf[0])), - uintptr(unsafe.Pointer(lpString))) -} - -func GlobalAlloc(uFlags uint, dwBytes uint32) HGLOBAL { - ret, _, _ := procGlobalAlloc.Call( - uintptr(uFlags), - uintptr(dwBytes)) - - if ret == 0 { - panic("GlobalAlloc failed") - } - - return HGLOBAL(ret) -} - -func GlobalFree(hMem HGLOBAL) { - ret, _, _ := procGlobalFree.Call(uintptr(hMem)) - - if ret != 0 { - panic("GlobalFree failed") - } -} - -func GlobalLock(hMem HGLOBAL) unsafe.Pointer { - ret, _, _ := procGlobalLock.Call(uintptr(hMem)) - - if ret == 0 { - panic("GlobalLock failed") - } - - return unsafe.Pointer(ret) -} - -func GlobalUnlock(hMem HGLOBAL) bool { - ret, _, _ := procGlobalUnlock.Call(uintptr(hMem)) - - return ret != 0 -} - -func MoveMemory(destination, source unsafe.Pointer, length uint32) { - procMoveMemory.Call( - uintptr(unsafe.Pointer(destination)), - uintptr(source), - uintptr(length)) -} - -func FindResource(hModule HMODULE, lpName, lpType *uint16) (HRSRC, error) { - ret, _, _ := procFindResource.Call( - uintptr(hModule), - uintptr(unsafe.Pointer(lpName)), - uintptr(unsafe.Pointer(lpType))) - - if ret == 0 { - return 0, syscall.GetLastError() - } - - return HRSRC(ret), nil -} - -func SizeofResource(hModule HMODULE, hResInfo HRSRC) uint32 { - ret, _, _ := procSizeofResource.Call( - uintptr(hModule), - uintptr(hResInfo)) - - if ret == 0 { - panic("SizeofResource failed") - } - - return uint32(ret) -} - -func LockResource(hResData HGLOBAL) unsafe.Pointer { - ret, _, _ := procLockResource.Call(uintptr(hResData)) - - if ret == 0 { - panic("LockResource failed") - } - - return unsafe.Pointer(ret) -} - -func LoadResource(hModule HMODULE, hResInfo HRSRC) HGLOBAL { - ret, _, _ := procLoadResource.Call( - uintptr(hModule), - uintptr(hResInfo)) - - if ret == 0 { - panic("LoadResource failed") - } - - return HGLOBAL(ret) -} - -func GetLastError() uint32 { - ret, _, _ := procGetLastError.Call() - return uint32(ret) -} - -func OpenProcess(desiredAccess uint32, inheritHandle bool, processId uint32) HANDLE { - inherit := 0 - if inheritHandle { - inherit = 1 - } - - ret, _, _ := procOpenProcess.Call( - uintptr(desiredAccess), - uintptr(inherit), - uintptr(processId)) - return HANDLE(ret) -} - -func TerminateProcess(hProcess HANDLE, uExitCode uint) bool { - ret, _, _ := procTerminateProcess.Call( - uintptr(hProcess), - uintptr(uExitCode)) - return ret != 0 -} - -func CloseHandle(object HANDLE) bool { - ret, _, _ := procCloseHandle.Call( - uintptr(object)) - return ret != 0 -} - -func CreateToolhelp32Snapshot(flags, processId uint32) HANDLE { - ret, _, _ := procCreateToolhelp32Snapshot.Call( - uintptr(flags), - uintptr(processId)) - - if ret <= 0 { - return HANDLE(0) - } - - return HANDLE(ret) -} - -func Module32First(snapshot HANDLE, me *MODULEENTRY32) bool { - ret, _, _ := procModule32First.Call( - uintptr(snapshot), - uintptr(unsafe.Pointer(me))) - - return ret != 0 -} - -func Module32Next(snapshot HANDLE, me *MODULEENTRY32) bool { - ret, _, _ := procModule32Next.Call( - uintptr(snapshot), - uintptr(unsafe.Pointer(me))) - - return ret != 0 -} - -func GetSystemTimes(lpIdleTime, lpKernelTime, lpUserTime *FILETIME) bool { - ret, _, _ := procGetSystemTimes.Call( - uintptr(unsafe.Pointer(lpIdleTime)), - uintptr(unsafe.Pointer(lpKernelTime)), - uintptr(unsafe.Pointer(lpUserTime))) - - return ret != 0 -} - -func GetProcessTimes(hProcess HANDLE, lpCreationTime, lpExitTime, lpKernelTime, lpUserTime *FILETIME) bool { - ret, _, _ := procGetProcessTimes.Call( - uintptr(hProcess), - uintptr(unsafe.Pointer(lpCreationTime)), - uintptr(unsafe.Pointer(lpExitTime)), - uintptr(unsafe.Pointer(lpKernelTime)), - uintptr(unsafe.Pointer(lpUserTime))) - - return ret != 0 -} - -func GetConsoleScreenBufferInfo(hConsoleOutput HANDLE) *CONSOLE_SCREEN_BUFFER_INFO { - var csbi CONSOLE_SCREEN_BUFFER_INFO - ret, _, _ := procGetConsoleScreenBufferInfo.Call( - uintptr(hConsoleOutput), - uintptr(unsafe.Pointer(&csbi))) - if ret == 0 { - return nil - } - return &csbi -} - -func SetConsoleTextAttribute(hConsoleOutput HANDLE, wAttributes uint16) bool { - ret, _, _ := procSetConsoleTextAttribute.Call( - uintptr(hConsoleOutput), - uintptr(wAttributes)) - return ret != 0 -} - -func GetDiskFreeSpaceEx(dirName string) (r bool, - freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes uint64) { - ret, _, _ := procGetDiskFreeSpaceEx.Call( - uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(dirName))), - uintptr(unsafe.Pointer(&freeBytesAvailable)), - uintptr(unsafe.Pointer(&totalNumberOfBytes)), - uintptr(unsafe.Pointer(&totalNumberOfFreeBytes))) - return ret != 0, - freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes -} - -func GetSystemTime() *SYSTEMTIME { - var time SYSTEMTIME - procGetSystemTime.Call( - uintptr(unsafe.Pointer(&time))) - return &time -} - -func SetSystemTime(time *SYSTEMTIME) bool { - ret, _, _ := procSetSystemTime.Call( - uintptr(unsafe.Pointer(time))) - return ret != 0 -} - -func GetLogicalDriveStrings(nBufferLength uint32, lpBuffer *uint16) uint32 { - ret, _, _ := procGetLogicalDriveStrings.Call( - uintptr(nBufferLength), - uintptr(unsafe.Pointer(lpBuffer)), - 0) - - return uint32(ret) -} diff --git a/v2/internal/frontend/desktop/windows/winc/w32/ole32.go b/v2/internal/frontend/desktop/windows/winc/w32/ole32.go deleted file mode 100644 index 004099316..000000000 --- a/v2/internal/frontend/desktop/windows/winc/w32/ole32.go +++ /dev/null @@ -1,65 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved. - * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved. - */ -package w32 - -import ( - "syscall" - "unsafe" -) - -var ( - modole32 = syscall.NewLazyDLL("ole32.dll") - - procCoInitializeEx = modole32.NewProc("CoInitializeEx") - procCoInitialize = modole32.NewProc("CoInitialize") - procCoUninitialize = modole32.NewProc("CoUninitialize") - procCreateStreamOnHGlobal = modole32.NewProc("CreateStreamOnHGlobal") -) - -func CoInitializeEx(coInit uintptr) HRESULT { - ret, _, _ := procCoInitializeEx.Call( - 0, - coInit) - - switch uint32(ret) { - case E_INVALIDARG: - panic("CoInitializeEx failed with E_INVALIDARG") - case E_OUTOFMEMORY: - panic("CoInitializeEx failed with E_OUTOFMEMORY") - case E_UNEXPECTED: - panic("CoInitializeEx failed with E_UNEXPECTED") - } - - return HRESULT(ret) -} - -func CoInitialize() { - procCoInitialize.Call(0) -} - -func CoUninitialize() { - procCoUninitialize.Call() -} - -func CreateStreamOnHGlobal(hGlobal HGLOBAL, fDeleteOnRelease bool) *IStream { - stream := new(IStream) - ret, _, _ := procCreateStreamOnHGlobal.Call( - uintptr(hGlobal), - uintptr(BoolToBOOL(fDeleteOnRelease)), - uintptr(unsafe.Pointer(&stream))) - - switch uint32(ret) { - case E_INVALIDARG: - panic("CreateStreamOnHGlobal failed with E_INVALIDARG") - case E_OUTOFMEMORY: - panic("CreateStreamOnHGlobal failed with E_OUTOFMEMORY") - case E_UNEXPECTED: - panic("CreateStreamOnHGlobal failed with E_UNEXPECTED") - } - - return stream -} diff --git a/v2/internal/frontend/desktop/windows/winc/w32/oleaut32.go b/v2/internal/frontend/desktop/windows/winc/w32/oleaut32.go deleted file mode 100644 index 0bb8ef7da..000000000 --- a/v2/internal/frontend/desktop/windows/winc/w32/oleaut32.go +++ /dev/null @@ -1,50 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved. - * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved. - */ -package w32 - -import ( - "syscall" - "unsafe" -) - -var ( - modoleaut32 = syscall.NewLazyDLL("oleaut32") - - procVariantInit = modoleaut32.NewProc("VariantInit") - procSysAllocString = modoleaut32.NewProc("SysAllocString") - procSysFreeString = modoleaut32.NewProc("SysFreeString") - procSysStringLen = modoleaut32.NewProc("SysStringLen") - procCreateDispTypeInfo = modoleaut32.NewProc("CreateDispTypeInfo") - procCreateStdDispatch = modoleaut32.NewProc("CreateStdDispatch") -) - -func VariantInit(v *VARIANT) { - hr, _, _ := procVariantInit.Call(uintptr(unsafe.Pointer(v))) - if hr != 0 { - panic("Invoke VariantInit error.") - } - return -} - -func SysAllocString(v string) (ss *int16) { - pss, _, _ := procSysAllocString.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(v)))) - ss = (*int16)(unsafe.Pointer(pss)) - return -} - -func SysFreeString(v *int16) { - hr, _, _ := procSysFreeString.Call(uintptr(unsafe.Pointer(v))) - if hr != 0 { - panic("Invoke SysFreeString error.") - } - return -} - -func SysStringLen(v *int16) uint { - l, _, _ := procSysStringLen.Call(uintptr(unsafe.Pointer(v))) - return uint(l) -} diff --git a/v2/internal/frontend/desktop/windows/winc/w32/shcore.go b/v2/internal/frontend/desktop/windows/winc/w32/shcore.go deleted file mode 100644 index 72e9aab3d..000000000 --- a/v2/internal/frontend/desktop/windows/winc/w32/shcore.go +++ /dev/null @@ -1,29 +0,0 @@ -//go:build windows - -package w32 - -import ( - "syscall" - "unsafe" -) - -var ( - modshcore = syscall.NewLazyDLL("shcore.dll") - - procGetDpiForMonitor = modshcore.NewProc("GetDpiForMonitor") -) - -func HasGetDPIForMonitorFunc() bool { - err := procGetDpiForMonitor.Find() - return err == nil -} - -func GetDPIForMonitor(hmonitor HMONITOR, dpiType MONITOR_DPI_TYPE, dpiX *UINT, dpiY *UINT) uintptr { - ret, _, _ := procGetDpiForMonitor.Call( - hmonitor, - uintptr(dpiType), - uintptr(unsafe.Pointer(dpiX)), - uintptr(unsafe.Pointer(dpiY))) - - return ret -} diff --git a/v2/internal/frontend/desktop/windows/winc/w32/shell32.go b/v2/internal/frontend/desktop/windows/winc/w32/shell32.go deleted file mode 100644 index 458fbc645..000000000 --- a/v2/internal/frontend/desktop/windows/winc/w32/shell32.go +++ /dev/null @@ -1,235 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved. - * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved. - */ -package w32 - -import ( - "errors" - "fmt" - "syscall" - "unsafe" -) - -type CSIDL uint32 - -const ( - CSIDL_DESKTOP = 0x00 - CSIDL_INTERNET = 0x01 - CSIDL_PROGRAMS = 0x02 - CSIDL_CONTROLS = 0x03 - CSIDL_PRINTERS = 0x04 - CSIDL_PERSONAL = 0x05 - CSIDL_FAVORITES = 0x06 - CSIDL_STARTUP = 0x07 - CSIDL_RECENT = 0x08 - CSIDL_SENDTO = 0x09 - CSIDL_BITBUCKET = 0x0A - CSIDL_STARTMENU = 0x0B - CSIDL_MYDOCUMENTS = 0x0C - CSIDL_MYMUSIC = 0x0D - CSIDL_MYVIDEO = 0x0E - CSIDL_DESKTOPDIRECTORY = 0x10 - CSIDL_DRIVES = 0x11 - CSIDL_NETWORK = 0x12 - CSIDL_NETHOOD = 0x13 - CSIDL_FONTS = 0x14 - CSIDL_TEMPLATES = 0x15 - CSIDL_COMMON_STARTMENU = 0x16 - CSIDL_COMMON_PROGRAMS = 0x17 - CSIDL_COMMON_STARTUP = 0x18 - CSIDL_COMMON_DESKTOPDIRECTORY = 0x19 - CSIDL_APPDATA = 0x1A - CSIDL_PRINTHOOD = 0x1B - CSIDL_LOCAL_APPDATA = 0x1C - CSIDL_ALTSTARTUP = 0x1D - CSIDL_COMMON_ALTSTARTUP = 0x1E - CSIDL_COMMON_FAVORITES = 0x1F - CSIDL_INTERNET_CACHE = 0x20 - CSIDL_COOKIES = 0x21 - CSIDL_HISTORY = 0x22 - CSIDL_COMMON_APPDATA = 0x23 - CSIDL_WINDOWS = 0x24 - CSIDL_SYSTEM = 0x25 - CSIDL_PROGRAM_FILES = 0x26 - CSIDL_MYPICTURES = 0x27 - CSIDL_PROFILE = 0x28 - CSIDL_SYSTEMX86 = 0x29 - CSIDL_PROGRAM_FILESX86 = 0x2A - CSIDL_PROGRAM_FILES_COMMON = 0x2B - CSIDL_PROGRAM_FILES_COMMONX86 = 0x2C - CSIDL_COMMON_TEMPLATES = 0x2D - CSIDL_COMMON_DOCUMENTS = 0x2E - CSIDL_COMMON_ADMINTOOLS = 0x2F - CSIDL_ADMINTOOLS = 0x30 - CSIDL_CONNECTIONS = 0x31 - CSIDL_COMMON_MUSIC = 0x35 - CSIDL_COMMON_PICTURES = 0x36 - CSIDL_COMMON_VIDEO = 0x37 - CSIDL_RESOURCES = 0x38 - CSIDL_RESOURCES_LOCALIZED = 0x39 - CSIDL_COMMON_OEM_LINKS = 0x3A - CSIDL_CDBURN_AREA = 0x3B - CSIDL_COMPUTERSNEARME = 0x3D - CSIDL_FLAG_CREATE = 0x8000 - CSIDL_FLAG_DONT_VERIFY = 0x4000 - CSIDL_FLAG_NO_ALIAS = 0x1000 - CSIDL_FLAG_PER_USER_INIT = 0x8000 - CSIDL_FLAG_MASK = 0xFF00 -) - -var ( - modshell32 = syscall.NewLazyDLL("shell32.dll") - - procSHBrowseForFolder = modshell32.NewProc("SHBrowseForFolderW") - procSHGetPathFromIDList = modshell32.NewProc("SHGetPathFromIDListW") - procDragAcceptFiles = modshell32.NewProc("DragAcceptFiles") - procDragQueryFile = modshell32.NewProc("DragQueryFileW") - procDragQueryPoint = modshell32.NewProc("DragQueryPoint") - procDragFinish = modshell32.NewProc("DragFinish") - procShellExecute = modshell32.NewProc("ShellExecuteW") - procExtractIcon = modshell32.NewProc("ExtractIconW") - procGetSpecialFolderPath = modshell32.NewProc("SHGetSpecialFolderPathW") -) - -func SHBrowseForFolder(bi *BROWSEINFO) uintptr { - ret, _, _ := procSHBrowseForFolder.Call(uintptr(unsafe.Pointer(bi))) - - return ret -} - -func SHGetPathFromIDList(idl uintptr) string { - buf := make([]uint16, 1024) - procSHGetPathFromIDList.Call( - idl, - uintptr(unsafe.Pointer(&buf[0]))) - - return syscall.UTF16ToString(buf) -} - -func DragAcceptFiles(hwnd HWND, accept bool) { - procDragAcceptFiles.Call( - uintptr(hwnd), - uintptr(BoolToBOOL(accept))) -} - -func DragQueryFile(hDrop HDROP, iFile uint) (fileName string, fileCount uint) { - ret, _, _ := procDragQueryFile.Call( - uintptr(hDrop), - uintptr(iFile), - 0, - 0) - - fileCount = uint(ret) - - if iFile != 0xFFFFFFFF { - buf := make([]uint16, fileCount+1) - - ret, _, _ := procDragQueryFile.Call( - uintptr(hDrop), - uintptr(iFile), - uintptr(unsafe.Pointer(&buf[0])), - uintptr(fileCount+1)) - - if ret == 0 { - panic("Invoke DragQueryFile error.") - } - - fileName = syscall.UTF16ToString(buf) - } - - return -} - -func DragQueryPoint(hDrop HDROP) (x, y int, isClientArea bool) { - var pt POINT - ret, _, _ := procDragQueryPoint.Call( - uintptr(hDrop), - uintptr(unsafe.Pointer(&pt))) - - return int(pt.X), int(pt.Y), (ret == 1) -} - -func DragFinish(hDrop HDROP) { - procDragFinish.Call(uintptr(hDrop)) -} - -func ShellExecute(hwnd HWND, lpOperation, lpFile, lpParameters, lpDirectory string, nShowCmd int) error { - var op, param, directory uintptr - if len(lpOperation) != 0 { - op = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpOperation))) - } - if len(lpParameters) != 0 { - param = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpParameters))) - } - if len(lpDirectory) != 0 { - directory = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpDirectory))) - } - - ret, _, _ := procShellExecute.Call( - uintptr(hwnd), - op, - uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpFile))), - param, - directory, - uintptr(nShowCmd)) - - errorMsg := "" - if ret != 0 && ret <= 32 { - switch int(ret) { - case ERROR_FILE_NOT_FOUND: - errorMsg = "The specified file was not found." - case ERROR_PATH_NOT_FOUND: - errorMsg = "The specified path was not found." - case ERROR_BAD_FORMAT: - errorMsg = "The .exe file is invalid (non-Win32 .exe or error in .exe image)." - case SE_ERR_ACCESSDENIED: - errorMsg = "The operating system denied access to the specified file." - case SE_ERR_ASSOCINCOMPLETE: - errorMsg = "The file name association is incomplete or invalid." - case SE_ERR_DDEBUSY: - errorMsg = "The DDE transaction could not be completed because other DDE transactions were being processed." - case SE_ERR_DDEFAIL: - errorMsg = "The DDE transaction failed." - case SE_ERR_DDETIMEOUT: - errorMsg = "The DDE transaction could not be completed because the request timed out." - case SE_ERR_DLLNOTFOUND: - errorMsg = "The specified DLL was not found." - case SE_ERR_NOASSOC: - errorMsg = "There is no application associated with the given file name extension. This error will also be returned if you attempt to print a file that is not printable." - case SE_ERR_OOM: - errorMsg = "There was not enough memory to complete the operation." - case SE_ERR_SHARE: - errorMsg = "A sharing violation occurred." - default: - errorMsg = fmt.Sprintf("Unknown error occurred with error code %v", ret) - } - } else { - return nil - } - - return errors.New(errorMsg) -} - -func ExtractIcon(lpszExeFileName string, nIconIndex int) HICON { - ret, _, _ := procExtractIcon.Call( - 0, - uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpszExeFileName))), - uintptr(nIconIndex)) - - return HICON(ret) -} - -func SHGetSpecialFolderPath(hwndOwner HWND, lpszPath *uint16, csidl CSIDL, fCreate bool) bool { - ret, _, _ := procGetSpecialFolderPath.Call( - uintptr(hwndOwner), - uintptr(unsafe.Pointer(lpszPath)), - uintptr(csidl), - uintptr(BoolToBOOL(fCreate)), - 0, - 0) - - return ret != 0 -} diff --git a/v2/internal/frontend/desktop/windows/winc/w32/shlwapi.go b/v2/internal/frontend/desktop/windows/winc/w32/shlwapi.go deleted file mode 100644 index 89d17ce6f..000000000 --- a/v2/internal/frontend/desktop/windows/winc/w32/shlwapi.go +++ /dev/null @@ -1,26 +0,0 @@ -//go:build windows - -package w32 - -import ( - "syscall" - "unsafe" -) - -var ( - modshlwapi = syscall.NewLazyDLL("shlwapi.dll") - - procSHCreateMemStream = modshlwapi.NewProc("SHCreateMemStream") -) - -func SHCreateMemStream(data []byte) (uintptr, error) { - ret, _, err := procSHCreateMemStream.Call( - uintptr(unsafe.Pointer(&data[0])), - uintptr(len(data)), - ) - if ret == 0 { - return 0, err - } - - return ret, nil -} diff --git a/v2/internal/frontend/desktop/windows/winc/w32/toolbar.go b/v2/internal/frontend/desktop/windows/winc/w32/toolbar.go deleted file mode 100644 index ac9261fc4..000000000 --- a/v2/internal/frontend/desktop/windows/winc/w32/toolbar.go +++ /dev/null @@ -1,216 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved. - * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved. - */ - -package w32 - -// ToolBar messages -const ( - TB_ENABLEBUTTON = WM_USER + 1 - TB_CHECKBUTTON = WM_USER + 2 - TB_PRESSBUTTON = WM_USER + 3 - TB_HIDEBUTTON = WM_USER + 4 - TB_INDETERMINATE = WM_USER + 5 - TB_MARKBUTTON = WM_USER + 6 - TB_ISBUTTONENABLED = WM_USER + 9 - TB_ISBUTTONCHECKED = WM_USER + 10 - TB_ISBUTTONPRESSED = WM_USER + 11 - TB_ISBUTTONHIDDEN = WM_USER + 12 - TB_ISBUTTONINDETERMINATE = WM_USER + 13 - TB_ISBUTTONHIGHLIGHTED = WM_USER + 14 - TB_SETSTATE = WM_USER + 17 - TB_GETSTATE = WM_USER + 18 - TB_ADDBITMAP = WM_USER + 19 - TB_DELETEBUTTON = WM_USER + 22 - TB_GETBUTTON = WM_USER + 23 - TB_BUTTONCOUNT = WM_USER + 24 - TB_COMMANDTOINDEX = WM_USER + 25 - TB_SAVERESTORE = WM_USER + 76 - TB_CUSTOMIZE = WM_USER + 27 - TB_ADDSTRING = WM_USER + 77 - TB_GETITEMRECT = WM_USER + 29 - TB_BUTTONSTRUCTSIZE = WM_USER + 30 - TB_SETBUTTONSIZE = WM_USER + 31 - TB_SETBITMAPSIZE = WM_USER + 32 - TB_AUTOSIZE = WM_USER + 33 - TB_GETTOOLTIPS = WM_USER + 35 - TB_SETTOOLTIPS = WM_USER + 36 - TB_SETPARENT = WM_USER + 37 - TB_SETROWS = WM_USER + 39 - TB_GETROWS = WM_USER + 40 - TB_GETBITMAPFLAGS = WM_USER + 41 - TB_SETCMDID = WM_USER + 42 - TB_CHANGEBITMAP = WM_USER + 43 - TB_GETBITMAP = WM_USER + 44 - TB_GETBUTTONTEXT = WM_USER + 75 - TB_REPLACEBITMAP = WM_USER + 46 - TB_GETBUTTONSIZE = WM_USER + 58 - TB_SETBUTTONWIDTH = WM_USER + 59 - TB_SETINDENT = WM_USER + 47 - TB_SETIMAGELIST = WM_USER + 48 - TB_GETIMAGELIST = WM_USER + 49 - TB_LOADIMAGES = WM_USER + 50 - TB_GETRECT = WM_USER + 51 - TB_SETHOTIMAGELIST = WM_USER + 52 - TB_GETHOTIMAGELIST = WM_USER + 53 - TB_SETDISABLEDIMAGELIST = WM_USER + 54 - TB_GETDISABLEDIMAGELIST = WM_USER + 55 - TB_SETSTYLE = WM_USER + 56 - TB_GETSTYLE = WM_USER + 57 - TB_SETMAXTEXTROWS = WM_USER + 60 - TB_GETTEXTROWS = WM_USER + 61 - TB_GETOBJECT = WM_USER + 62 - TB_GETBUTTONINFO = WM_USER + 63 - TB_SETBUTTONINFO = WM_USER + 64 - TB_INSERTBUTTON = WM_USER + 67 - TB_ADDBUTTONS = WM_USER + 68 - TB_HITTEST = WM_USER + 69 - TB_SETDRAWTEXTFLAGS = WM_USER + 70 - TB_GETHOTITEM = WM_USER + 71 - TB_SETHOTITEM = WM_USER + 72 - TB_SETANCHORHIGHLIGHT = WM_USER + 73 - TB_GETANCHORHIGHLIGHT = WM_USER + 74 - TB_GETINSERTMARK = WM_USER + 79 - TB_SETINSERTMARK = WM_USER + 80 - TB_INSERTMARKHITTEST = WM_USER + 81 - TB_MOVEBUTTON = WM_USER + 82 - TB_GETMAXSIZE = WM_USER + 83 - TB_SETEXTENDEDSTYLE = WM_USER + 84 - TB_GETEXTENDEDSTYLE = WM_USER + 85 - TB_GETPADDING = WM_USER + 86 - TB_SETPADDING = WM_USER + 87 - TB_SETINSERTMARKCOLOR = WM_USER + 88 - TB_GETINSERTMARKCOLOR = WM_USER + 89 - TB_MAPACCELERATOR = WM_USER + 90 - TB_GETSTRING = WM_USER + 91 - TB_SETCOLORSCHEME = CCM_SETCOLORSCHEME - TB_GETCOLORSCHEME = CCM_GETCOLORSCHEME - TB_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT - TB_GETUNICODEFORMAT = CCM_GETUNICODEFORMAT -) - -// ToolBar notifications -const ( - TBN_FIRST = -700 - TBN_DROPDOWN = TBN_FIRST - 10 -) - -// TBN_DROPDOWN return codes -const ( - TBDDRET_DEFAULT = 0 - TBDDRET_NODEFAULT = 1 - TBDDRET_TREATPRESSED = 2 -) - -// ToolBar state constants -const ( - TBSTATE_CHECKED = 1 - TBSTATE_PRESSED = 2 - TBSTATE_ENABLED = 4 - TBSTATE_HIDDEN = 8 - TBSTATE_INDETERMINATE = 16 - TBSTATE_WRAP = 32 - TBSTATE_ELLIPSES = 0x40 - TBSTATE_MARKED = 0x0080 -) - -// ToolBar style constants -const ( - TBSTYLE_BUTTON = 0 - TBSTYLE_SEP = 1 - TBSTYLE_CHECK = 2 - TBSTYLE_GROUP = 4 - TBSTYLE_CHECKGROUP = TBSTYLE_GROUP | TBSTYLE_CHECK - TBSTYLE_DROPDOWN = 8 - TBSTYLE_AUTOSIZE = 16 - TBSTYLE_NOPREFIX = 32 - TBSTYLE_TOOLTIPS = 256 - TBSTYLE_WRAPABLE = 512 - TBSTYLE_ALTDRAG = 1024 - TBSTYLE_FLAT = 2048 - TBSTYLE_LIST = 4096 - TBSTYLE_CUSTOMERASE = 8192 - TBSTYLE_REGISTERDROP = 0x4000 - TBSTYLE_TRANSPARENT = 0x8000 -) - -// ToolBar extended style constants -const ( - TBSTYLE_EX_DRAWDDARROWS = 0x00000001 - TBSTYLE_EX_MIXEDBUTTONS = 8 - TBSTYLE_EX_HIDECLIPPEDBUTTONS = 16 - TBSTYLE_EX_DOUBLEBUFFER = 0x80 -) - -// ToolBar button style constants -const ( - BTNS_BUTTON = TBSTYLE_BUTTON - BTNS_SEP = TBSTYLE_SEP - BTNS_CHECK = TBSTYLE_CHECK - BTNS_GROUP = TBSTYLE_GROUP - BTNS_CHECKGROUP = TBSTYLE_CHECKGROUP - BTNS_DROPDOWN = TBSTYLE_DROPDOWN - BTNS_AUTOSIZE = TBSTYLE_AUTOSIZE - BTNS_NOPREFIX = TBSTYLE_NOPREFIX - BTNS_WHOLEDROPDOWN = 0x0080 - BTNS_SHOWTEXT = 0x0040 -) - -// TBBUTTONINFO mask flags -const ( - TBIF_IMAGE = 0x00000001 - TBIF_TEXT = 0x00000002 - TBIF_STATE = 0x00000004 - TBIF_STYLE = 0x00000008 - TBIF_LPARAM = 0x00000010 - TBIF_COMMAND = 0x00000020 - TBIF_SIZE = 0x00000040 - TBIF_BYINDEX = 0x80000000 -) - -type NMMOUSE struct { - Hdr NMHDR - DwItemSpec uintptr - DwItemData uintptr - Pt POINT - DwHitInfo uintptr -} - -type NMTOOLBAR struct { - Hdr NMHDR - IItem int32 - TbButton TBBUTTON - CchText int32 - PszText *uint16 - RcButton RECT -} - -type TBBUTTON struct { - IBitmap int32 - IdCommand int32 - FsState byte - FsStyle byte - //#ifdef _WIN64 - // BYTE bReserved[6] // padding for alignment - //#elif defined(_WIN32) - BReserved [2]byte // padding for alignment - //#endif - DwData uintptr - IString uintptr -} - -type TBBUTTONINFO struct { - CbSize uint32 - DwMask uint32 - IdCommand int32 - IImage int32 - FsState byte - FsStyle byte - Cx uint16 - LParam uintptr - PszText uintptr - CchText int32 -} diff --git a/v2/internal/frontend/desktop/windows/winc/w32/typedef.go b/v2/internal/frontend/desktop/windows/winc/w32/typedef.go deleted file mode 100644 index 13735204c..000000000 --- a/v2/internal/frontend/desktop/windows/winc/w32/typedef.go +++ /dev/null @@ -1,1081 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved. - * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved. - */ - -package w32 - -import ( - "fmt" - "unsafe" -) - -// From MSDN: Windows Data Types -// http://msdn.microsoft.com/en-us/library/s3f49ktz.aspx -// http://msdn.microsoft.com/en-us/library/windows/desktop/aa383751.aspx -// ATOM WORD -// BOOL int32 -// BOOLEAN byte -// BYTE byte -// CCHAR int8 -// CHAR int8 -// COLORREF DWORD -// DWORD uint32 -// DWORDLONG ULONGLONG -// DWORD_PTR ULONG_PTR -// DWORD32 uint32 -// DWORD64 uint64 -// FLOAT float32 -// HACCEL HANDLE -// HALF_PTR struct{} // ??? -// HANDLE PVOID -// HBITMAP HANDLE -// HBRUSH HANDLE -// HCOLORSPACE HANDLE -// HCONV HANDLE -// HCONVLIST HANDLE -// HCURSOR HANDLE -// HDC HANDLE -// HDDEDATA HANDLE -// HDESK HANDLE -// HDROP HANDLE -// HDWP HANDLE -// HENHMETAFILE HANDLE -// HFILE HANDLE -// HFONT HANDLE -// HGDIOBJ HANDLE -// HGLOBAL HANDLE -// HHOOK HANDLE -// HICON HANDLE -// HINSTANCE HANDLE -// HKEY HANDLE -// HKL HANDLE -// HLOCAL HANDLE -// HMENU HANDLE -// HMETAFILE HANDLE -// HMODULE HANDLE -// HPALETTE HANDLE -// HPEN HANDLE -// HRESULT int32 -// HRGN HANDLE -// HSZ HANDLE -// HWINSTA HANDLE -// HWND HANDLE -// INT int32 -// INT_PTR uintptr -// INT8 int8 -// INT16 int16 -// INT32 int32 -// INT64 int64 -// LANGID WORD -// LCID DWORD -// LCTYPE DWORD -// LGRPID DWORD -// LONG int32 -// LONGLONG int64 -// LONG_PTR uintptr -// LONG32 int32 -// LONG64 int64 -// LPARAM LONG_PTR -// LPBOOL *BOOL -// LPBYTE *BYTE -// LPCOLORREF *COLORREF -// LPCSTR *int8 -// LPCTSTR LPCWSTR -// LPCVOID unsafe.Pointer -// LPCWSTR *WCHAR -// LPDWORD *DWORD -// LPHANDLE *HANDLE -// LPINT *INT -// LPLONG *LONG -// LPSTR *CHAR -// LPTSTR LPWSTR -// LPVOID unsafe.Pointer -// LPWORD *WORD -// LPWSTR *WCHAR -// LRESULT LONG_PTR -// PBOOL *BOOL -// PBOOLEAN *BOOLEAN -// PBYTE *BYTE -// PCHAR *CHAR -// PCSTR *CHAR -// PCTSTR PCWSTR -// PCWSTR *WCHAR -// PDWORD *DWORD -// PDWORDLONG *DWORDLONG -// PDWORD_PTR *DWORD_PTR -// PDWORD32 *DWORD32 -// PDWORD64 *DWORD64 -// PFLOAT *FLOAT -// PHALF_PTR *HALF_PTR -// PHANDLE *HANDLE -// PHKEY *HKEY -// PINT_PTR *INT_PTR -// PINT8 *INT8 -// PINT16 *INT16 -// PINT32 *INT32 -// PINT64 *INT64 -// PLCID *LCID -// PLONG *LONG -// PLONGLONG *LONGLONG -// PLONG_PTR *LONG_PTR -// PLONG32 *LONG32 -// PLONG64 *LONG64 -// POINTER_32 struct{} // ??? -// POINTER_64 struct{} // ??? -// POINTER_SIGNED uintptr -// POINTER_UNSIGNED uintptr -// PSHORT *SHORT -// PSIZE_T *SIZE_T -// PSSIZE_T *SSIZE_T -// PSTR *CHAR -// PTBYTE *TBYTE -// PTCHAR *TCHAR -// PTSTR PWSTR -// PUCHAR *UCHAR -// PUHALF_PTR *UHALF_PTR -// PUINT *UINT -// PUINT_PTR *UINT_PTR -// PUINT8 *UINT8 -// PUINT16 *UINT16 -// PUINT32 *UINT32 -// PUINT64 *UINT64 -// PULONG *ULONG -// PULONGLONG *ULONGLONG -// PULONG_PTR *ULONG_PTR -// PULONG32 *ULONG32 -// PULONG64 *ULONG64 -// PUSHORT *USHORT -// PVOID unsafe.Pointer -// PWCHAR *WCHAR -// PWORD *WORD -// PWSTR *WCHAR -// QWORD uint64 -// SC_HANDLE HANDLE -// SC_LOCK LPVOID -// SERVICE_STATUS_HANDLE HANDLE -// SHORT int16 -// SIZE_T ULONG_PTR -// SSIZE_T LONG_PTR -// TBYTE WCHAR -// TCHAR WCHAR -// UCHAR uint8 -// UHALF_PTR struct{} // ??? -// UINT uint32 -// UINT_PTR uintptr -// UINT8 uint8 -// UINT16 uint16 -// UINT32 uint32 -// UINT64 uint64 -// ULONG uint32 -// ULONGLONG uint64 -// ULONG_PTR uintptr -// ULONG32 uint32 -// ULONG64 uint64 -// USHORT uint16 -// USN LONGLONG -// WCHAR uint16 -// WORD uint16 -// WPARAM UINT_PTR -type ( - ATOM = uint16 - BOOL = int32 - COLORREF = uint32 - DWM_FRAME_COUNT = uint64 - WORD = uint16 - DWORD = uint32 - HACCEL = HANDLE - HANDLE = uintptr - HBITMAP = HANDLE - HBRUSH = HANDLE - HCURSOR = HANDLE - HDC = HANDLE - HDROP = HANDLE - HDWP = HANDLE - HENHMETAFILE = HANDLE - HFONT = HANDLE - HGDIOBJ = HANDLE - HGLOBAL = HANDLE - HGLRC = HANDLE - HHOOK = HANDLE - HICON = HANDLE - HIMAGELIST = HANDLE - HINSTANCE = HANDLE - HKEY = HANDLE - HKL = HANDLE - HMENU = HANDLE - HMODULE = HANDLE - HMONITOR = HANDLE - HPEN = HANDLE - HRESULT = int32 - HRGN = HANDLE - HRSRC = HANDLE - HTHUMBNAIL = HANDLE - HWND = HANDLE - LPARAM = uintptr - LPCVOID = unsafe.Pointer - LRESULT = uintptr - PVOID = unsafe.Pointer - QPC_TIME = uint64 - ULONG_PTR = uintptr - SIZE_T = ULONG_PTR - WPARAM = uintptr - UINT = uint -) - -// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162805.aspx -type POINT struct { - X, Y int32 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162897.aspx -type RECT struct { - Left, Top, Right, Bottom int32 -} - -func (r *RECT) String() string { - return fmt.Sprintf("RECT (%p): Left: %d, Top: %d, Right: %d, Bottom: %d", r, r.Left, r.Top, r.Right, r.Bottom) -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/ms633577.aspx -type WNDCLASSEX struct { - Size uint32 - Style uint32 - WndProc uintptr - ClsExtra int32 - WndExtra int32 - Instance HINSTANCE - Icon HICON - Cursor HCURSOR - Background HBRUSH - MenuName *uint16 - ClassName *uint16 - IconSm HICON -} - -type TPMPARAMS struct { - CbSize uint32 - RcExclude RECT -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/ms644958.aspx -type MSG struct { - Hwnd HWND - Message uint32 - WParam uintptr - LParam uintptr - Time uint32 - Pt POINT -} - -// https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-minmaxinfo -type MINMAXINFO struct { - PtReserved POINT - PtMaxSize POINT - PtMaxPosition POINT - PtMinTrackSize POINT - PtMaxTrackSize POINT -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145037.aspx -type LOGFONT struct { - Height int32 - Width int32 - Escapement int32 - Orientation int32 - Weight int32 - Italic byte - Underline byte - StrikeOut byte - CharSet byte - OutPrecision byte - ClipPrecision byte - Quality byte - PitchAndFamily byte - FaceName [LF_FACESIZE]uint16 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646839.aspx -type OPENFILENAME struct { - StructSize uint32 - Owner HWND - Instance HINSTANCE - Filter *uint16 - CustomFilter *uint16 - MaxCustomFilter uint32 - FilterIndex uint32 - File *uint16 - MaxFile uint32 - FileTitle *uint16 - MaxFileTitle uint32 - InitialDir *uint16 - Title *uint16 - Flags uint32 - FileOffset uint16 - FileExtension uint16 - DefExt *uint16 - CustData uintptr - FnHook uintptr - TemplateName *uint16 - PvReserved unsafe.Pointer - DwReserved uint32 - FlagsEx uint32 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/bb773205.aspx -type BROWSEINFO struct { - Owner HWND - Root *uint16 - DisplayName *uint16 - Title *uint16 - Flags uint32 - CallbackFunc uintptr - LParam uintptr - Image int32 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/aa373931.aspx -type GUID struct { - Data1 uint32 - Data2 uint16 - Data3 uint16 - Data4 [8]byte -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/ms221627.aspx -type VARIANT struct { - VT uint16 // 2 - WReserved1 uint16 // 4 - WReserved2 uint16 // 6 - WReserved3 uint16 // 8 - Val int64 // 16 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/ms221416.aspx -type DISPPARAMS struct { - Rgvarg uintptr - RgdispidNamedArgs uintptr - CArgs uint32 - CNamedArgs uint32 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/ms221133.aspx -type EXCEPINFO struct { - WCode uint16 - WReserved uint16 - BstrSource *uint16 - BstrDescription *uint16 - BstrHelpFile *uint16 - DwHelpContext uint32 - PvReserved uintptr - PfnDeferredFillIn uintptr - Scode int32 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145035.aspx -type LOGBRUSH struct { - LbStyle uint32 - LbColor COLORREF - LbHatch uintptr -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183565.aspx -type DEVMODE struct { - DmDeviceName [CCHDEVICENAME]uint16 - DmSpecVersion uint16 - DmDriverVersion uint16 - DmSize uint16 - DmDriverExtra uint16 - DmFields uint32 - DmOrientation int16 - DmPaperSize int16 - DmPaperLength int16 - DmPaperWidth int16 - DmScale int16 - DmCopies int16 - DmDefaultSource int16 - DmPrintQuality int16 - DmColor int16 - DmDuplex int16 - DmYResolution int16 - DmTTOption int16 - DmCollate int16 - DmFormName [CCHFORMNAME]uint16 - DmLogPixels uint16 - DmBitsPerPel uint32 - DmPelsWidth uint32 - DmPelsHeight uint32 - DmDisplayFlags uint32 - DmDisplayFrequency uint32 - DmICMMethod uint32 - DmICMIntent uint32 - DmMediaType uint32 - DmDitherType uint32 - DmReserved1 uint32 - DmReserved2 uint32 - DmPanningWidth uint32 - DmPanningHeight uint32 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183376.aspx -type BITMAPINFOHEADER struct { - BiSize uint32 - BiWidth int32 - BiHeight int32 - BiPlanes uint16 - BiBitCount uint16 - BiCompression uint32 - BiSizeImage uint32 - BiXPelsPerMeter int32 - BiYPelsPerMeter int32 - BiClrUsed uint32 - BiClrImportant uint32 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162938.aspx -type RGBQUAD struct { - RgbBlue byte - RgbGreen byte - RgbRed byte - RgbReserved byte -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183375.aspx -type BITMAPINFO struct { - BmiHeader BITMAPINFOHEADER - BmiColors *RGBQUAD -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183371.aspx -type BITMAP struct { - BmType int32 - BmWidth int32 - BmHeight int32 - BmWidthBytes int32 - BmPlanes uint16 - BmBitsPixel uint16 - BmBits unsafe.Pointer -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183567.aspx -type DIBSECTION struct { - DsBm BITMAP - DsBmih BITMAPINFOHEADER - DsBitfields [3]uint32 - DshSection HANDLE - DsOffset uint32 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162607.aspx -type ENHMETAHEADER struct { - IType uint32 - NSize uint32 - RclBounds RECT - RclFrame RECT - DSignature uint32 - NVersion uint32 - NBytes uint32 - NRecords uint32 - NHandles uint16 - SReserved uint16 - NDescription uint32 - OffDescription uint32 - NPalEntries uint32 - SzlDevice SIZE - SzlMillimeters SIZE - CbPixelFormat uint32 - OffPixelFormat uint32 - BOpenGL uint32 - SzlMicrometers SIZE -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145106.aspx -type SIZE struct { - CX, CY int32 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145132.aspx -type TEXTMETRIC struct { - TmHeight int32 - TmAscent int32 - TmDescent int32 - TmInternalLeading int32 - TmExternalLeading int32 - TmAveCharWidth int32 - TmMaxCharWidth int32 - TmWeight int32 - TmOverhang int32 - TmDigitizedAspectX int32 - TmDigitizedAspectY int32 - TmFirstChar uint16 - TmLastChar uint16 - TmDefaultChar uint16 - TmBreakChar uint16 - TmItalic byte - TmUnderlined byte - TmStruckOut byte - TmPitchAndFamily byte - TmCharSet byte -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183574.aspx -type DOCINFO struct { - CbSize int32 - LpszDocName *uint16 - LpszOutput *uint16 - LpszDatatype *uint16 - FwType uint32 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/bb775514.aspx -type NMHDR struct { - HwndFrom HWND - IdFrom uintptr - Code uint32 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774743.aspx -type LVCOLUMN struct { - Mask uint32 - Fmt int32 - Cx int32 - PszText *uint16 - CchTextMax int32 - ISubItem int32 - IImage int32 - IOrder int32 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774760.aspx -type LVITEM struct { - Mask uint32 - IItem int32 - ISubItem int32 - State uint32 - StateMask uint32 - PszText *uint16 - CchTextMax int32 - IImage int32 - LParam uintptr - IIndent int32 - IGroupId int32 - CColumns uint32 - PuColumns uint32 -} - -type LVFINDINFO struct { - Flags uint32 - PszText *uint16 - LParam uintptr - Pt POINT - VkDirection uint32 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774754.aspx -type LVHITTESTINFO struct { - Pt POINT - Flags uint32 - IItem int32 - ISubItem int32 - IGroup int32 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774771.aspx -type NMITEMACTIVATE struct { - Hdr NMHDR - IItem int32 - ISubItem int32 - UNewState uint32 - UOldState uint32 - UChanged uint32 - PtAction POINT - LParam uintptr - UKeyFlags uint32 -} - -type NMLVKEYDOWN struct { - Hdr NMHDR - WVKey uint16 - Flags uint32 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774773.aspx -type NMLISTVIEW struct { - Hdr NMHDR - IItem int32 - ISubItem int32 - UNewState uint32 - UOldState uint32 - UChanged uint32 - PtAction POINT - LParam uintptr -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774780.aspx -type NMLVDISPINFO struct { - Hdr NMHDR - Item LVITEM -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/bb775507.aspx -type INITCOMMONCONTROLSEX struct { - DwSize uint32 - DwICC uint32 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/bb760256.aspx -type TOOLINFO struct { - CbSize uint32 - UFlags uint32 - Hwnd HWND - UId uintptr - Rect RECT - Hinst HINSTANCE - LpszText *uint16 - LParam uintptr - LpReserved unsafe.Pointer -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/ms645604.aspx -type TRACKMOUSEEVENT struct { - CbSize uint32 - DwFlags uint32 - HwndTrack HWND - DwHoverTime uint32 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/ms534067.aspx -type GdiplusStartupInput struct { - GdiplusVersion uint32 - DebugEventCallback uintptr - SuppressBackgroundThread BOOL - SuppressExternalCodecs BOOL -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/ms534068.aspx -type GdiplusStartupOutput struct { - NotificationHook uintptr - NotificationUnhook uintptr -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162768.aspx -type PAINTSTRUCT struct { - Hdc HDC - FErase BOOL - RcPaint RECT - FRestore BOOL - FIncUpdate BOOL - RgbReserved [32]byte -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/aa363646.aspx -type EVENTLOGRECORD struct { - Length uint32 - Reserved uint32 - RecordNumber uint32 - TimeGenerated uint32 - TimeWritten uint32 - EventID uint32 - EventType uint16 - NumStrings uint16 - EventCategory uint16 - ReservedFlags uint16 - ClosingRecordNumber uint32 - StringOffset uint32 - UserSidLength uint32 - UserSidOffset uint32 - DataLength uint32 - DataOffset uint32 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/ms685996.aspx -type SERVICE_STATUS struct { - DwServiceType uint32 - DwCurrentState uint32 - DwControlsAccepted uint32 - DwWin32ExitCode uint32 - DwServiceSpecificExitCode uint32 - DwCheckPoint uint32 - DwWaitHint uint32 -} - -/* ------------------------- - Undocumented API -------------------------- */ - -type ACCENT_STATE DWORD - -const ( - ACCENT_DISABLED ACCENT_STATE = 0 - ACCENT_ENABLE_GRADIENT ACCENT_STATE = 1 - ACCENT_ENABLE_TRANSPARENTGRADIENT ACCENT_STATE = 2 - ACCENT_ENABLE_BLURBEHIND ACCENT_STATE = 3 - ACCENT_ENABLE_ACRYLICBLURBEHIND ACCENT_STATE = 4 // RS4 1803 - ACCENT_ENABLE_HOSTBACKDROP ACCENT_STATE = 5 // RS5 1809 - ACCENT_INVALID_STATE ACCENT_STATE = 6 -) - -type ACCENT_POLICY struct { - AccentState ACCENT_STATE - AccentFlags DWORD - GradientColor DWORD - AnimationId DWORD -} - -type WINDOWCOMPOSITIONATTRIBDATA struct { - Attrib WINDOWCOMPOSITIONATTRIB - PvData PVOID - CbData SIZE_T -} - -type WINDOWCOMPOSITIONATTRIB DWORD - -const ( - WCA_UNDEFINED WINDOWCOMPOSITIONATTRIB = 0 - WCA_NCRENDERING_ENABLED WINDOWCOMPOSITIONATTRIB = 1 - WCA_NCRENDERING_POLICY WINDOWCOMPOSITIONATTRIB = 2 - WCA_TRANSITIONS_FORCEDISABLED WINDOWCOMPOSITIONATTRIB = 3 - WCA_ALLOW_NCPAINT WINDOWCOMPOSITIONATTRIB = 4 - WCA_CAPTION_BUTTON_BOUNDS WINDOWCOMPOSITIONATTRIB = 5 - WCA_NONCLIENT_RTL_LAYOUT WINDOWCOMPOSITIONATTRIB = 6 - WCA_FORCE_ICONIC_REPRESENTATION WINDOWCOMPOSITIONATTRIB = 7 - WCA_EXTENDED_FRAME_BOUNDS WINDOWCOMPOSITIONATTRIB = 8 - WCA_HAS_ICONIC_BITMAP WINDOWCOMPOSITIONATTRIB = 9 - WCA_THEME_ATTRIBUTES WINDOWCOMPOSITIONATTRIB = 10 - WCA_NCRENDERING_EXILED WINDOWCOMPOSITIONATTRIB = 11 - WCA_NCADORNMENTINFO WINDOWCOMPOSITIONATTRIB = 12 - WCA_EXCLUDED_FROM_LIVEPREVIEW WINDOWCOMPOSITIONATTRIB = 13 - WCA_VIDEO_OVERLAY_ACTIVE WINDOWCOMPOSITIONATTRIB = 14 - WCA_FORCE_ACTIVEWINDOW_APPEARANCE WINDOWCOMPOSITIONATTRIB = 15 - WCA_DISALLOW_PEEK WINDOWCOMPOSITIONATTRIB = 16 - WCA_CLOAK WINDOWCOMPOSITIONATTRIB = 17 - WCA_CLOAKED WINDOWCOMPOSITIONATTRIB = 18 - WCA_ACCENT_POLICY WINDOWCOMPOSITIONATTRIB = 19 - WCA_FREEZE_REPRESENTATION WINDOWCOMPOSITIONATTRIB = 20 - WCA_EVER_UNCLOAKED WINDOWCOMPOSITIONATTRIB = 21 - WCA_VISUAL_OWNER WINDOWCOMPOSITIONATTRIB = 22 - WCA_HOLOGRAPHIC WINDOWCOMPOSITIONATTRIB = 23 - WCA_EXCLUDED_FROM_DDA WINDOWCOMPOSITIONATTRIB = 24 - WCA_PASSIVEUPDATEMODE WINDOWCOMPOSITIONATTRIB = 25 - WCA_USEDARKMODECOLORS WINDOWCOMPOSITIONATTRIB = 26 - WCA_CORNER_STYLE WINDOWCOMPOSITIONATTRIB = 27 - WCA_PART_COLOR WINDOWCOMPOSITIONATTRIB = 28 - WCA_DISABLE_MOVESIZE_FEEDBACK WINDOWCOMPOSITIONATTRIB = 29 - WCA_LAST WINDOWCOMPOSITIONATTRIB = 30 -) - -// ------------------------- - -// http://msdn.microsoft.com/en-us/library/windows/desktop/ms684225.aspx -type MODULEENTRY32 struct { - Size uint32 - ModuleID uint32 - ProcessID uint32 - GlblcntUsage uint32 - ProccntUsage uint32 - ModBaseAddr *uint8 - ModBaseSize uint32 - HModule HMODULE - SzModule [MAX_MODULE_NAME32 + 1]uint16 - SzExePath [MAX_PATH]uint16 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/ms724284.aspx -type FILETIME struct { - DwLowDateTime uint32 - DwHighDateTime uint32 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/ms682119.aspx -type COORD struct { - X, Y int16 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/ms686311.aspx -type SMALL_RECT struct { - Left, Top, Right, Bottom int16 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/ms682093.aspx -type CONSOLE_SCREEN_BUFFER_INFO struct { - DwSize COORD - DwCursorPosition COORD - WAttributes uint16 - SrWindow SMALL_RECT - DwMaximumWindowSize COORD -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/bb773244.aspx -type MARGINS struct { - CxLeftWidth, CxRightWidth, CyTopHeight, CyBottomHeight int32 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969500.aspx -type DWM_BLURBEHIND struct { - DwFlags uint32 - fEnable BOOL - hRgnBlur HRGN - fTransitionOnMaximized BOOL -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969501.aspx -type DWM_PRESENT_PARAMETERS struct { - cbSize uint32 - fQueue BOOL - cRefreshStart DWM_FRAME_COUNT - cBuffer uint32 - fUseSourceRate BOOL - rateSource UNSIGNED_RATIO - cRefreshesPerFrame uint32 - eSampling DWM_SOURCE_FRAME_SAMPLING -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969502.aspx -type DWM_THUMBNAIL_PROPERTIES struct { - dwFlags uint32 - rcDestination RECT - rcSource RECT - opacity byte - fVisible BOOL - fSourceClientAreaOnly BOOL -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969503.aspx -type DWM_TIMING_INFO struct { - cbSize uint32 - rateRefresh UNSIGNED_RATIO - qpcRefreshPeriod QPC_TIME - rateCompose UNSIGNED_RATIO - qpcVBlank QPC_TIME - cRefresh DWM_FRAME_COUNT - cDXRefresh uint32 - qpcCompose QPC_TIME - cFrame DWM_FRAME_COUNT - cDXPresent uint32 - cRefreshFrame DWM_FRAME_COUNT - cFrameSubmitted DWM_FRAME_COUNT - cDXPresentSubmitted uint32 - cFrameConfirmed DWM_FRAME_COUNT - cDXPresentConfirmed uint32 - cRefreshConfirmed DWM_FRAME_COUNT - cDXRefreshConfirmed uint32 - cFramesLate DWM_FRAME_COUNT - cFramesOutstanding uint32 - cFrameDisplayed DWM_FRAME_COUNT - qpcFrameDisplayed QPC_TIME - cRefreshFrameDisplayed DWM_FRAME_COUNT - cFrameComplete DWM_FRAME_COUNT - qpcFrameComplete QPC_TIME - cFramePending DWM_FRAME_COUNT - qpcFramePending QPC_TIME - cFramesDisplayed DWM_FRAME_COUNT - cFramesComplete DWM_FRAME_COUNT - cFramesPending DWM_FRAME_COUNT - cFramesAvailable DWM_FRAME_COUNT - cFramesDropped DWM_FRAME_COUNT - cFramesMissed DWM_FRAME_COUNT - cRefreshNextDisplayed DWM_FRAME_COUNT - cRefreshNextPresented DWM_FRAME_COUNT - cRefreshesDisplayed DWM_FRAME_COUNT - cRefreshesPresented DWM_FRAME_COUNT - cRefreshStarted DWM_FRAME_COUNT - cPixelsReceived uint64 - cPixelsDrawn uint64 - cBuffersEmpty DWM_FRAME_COUNT -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/dd389402.aspx -type MilMatrix3x2D struct { - S_11, S_12, S_21, S_22 float64 - DX, DY float64 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969505.aspx -type UNSIGNED_RATIO struct { - uiNumerator uint32 - uiDenominator uint32 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/ms632603.aspx -type CREATESTRUCT struct { - CreateParams uintptr - Instance HINSTANCE - Menu HMENU - Parent HWND - Cy, Cx int32 - Y, X int32 - Style int32 - Name *uint16 - Class *uint16 - dwExStyle uint32 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145065.aspx -type MONITORINFO struct { - CbSize uint32 - RcMonitor RECT - RcWork RECT - DwFlags uint32 -} - -type WINDOWINFO struct { - CbSize DWORD - RcWindow RECT - RcClient RECT - DwStyle DWORD - DwExStyle DWORD - DwWindowStatus DWORD - CxWindowBorders UINT - CyWindowBorders UINT - AtomWindowType ATOM - WCreatorVersion WORD -} - -type MONITOR_DPI_TYPE int32 - -const ( - MDT_EFFECTIVE_DPI MONITOR_DPI_TYPE = 0 - MDT_ANGULAR_DPI MONITOR_DPI_TYPE = 1 - MDT_RAW_DPI MONITOR_DPI_TYPE = 2 - MDT_DEFAULT MONITOR_DPI_TYPE = 0 -) - -func (w *WINDOWINFO) isStyle(style DWORD) bool { - return w.DwStyle&style == style -} - -func (w *WINDOWINFO) IsPopup() bool { - return w.isStyle(WS_POPUP) -} - -func (m *MONITORINFO) Dump() { - fmt.Printf("MONITORINFO (%p)\n", m) - fmt.Printf(" CbSize : %d\n", m.CbSize) - fmt.Printf(" RcMonitor: %s\n", &m.RcMonitor) - fmt.Printf(" RcWork : %s\n", &m.RcWork) - fmt.Printf(" DwFlags : %d\n", m.DwFlags) -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145066.aspx -type MONITORINFOEX struct { - MONITORINFO - SzDevice [CCHDEVICENAME]uint16 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/dd368826.aspx -type PIXELFORMATDESCRIPTOR struct { - Size uint16 - Version uint16 - DwFlags uint32 - IPixelType byte - ColorBits byte - RedBits, RedShift byte - GreenBits, GreenShift byte - BlueBits, BlueShift byte - AlphaBits, AlphaShift byte - AccumBits byte - AccumRedBits byte - AccumGreenBits byte - AccumBlueBits byte - AccumAlphaBits byte - DepthBits, StencilBits byte - AuxBuffers byte - ILayerType byte - Reserved byte - DwLayerMask uint32 - DwVisibleMask uint32 - DwDamageMask uint32 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646270(v=vs.85).aspx -type INPUT struct { - Type uint32 - Mi MOUSEINPUT - Ki KEYBDINPUT - Hi HARDWAREINPUT -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646273(v=vs.85).aspx -type MOUSEINPUT struct { - Dx int32 - Dy int32 - MouseData uint32 - DwFlags uint32 - Time uint32 - DwExtraInfo uintptr -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646271(v=vs.85).aspx -type KEYBDINPUT struct { - WVk uint16 - WScan uint16 - DwFlags uint32 - Time uint32 - DwExtraInfo uintptr -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646269(v=vs.85).aspx -type HARDWAREINPUT struct { - UMsg uint32 - WParamL uint16 - WParamH uint16 -} - -type KbdInput struct { - typ uint32 - ki KEYBDINPUT -} - -type MouseInput struct { - typ uint32 - mi MOUSEINPUT -} - -type HardwareInput struct { - typ uint32 - hi HARDWAREINPUT -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/ms724950(v=vs.85).aspx -type SYSTEMTIME struct { - Year uint16 - Month uint16 - DayOfWeek uint16 - Day uint16 - Hour uint16 - Minute uint16 - Second uint16 - Milliseconds uint16 -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/ms644967(v=vs.85).aspx -type KBDLLHOOKSTRUCT struct { - VkCode DWORD - ScanCode DWORD - Flags DWORD - Time DWORD - DwExtraInfo ULONG_PTR -} - -type HOOKPROC func(int, WPARAM, LPARAM) LRESULT - -type WINDOWPLACEMENT struct { - Length uint32 - Flags uint32 - ShowCmd uint32 - PtMinPosition POINT - PtMaxPosition POINT - RcNormalPosition RECT -} - -type SCROLLINFO struct { - CbSize uint32 - FMask uint32 - NMin int32 - NMax int32 - NPage uint32 - NPos int32 - NTrackPos int32 -} diff --git a/v2/internal/frontend/desktop/windows/winc/w32/user32.go b/v2/internal/frontend/desktop/windows/winc/w32/user32.go deleted file mode 100644 index 707701f5e..000000000 --- a/v2/internal/frontend/desktop/windows/winc/w32/user32.go +++ /dev/null @@ -1,1277 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved. - * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved. - */ - -package w32 - -import ( - "fmt" - "runtime" - "syscall" - "unsafe" -) - -var ( - moduser32 = syscall.NewLazyDLL("user32.dll") - - procRegisterClassEx = moduser32.NewProc("RegisterClassExW") - procLoadIcon = moduser32.NewProc("LoadIconW") - procLoadCursor = moduser32.NewProc("LoadCursorW") - procShowWindow = moduser32.NewProc("ShowWindow") - procShowWindowAsync = moduser32.NewProc("ShowWindowAsync") - procUpdateWindow = moduser32.NewProc("UpdateWindow") - procCreateWindowEx = moduser32.NewProc("CreateWindowExW") - procFindWindowW = moduser32.NewProc("FindWindowW") - procAdjustWindowRect = moduser32.NewProc("AdjustWindowRect") - procAdjustWindowRectEx = moduser32.NewProc("AdjustWindowRectEx") - procDestroyWindow = moduser32.NewProc("DestroyWindow") - procDefWindowProc = moduser32.NewProc("DefWindowProcW") - procDefDlgProc = moduser32.NewProc("DefDlgProcW") - procPostQuitMessage = moduser32.NewProc("PostQuitMessage") - procGetMessage = moduser32.NewProc("GetMessageW") - procTranslateMessage = moduser32.NewProc("TranslateMessage") - procDispatchMessage = moduser32.NewProc("DispatchMessageW") - procSendMessage = moduser32.NewProc("SendMessageW") - procPostMessage = moduser32.NewProc("PostMessageW") - procWaitMessage = moduser32.NewProc("WaitMessage") - procSetWindowText = moduser32.NewProc("SetWindowTextW") - procGetWindowTextLength = moduser32.NewProc("GetWindowTextLengthW") - procGetWindowText = moduser32.NewProc("GetWindowTextW") - procGetWindowRect = moduser32.NewProc("GetWindowRect") - procGetWindowInfo = moduser32.NewProc("GetWindowInfo") - procSetWindowCompositionAttribute = moduser32.NewProc("SetWindowCompositionAttribute") - procMoveWindow = moduser32.NewProc("MoveWindow") - procScreenToClient = moduser32.NewProc("ScreenToClient") - procCallWindowProc = moduser32.NewProc("CallWindowProcW") - procSetWindowLong = moduser32.NewProc("SetWindowLongW") - procSetWindowLongPtr = moduser32.NewProc("SetWindowLongW") - procGetWindowLong = moduser32.NewProc("GetWindowLongW") - procGetWindowLongPtr = moduser32.NewProc("GetWindowLongW") - procEnableWindow = moduser32.NewProc("EnableWindow") - procIsWindowEnabled = moduser32.NewProc("IsWindowEnabled") - procIsWindowVisible = moduser32.NewProc("IsWindowVisible") - procSetFocus = moduser32.NewProc("SetFocus") - procGetFocus = moduser32.NewProc("GetFocus") - procSetActiveWindow = moduser32.NewProc("SetActiveWindow") - procSetForegroundWindow = moduser32.NewProc("SetForegroundWindow") - procBringWindowToTop = moduser32.NewProc("BringWindowToTop") - procInvalidateRect = moduser32.NewProc("InvalidateRect") - procGetClientRect = moduser32.NewProc("GetClientRect") - procGetDC = moduser32.NewProc("GetDC") - procReleaseDC = moduser32.NewProc("ReleaseDC") - procSetCapture = moduser32.NewProc("SetCapture") - procReleaseCapture = moduser32.NewProc("ReleaseCapture") - procGetWindowThreadProcessId = moduser32.NewProc("GetWindowThreadProcessId") - procMessageBox = moduser32.NewProc("MessageBoxW") - procGetSystemMetrics = moduser32.NewProc("GetSystemMetrics") - procPostThreadMessageW = moduser32.NewProc("PostThreadMessageW") - procRegisterWindowMessageA = moduser32.NewProc("RegisterWindowMessageA") - //procSysColorBrush = moduser32.NewProc("GetSysColorBrush") - procCopyRect = moduser32.NewProc("CopyRect") - procEqualRect = moduser32.NewProc("EqualRect") - procInflateRect = moduser32.NewProc("InflateRect") - procIntersectRect = moduser32.NewProc("IntersectRect") - procIsRectEmpty = moduser32.NewProc("IsRectEmpty") - procOffsetRect = moduser32.NewProc("OffsetRect") - procPtInRect = moduser32.NewProc("PtInRect") - procSetRect = moduser32.NewProc("SetRect") - procSetRectEmpty = moduser32.NewProc("SetRectEmpty") - procSubtractRect = moduser32.NewProc("SubtractRect") - procUnionRect = moduser32.NewProc("UnionRect") - procCreateDialogParam = moduser32.NewProc("CreateDialogParamW") - procDialogBoxParam = moduser32.NewProc("DialogBoxParamW") - procGetDlgItem = moduser32.NewProc("GetDlgItem") - procDrawIcon = moduser32.NewProc("DrawIcon") - procCreateMenu = moduser32.NewProc("CreateMenu") - //procSetMenu = moduser32.NewProc("SetMenu") - procDestroyMenu = moduser32.NewProc("DestroyMenu") - procCreatePopupMenu = moduser32.NewProc("CreatePopupMenu") - procCheckMenuRadioItem = moduser32.NewProc("CheckMenuRadioItem") - //procDrawMenuBar = moduser32.NewProc("DrawMenuBar") - //procInsertMenuItem = moduser32.NewProc("InsertMenuItemW") // FIXIT: - - procClientToScreen = moduser32.NewProc("ClientToScreen") - procIsDialogMessage = moduser32.NewProc("IsDialogMessageW") - procIsWindow = moduser32.NewProc("IsWindow") - procEndDialog = moduser32.NewProc("EndDialog") - procPeekMessage = moduser32.NewProc("PeekMessageW") - procTranslateAccelerator = moduser32.NewProc("TranslateAcceleratorW") - procSetWindowPos = moduser32.NewProc("SetWindowPos") - procFillRect = moduser32.NewProc("FillRect") - procDrawText = moduser32.NewProc("DrawTextW") - procAddClipboardFormatListener = moduser32.NewProc("AddClipboardFormatListener") - procRemoveClipboardFormatListener = moduser32.NewProc("RemoveClipboardFormatListener") - procOpenClipboard = moduser32.NewProc("OpenClipboard") - procCloseClipboard = moduser32.NewProc("CloseClipboard") - procEnumClipboardFormats = moduser32.NewProc("EnumClipboardFormats") - procGetClipboardData = moduser32.NewProc("GetClipboardData") - procSetClipboardData = moduser32.NewProc("SetClipboardData") - procEmptyClipboard = moduser32.NewProc("EmptyClipboard") - procGetClipboardFormatName = moduser32.NewProc("GetClipboardFormatNameW") - procIsClipboardFormatAvailable = moduser32.NewProc("IsClipboardFormatAvailable") - procBeginPaint = moduser32.NewProc("BeginPaint") - procEndPaint = moduser32.NewProc("EndPaint") - procGetKeyboardState = moduser32.NewProc("GetKeyboardState") - procMapVirtualKey = moduser32.NewProc("MapVirtualKeyExW") - procGetAsyncKeyState = moduser32.NewProc("GetAsyncKeyState") - procToAscii = moduser32.NewProc("ToAscii") - procSwapMouseButton = moduser32.NewProc("SwapMouseButton") - procGetCursorPos = moduser32.NewProc("GetCursorPos") - procSetCursorPos = moduser32.NewProc("SetCursorPos") - procSetCursor = moduser32.NewProc("SetCursor") - procCreateIcon = moduser32.NewProc("CreateIcon") - procDestroyIcon = moduser32.NewProc("DestroyIcon") - procMonitorFromPoint = moduser32.NewProc("MonitorFromPoint") - procMonitorFromRect = moduser32.NewProc("MonitorFromRect") - procMonitorFromWindow = moduser32.NewProc("MonitorFromWindow") - procGetMonitorInfo = moduser32.NewProc("GetMonitorInfoW") - procGetDpiForSystem = moduser32.NewProc("GetDpiForSystem") - procGetDpiForWindow = moduser32.NewProc("GetDpiForWindow") - procEnumDisplayMonitors = moduser32.NewProc("EnumDisplayMonitors") - procEnumDisplaySettingsEx = moduser32.NewProc("EnumDisplaySettingsExW") - procChangeDisplaySettingsEx = moduser32.NewProc("ChangeDisplaySettingsExW") - procSendInput = moduser32.NewProc("SendInput") - procSetWindowsHookEx = moduser32.NewProc("SetWindowsHookExW") - procUnhookWindowsHookEx = moduser32.NewProc("UnhookWindowsHookEx") - procCallNextHookEx = moduser32.NewProc("CallNextHookEx") - - libuser32, _ = syscall.LoadLibrary("user32.dll") - insertMenuItem, _ = syscall.GetProcAddress(libuser32, "InsertMenuItemW") - setMenuItemInfo, _ = syscall.GetProcAddress(libuser32, "SetMenuItemInfoW") - setMenu, _ = syscall.GetProcAddress(libuser32, "SetMenu") - drawMenuBar, _ = syscall.GetProcAddress(libuser32, "DrawMenuBar") - trackPopupMenuEx, _ = syscall.GetProcAddress(libuser32, "TrackPopupMenuEx") - getKeyState, _ = syscall.GetProcAddress(libuser32, "GetKeyState") - getSysColorBrush, _ = syscall.GetProcAddress(libuser32, "GetSysColorBrush") - - getWindowPlacement, _ = syscall.GetProcAddress(libuser32, "GetWindowPlacement") - setWindowPlacement, _ = syscall.GetProcAddress(libuser32, "SetWindowPlacement") - - setScrollInfo, _ = syscall.GetProcAddress(libuser32, "SetScrollInfo") - getScrollInfo, _ = syscall.GetProcAddress(libuser32, "GetScrollInfo") - - mainThread HANDLE -) - -func init() { - runtime.LockOSThread() - mainThread = GetCurrentThreadId() -} - -func GET_X_LPARAM(lp uintptr) int32 { - return int32(int16(LOWORD(uint32(lp)))) -} - -func GET_Y_LPARAM(lp uintptr) int32 { - return int32(int16(HIWORD(uint32(lp)))) -} - -func RegisterClassEx(wndClassEx *WNDCLASSEX) ATOM { - ret, _, _ := procRegisterClassEx.Call(uintptr(unsafe.Pointer(wndClassEx))) - return ATOM(ret) -} - -func LoadIcon(instance HINSTANCE, iconName *uint16) HICON { - ret, _, _ := procLoadIcon.Call( - uintptr(instance), - uintptr(unsafe.Pointer(iconName))) - - return HICON(ret) -} - -func LoadIconWithResourceID(instance HINSTANCE, res uint16) HICON { - ret, _, _ := procLoadIcon.Call( - uintptr(instance), - uintptr(res)) - - return HICON(ret) -} - -func LoadCursor(instance HINSTANCE, cursorName *uint16) HCURSOR { - ret, _, _ := procLoadCursor.Call( - uintptr(instance), - uintptr(unsafe.Pointer(cursorName))) - - return HCURSOR(ret) -} - -func LoadCursorWithResourceID(instance HINSTANCE, res uint16) HCURSOR { - ret, _, _ := procLoadCursor.Call( - uintptr(instance), - uintptr(res)) - - return HCURSOR(ret) -} - -func ShowWindow(hwnd HWND, cmdshow int) bool { - ret, _, _ := procShowWindow.Call( - uintptr(hwnd), - uintptr(cmdshow)) - - return ret != 0 -} - -func ShowWindowAsync(hwnd HWND, cmdshow int) bool { - ret, _, _ := procShowWindowAsync.Call( - uintptr(hwnd), - uintptr(cmdshow)) - - return ret != 0 -} - -func UpdateWindow(hwnd HWND) bool { - ret, _, _ := procUpdateWindow.Call( - uintptr(hwnd)) - return ret != 0 -} - -func PostThreadMessage(threadID HANDLE, msg int, wp, lp uintptr) { - procPostThreadMessageW.Call(threadID, uintptr(msg), wp, lp) -} - -func RegisterWindowMessage(name *uint16) uint32 { - ret, _, _ := procRegisterWindowMessageA.Call( - uintptr(unsafe.Pointer(name))) - - return uint32(ret) -} - -func PostMainThreadMessage(msg uint32, wp, lp uintptr) bool { - ret, _, _ := procPostThreadMessageW.Call(mainThread, uintptr(msg), wp, lp) - return ret != 0 -} - -func CreateWindowEx(exStyle uint, className, windowName *uint16, - style uint, x, y, width, height int, parent HWND, menu HMENU, - instance HINSTANCE, param unsafe.Pointer) HWND { - ret, _, _ := procCreateWindowEx.Call( - uintptr(exStyle), - uintptr(unsafe.Pointer(className)), - uintptr(unsafe.Pointer(windowName)), - uintptr(style), - uintptr(x), - uintptr(y), - uintptr(width), - uintptr(height), - uintptr(parent), - uintptr(menu), - uintptr(instance), - uintptr(param)) - - return HWND(ret) -} - -func FindWindowW(className, windowName *uint16) HWND { - ret, _, _ := procFindWindowW.Call( - uintptr(unsafe.Pointer(className)), - uintptr(unsafe.Pointer(windowName))) - - return HWND(ret) -} - -func AdjustWindowRectEx(rect *RECT, style uint, menu bool, exStyle uint) bool { - ret, _, _ := procAdjustWindowRectEx.Call( - uintptr(unsafe.Pointer(rect)), - uintptr(style), - uintptr(BoolToBOOL(menu)), - uintptr(exStyle)) - - return ret != 0 -} - -func AdjustWindowRect(rect *RECT, style uint, menu bool) bool { - ret, _, _ := procAdjustWindowRect.Call( - uintptr(unsafe.Pointer(rect)), - uintptr(style), - uintptr(BoolToBOOL(menu))) - - return ret != 0 -} - -func DestroyWindow(hwnd HWND) bool { - ret, _, _ := procDestroyWindow.Call(hwnd) - return ret != 0 -} - -func HasGetDpiForWindowFunc() bool { - err := procGetDpiForWindow.Find() - return err == nil -} - -func GetDpiForWindow(hwnd HWND) UINT { - dpi, _, _ := procGetDpiForWindow.Call(hwnd) - return uint(dpi) -} - -func SetWindowCompositionAttribute(hwnd HWND, data *WINDOWCOMPOSITIONATTRIBDATA) bool { - if procSetWindowCompositionAttribute != nil { - ret, _, _ := procSetWindowCompositionAttribute.Call( - hwnd, - uintptr(unsafe.Pointer(data)), - ) - return ret != 0 - } - return false -} - -func DefWindowProc(hwnd HWND, msg uint32, wParam, lParam uintptr) uintptr { - ret, _, _ := procDefWindowProc.Call( - uintptr(hwnd), - uintptr(msg), - wParam, - lParam) - - return ret -} - -func DefDlgProc(hwnd HWND, msg uint32, wParam, lParam uintptr) uintptr { - ret, _, _ := procDefDlgProc.Call( - uintptr(hwnd), - uintptr(msg), - wParam, - lParam) - - return ret -} - -func PostQuitMessage(exitCode int) { - procPostQuitMessage.Call( - uintptr(exitCode)) -} - -func GetMessage(msg *MSG, hwnd HWND, msgFilterMin, msgFilterMax uint32) int { - ret, _, _ := procGetMessage.Call( - uintptr(unsafe.Pointer(msg)), - uintptr(hwnd), - uintptr(msgFilterMin), - uintptr(msgFilterMax)) - - return int(ret) -} - -func TranslateMessage(msg *MSG) bool { - ret, _, _ := procTranslateMessage.Call( - uintptr(unsafe.Pointer(msg))) - - return ret != 0 - -} - -func DispatchMessage(msg *MSG) uintptr { - ret, _, _ := procDispatchMessage.Call( - uintptr(unsafe.Pointer(msg))) - - return ret - -} - -func SendMessage(hwnd HWND, msg uint32, wParam, lParam uintptr) uintptr { - ret, _, _ := procSendMessage.Call( - uintptr(hwnd), - uintptr(msg), - wParam, - lParam) - - return ret -} - -func PostMessage(hwnd HWND, msg uint32, wParam, lParam uintptr) bool { - ret, _, _ := procPostMessage.Call( - uintptr(hwnd), - uintptr(msg), - wParam, - lParam) - - return ret != 0 -} - -func WaitMessage() bool { - ret, _, _ := procWaitMessage.Call() - return ret != 0 -} - -func SetWindowText(hwnd HWND, text string) { - procSetWindowText.Call( - uintptr(hwnd), - uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(text)))) -} - -func GetWindowTextLength(hwnd HWND) int { - ret, _, _ := procGetWindowTextLength.Call( - uintptr(hwnd)) - - return int(ret) -} - -func GetWindowInfo(hwnd HWND, info *WINDOWINFO) int { - ret, _, _ := procGetWindowInfo.Call( - hwnd, - uintptr(unsafe.Pointer(info)), - ) - return int(ret) -} - -func GetWindowText(hwnd HWND) string { - textLen := GetWindowTextLength(hwnd) + 1 - - buf := make([]uint16, textLen) - procGetWindowText.Call( - uintptr(hwnd), - uintptr(unsafe.Pointer(&buf[0])), - uintptr(textLen)) - - return syscall.UTF16ToString(buf) -} - -func GetWindowRect(hwnd HWND) *RECT { - var rect RECT - procGetWindowRect.Call( - hwnd, - uintptr(unsafe.Pointer(&rect))) - - return &rect -} - -func MoveWindow(hwnd HWND, x, y, width, height int, repaint bool) bool { - ret, _, _ := procMoveWindow.Call( - uintptr(hwnd), - uintptr(x), - uintptr(y), - uintptr(width), - uintptr(height), - uintptr(BoolToBOOL(repaint))) - - return ret != 0 - -} - -func ScreenToClient(hwnd HWND, x, y int) (X, Y int, ok bool) { - pt := POINT{X: int32(x), Y: int32(y)} - ret, _, _ := procScreenToClient.Call( - uintptr(hwnd), - uintptr(unsafe.Pointer(&pt))) - - return int(pt.X), int(pt.Y), ret != 0 -} - -func CallWindowProc(preWndProc uintptr, hwnd HWND, msg uint32, wParam, lParam uintptr) uintptr { - ret, _, _ := procCallWindowProc.Call( - preWndProc, - uintptr(hwnd), - uintptr(msg), - wParam, - lParam) - - return ret -} - -func SetWindowLong(hwnd HWND, index int, value uint32) uint32 { - ret, _, _ := procSetWindowLong.Call( - uintptr(hwnd), - uintptr(index), - uintptr(value)) - - return uint32(ret) -} - -func SetWindowLongPtr(hwnd HWND, index int, value uintptr) uintptr { - ret, _, _ := procSetWindowLongPtr.Call( - uintptr(hwnd), - uintptr(index), - value) - - return ret -} - -func GetWindowLong(hwnd HWND, index int) int32 { - ret, _, _ := procGetWindowLong.Call( - uintptr(hwnd), - uintptr(index)) - - return int32(ret) -} - -func GetWindowLongPtr(hwnd HWND, index int) uintptr { - ret, _, _ := procGetWindowLongPtr.Call( - uintptr(hwnd), - uintptr(index)) - - return ret -} - -func EnableWindow(hwnd HWND, b bool) bool { - ret, _, _ := procEnableWindow.Call( - uintptr(hwnd), - uintptr(BoolToBOOL(b))) - return ret != 0 -} - -func IsWindowEnabled(hwnd HWND) bool { - ret, _, _ := procIsWindowEnabled.Call( - uintptr(hwnd)) - - return ret != 0 -} - -func IsWindowVisible(hwnd HWND) bool { - ret, _, _ := procIsWindowVisible.Call( - uintptr(hwnd)) - - return ret != 0 -} - -func SetFocus(hwnd HWND) HWND { - ret, _, _ := procSetFocus.Call( - uintptr(hwnd)) - - return HWND(ret) -} - -func SetActiveWindow(hwnd HWND) HWND { - ret, _, _ := procSetActiveWindow.Call( - uintptr(hwnd)) - - return HWND(ret) -} - -func BringWindowToTop(hwnd HWND) bool { - ret, _, _ := procBringWindowToTop.Call(uintptr(hwnd)) - return ret != 0 -} - -func SetForegroundWindow(hwnd HWND) HWND { - ret, _, _ := procSetForegroundWindow.Call( - uintptr(hwnd)) - - return HWND(ret) -} - -func GetFocus() HWND { - ret, _, _ := procGetFocus.Call() - return HWND(ret) -} - -func InvalidateRect(hwnd HWND, rect *RECT, erase bool) bool { - ret, _, _ := procInvalidateRect.Call( - uintptr(hwnd), - uintptr(unsafe.Pointer(rect)), - uintptr(BoolToBOOL(erase))) - - return ret != 0 -} - -func GetClientRect(hwnd HWND) *RECT { - var rect RECT - ret, _, _ := procGetClientRect.Call( - uintptr(hwnd), - uintptr(unsafe.Pointer(&rect))) - - if ret == 0 { - panic(fmt.Sprintf("GetClientRect(%d) failed", hwnd)) - } - - return &rect -} - -func GetDC(hwnd HWND) HDC { - ret, _, _ := procGetDC.Call( - uintptr(hwnd)) - - return HDC(ret) -} - -func ReleaseDC(hwnd HWND, hDC HDC) bool { - ret, _, _ := procReleaseDC.Call( - uintptr(hwnd), - uintptr(hDC)) - - return ret != 0 -} - -func SetCapture(hwnd HWND) HWND { - ret, _, _ := procSetCapture.Call( - uintptr(hwnd)) - - return HWND(ret) -} - -func ReleaseCapture() bool { - ret, _, _ := procReleaseCapture.Call() - - return ret != 0 -} - -func GetWindowThreadProcessId(hwnd HWND) (HANDLE, int) { - var processId int - ret, _, _ := procGetWindowThreadProcessId.Call( - uintptr(hwnd), - uintptr(unsafe.Pointer(&processId))) - - return HANDLE(ret), processId -} - -func MessageBox(hwnd HWND, title, caption string, flags uint) int { - ret, _, _ := procMessageBox.Call( - uintptr(hwnd), - uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(title))), - uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(caption))), - uintptr(flags)) - - return int(ret) -} - -func GetSystemMetrics(index int) int { - ret, _, _ := procGetSystemMetrics.Call( - uintptr(index)) - - return int(ret) -} - -func GetSysColorBrush(nIndex int) HBRUSH { - /* - ret, _, _ := procSysColorBrush.Call(1, - uintptr(nIndex), - 0, - 0) - - return HBRUSH(ret) - */ - ret, _, _ := syscall.SyscallN(getSysColorBrush, - uintptr(nIndex), - 0, - 0) - - return HBRUSH(ret) -} - -func CopyRect(dst, src *RECT) bool { - ret, _, _ := procCopyRect.Call( - uintptr(unsafe.Pointer(dst)), - uintptr(unsafe.Pointer(src))) - - return ret != 0 -} - -func EqualRect(rect1, rect2 *RECT) bool { - ret, _, _ := procEqualRect.Call( - uintptr(unsafe.Pointer(rect1)), - uintptr(unsafe.Pointer(rect2))) - - return ret != 0 -} - -func InflateRect(rect *RECT, dx, dy int) bool { - ret, _, _ := procInflateRect.Call( - uintptr(unsafe.Pointer(rect)), - uintptr(dx), - uintptr(dy)) - - return ret != 0 -} - -func IntersectRect(dst, src1, src2 *RECT) bool { - ret, _, _ := procIntersectRect.Call( - uintptr(unsafe.Pointer(dst)), - uintptr(unsafe.Pointer(src1)), - uintptr(unsafe.Pointer(src2))) - - return ret != 0 -} - -func IsRectEmpty(rect *RECT) bool { - ret, _, _ := procIsRectEmpty.Call( - uintptr(unsafe.Pointer(rect))) - - return ret != 0 -} - -func OffsetRect(rect *RECT, dx, dy int) bool { - ret, _, _ := procOffsetRect.Call( - uintptr(unsafe.Pointer(rect)), - uintptr(dx), - uintptr(dy)) - - return ret != 0 -} - -func PtInRect(rect *RECT, x, y int) bool { - pt := POINT{X: int32(x), Y: int32(y)} - ret, _, _ := procPtInRect.Call( - uintptr(unsafe.Pointer(rect)), - uintptr(unsafe.Pointer(&pt))) - - return ret != 0 -} - -func SetRect(rect *RECT, left, top, right, bottom int) bool { - ret, _, _ := procSetRect.Call( - uintptr(unsafe.Pointer(rect)), - uintptr(left), - uintptr(top), - uintptr(right), - uintptr(bottom)) - - return ret != 0 -} - -func SetRectEmpty(rect *RECT) bool { - ret, _, _ := procSetRectEmpty.Call( - uintptr(unsafe.Pointer(rect))) - - return ret != 0 -} - -func SubtractRect(dst, src1, src2 *RECT) bool { - ret, _, _ := procSubtractRect.Call( - uintptr(unsafe.Pointer(dst)), - uintptr(unsafe.Pointer(src1)), - uintptr(unsafe.Pointer(src2))) - - return ret != 0 -} - -func UnionRect(dst, src1, src2 *RECT) bool { - ret, _, _ := procUnionRect.Call( - uintptr(unsafe.Pointer(dst)), - uintptr(unsafe.Pointer(src1)), - uintptr(unsafe.Pointer(src2))) - - return ret != 0 -} - -func CreateDialog(hInstance HINSTANCE, lpTemplate *uint16, hWndParent HWND, lpDialogProc uintptr) HWND { - ret, _, _ := procCreateDialogParam.Call( - uintptr(hInstance), - uintptr(unsafe.Pointer(lpTemplate)), - uintptr(hWndParent), - lpDialogProc, - 0) - - return HWND(ret) -} - -func DialogBox(hInstance HINSTANCE, lpTemplateName *uint16, hWndParent HWND, lpDialogProc uintptr) int { - ret, _, _ := procDialogBoxParam.Call( - uintptr(hInstance), - uintptr(unsafe.Pointer(lpTemplateName)), - uintptr(hWndParent), - lpDialogProc, - 0) - - return int(ret) -} - -func GetDlgItem(hDlg HWND, nIDDlgItem int) HWND { - ret, _, _ := procGetDlgItem.Call( - uintptr(unsafe.Pointer(hDlg)), - uintptr(nIDDlgItem)) - - return HWND(ret) -} - -func DrawIcon(hDC HDC, x, y int, hIcon HICON) bool { - ret, _, _ := procDrawIcon.Call( - uintptr(unsafe.Pointer(hDC)), - uintptr(x), - uintptr(y), - uintptr(unsafe.Pointer(hIcon))) - - return ret != 0 -} - -func CreateMenu() HMENU { - ret, _, _ := procCreateMenu.Call(0, - 0, - 0, - 0) - - return HMENU(ret) -} - -func SetMenu(hWnd HWND, hMenu HMENU) bool { - ret, _, _ := syscall.SyscallN(setMenu, - uintptr(hWnd), - uintptr(hMenu)) - return ret != 0 -} - -// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-checkmenuradioitem -func SelectRadioMenuItem(menuID uint16, startID uint16, endID uint16, hwnd HWND) bool { - ret, _, _ := procCheckMenuRadioItem.Call( - hwnd, - uintptr(startID), - uintptr(endID), - uintptr(menuID), - MF_BYCOMMAND) - return ret != 0 - -} - -func CreatePopupMenu() HMENU { - ret, _, _ := procCreatePopupMenu.Call(0, - 0, - 0, - 0) - - return HMENU(ret) -} - -func TrackPopupMenuEx(hMenu HMENU, fuFlags uint32, x, y int32, hWnd HWND, lptpm *TPMPARAMS) BOOL { - ret, _, _ := syscall.Syscall6(trackPopupMenuEx, 6, - uintptr(hMenu), - uintptr(fuFlags), - uintptr(x), - uintptr(y), - uintptr(hWnd), - uintptr(unsafe.Pointer(lptpm))) - - return BOOL(ret) -} - -func DrawMenuBar(hWnd HWND) bool { - ret, _, _ := syscall.SyscallN(drawMenuBar, hWnd) - return ret != 0 -} - -func InsertMenuItem(hMenu HMENU, uItem uint32, fByPosition bool, lpmii *MENUITEMINFO) bool { - ret, _, _ := syscall.Syscall6(insertMenuItem, 4, - uintptr(hMenu), - uintptr(uItem), - uintptr(BoolToBOOL(fByPosition)), - uintptr(unsafe.Pointer(lpmii)), - 0, - 0) - - return ret != 0 -} - -func SetMenuItemInfo(hMenu HMENU, uItem uint32, fByPosition bool, lpmii *MENUITEMINFO) bool { - ret, _, _ := syscall.Syscall6(setMenuItemInfo, 4, - uintptr(hMenu), - uintptr(uItem), - uintptr(BoolToBOOL(fByPosition)), - uintptr(unsafe.Pointer(lpmii)), - 0, - 0) - - return ret != 0 -} - -func ClientToScreen(hwnd HWND, x, y int) (int, int) { - pt := POINT{X: int32(x), Y: int32(y)} - - procClientToScreen.Call( - uintptr(hwnd), - uintptr(unsafe.Pointer(&pt))) - - return int(pt.X), int(pt.Y) -} - -func IsDialogMessage(hwnd HWND, msg *MSG) bool { - ret, _, _ := procIsDialogMessage.Call( - uintptr(hwnd), - uintptr(unsafe.Pointer(msg))) - - return ret != 0 -} - -func IsWindow(hwnd HWND) bool { - ret, _, _ := procIsWindow.Call( - uintptr(hwnd)) - - return ret != 0 -} - -func EndDialog(hwnd HWND, nResult uintptr) bool { - ret, _, _ := procEndDialog.Call( - uintptr(hwnd), - nResult) - - return ret != 0 -} - -func PeekMessage(lpMsg *MSG, hwnd HWND, wMsgFilterMin, wMsgFilterMax, wRemoveMsg uint32) bool { - ret, _, _ := procPeekMessage.Call( - uintptr(unsafe.Pointer(lpMsg)), - uintptr(hwnd), - uintptr(wMsgFilterMin), - uintptr(wMsgFilterMax), - uintptr(wRemoveMsg)) - - return ret != 0 -} - -func TranslateAccelerator(hwnd HWND, hAccTable HACCEL, lpMsg *MSG) bool { - ret, _, _ := procTranslateMessage.Call( - uintptr(hwnd), - uintptr(hAccTable), - uintptr(unsafe.Pointer(lpMsg))) - - return ret != 0 -} - -func SetWindowPos(hwnd, hWndInsertAfter HWND, x, y, cx, cy int, uFlags uint) bool { - ret, _, _ := procSetWindowPos.Call( - uintptr(hwnd), - uintptr(hWndInsertAfter), - uintptr(x), - uintptr(y), - uintptr(cx), - uintptr(cy), - uintptr(uFlags)) - - return ret != 0 -} - -func FillRect(hDC HDC, lprc *RECT, hbr HBRUSH) bool { - ret, _, _ := procFillRect.Call( - uintptr(hDC), - uintptr(unsafe.Pointer(lprc)), - uintptr(hbr)) - - return ret != 0 -} - -func DrawText(hDC HDC, text string, uCount int, lpRect *RECT, uFormat uint) int { - ret, _, _ := procDrawText.Call( - uintptr(hDC), - uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(text))), - uintptr(uCount), - uintptr(unsafe.Pointer(lpRect)), - uintptr(uFormat)) - - return int(ret) -} - -func AddClipboardFormatListener(hwnd HWND) bool { - ret, _, _ := procAddClipboardFormatListener.Call( - uintptr(hwnd)) - return ret != 0 -} - -func RemoveClipboardFormatListener(hwnd HWND) bool { - ret, _, _ := procRemoveClipboardFormatListener.Call( - uintptr(hwnd)) - return ret != 0 -} - -func OpenClipboard(hWndNewOwner HWND) bool { - ret, _, _ := procOpenClipboard.Call( - uintptr(hWndNewOwner)) - return ret != 0 -} - -func CloseClipboard() bool { - ret, _, _ := procCloseClipboard.Call() - return ret != 0 -} - -func EnumClipboardFormats(format uint) uint { - ret, _, _ := procEnumClipboardFormats.Call( - uintptr(format)) - return uint(ret) -} - -func GetClipboardData(uFormat uint) HANDLE { - ret, _, _ := procGetClipboardData.Call( - uintptr(uFormat)) - return HANDLE(ret) -} - -func SetClipboardData(uFormat uint, hMem HANDLE) HANDLE { - ret, _, _ := procSetClipboardData.Call( - uintptr(uFormat), - uintptr(hMem)) - return HANDLE(ret) -} - -func EmptyClipboard() bool { - ret, _, _ := procEmptyClipboard.Call() - return ret != 0 -} - -func GetClipboardFormatName(format uint) (string, bool) { - cchMaxCount := 255 - buf := make([]uint16, cchMaxCount) - ret, _, _ := procGetClipboardFormatName.Call( - uintptr(format), - uintptr(unsafe.Pointer(&buf[0])), - uintptr(cchMaxCount)) - - if ret > 0 { - return syscall.UTF16ToString(buf), true - } - - return "Requested format does not exist or is predefined", false -} - -func IsClipboardFormatAvailable(format uint) bool { - ret, _, _ := procIsClipboardFormatAvailable.Call(uintptr(format)) - return ret != 0 -} - -func BeginPaint(hwnd HWND, paint *PAINTSTRUCT) HDC { - ret, _, _ := procBeginPaint.Call( - uintptr(hwnd), - uintptr(unsafe.Pointer(paint))) - return HDC(ret) -} - -func EndPaint(hwnd HWND, paint *PAINTSTRUCT) { - procEndPaint.Call( - uintptr(hwnd), - uintptr(unsafe.Pointer(paint))) -} - -func GetKeyboardState(keyState []byte) bool { - if len(keyState) != 256 { - panic("keyState slice must have a size of 256 bytes") - } - ret, _, _ := procGetKeyboardState.Call(uintptr(unsafe.Pointer(&keyState[0]))) - return ret != 0 -} - -func MapVirtualKeyEx(uCode, uMapType uint, dwhkl HKL) uint { - ret, _, _ := procMapVirtualKey.Call( - uintptr(uCode), - uintptr(uMapType), - uintptr(dwhkl)) - return uint(ret) -} - -func GetAsyncKeyState(vKey int) uint16 { - ret, _, _ := procGetAsyncKeyState.Call(uintptr(vKey)) - return uint16(ret) -} - -func ToAscii(uVirtKey, uScanCode uint, lpKeyState *byte, lpChar *uint16, uFlags uint) int { - ret, _, _ := procToAscii.Call( - uintptr(uVirtKey), - uintptr(uScanCode), - uintptr(unsafe.Pointer(lpKeyState)), - uintptr(unsafe.Pointer(lpChar)), - uintptr(uFlags)) - return int(ret) -} - -func SwapMouseButton(fSwap bool) bool { - ret, _, _ := procSwapMouseButton.Call( - uintptr(BoolToBOOL(fSwap))) - return ret != 0 -} - -func GetCursorPos() (x, y int, ok bool) { - pt := POINT{} - ret, _, _ := procGetCursorPos.Call(uintptr(unsafe.Pointer(&pt))) - return int(pt.X), int(pt.Y), ret != 0 -} - -func SetCursorPos(x, y int) bool { - ret, _, _ := procSetCursorPos.Call( - uintptr(x), - uintptr(y), - ) - return ret != 0 -} - -func SetCursor(cursor HCURSOR) HCURSOR { - ret, _, _ := procSetCursor.Call( - uintptr(cursor), - ) - return HCURSOR(ret) -} - -func CreateIcon(instance HINSTANCE, nWidth, nHeight int, cPlanes, cBitsPerPixel byte, ANDbits, XORbits *byte) HICON { - ret, _, _ := procCreateIcon.Call( - uintptr(instance), - uintptr(nWidth), - uintptr(nHeight), - uintptr(cPlanes), - uintptr(cBitsPerPixel), - uintptr(unsafe.Pointer(ANDbits)), - uintptr(unsafe.Pointer(XORbits)), - ) - return HICON(ret) -} - -func DestroyIcon(icon HICON) bool { - ret, _, _ := procDestroyIcon.Call( - uintptr(icon), - ) - return ret != 0 -} - -func MonitorFromPoint(x, y int, dwFlags uint32) HMONITOR { - ret, _, _ := procMonitorFromPoint.Call( - uintptr(x), - uintptr(y), - uintptr(dwFlags), - ) - return HMONITOR(ret) -} - -func MonitorFromRect(rc *RECT, dwFlags uint32) HMONITOR { - ret, _, _ := procMonitorFromRect.Call( - uintptr(unsafe.Pointer(rc)), - uintptr(dwFlags), - ) - return HMONITOR(ret) -} - -func MonitorFromWindow(hwnd HWND, dwFlags uint32) HMONITOR { - ret, _, _ := procMonitorFromWindow.Call( - uintptr(hwnd), - uintptr(dwFlags), - ) - return HMONITOR(ret) -} - -func GetMonitorInfo(hMonitor HMONITOR, lmpi *MONITORINFO) bool { - ret, _, _ := procGetMonitorInfo.Call( - uintptr(hMonitor), - uintptr(unsafe.Pointer(lmpi)), - ) - return ret != 0 -} - -func EnumDisplayMonitors(hdc HDC, clip *RECT, fnEnum uintptr, dwData unsafe.Pointer) bool { - ret, _, _ := procEnumDisplayMonitors.Call( - hdc, - uintptr(unsafe.Pointer(clip)), - fnEnum, - uintptr(dwData), - ) - return ret != 0 -} - -func EnumDisplaySettingsEx(szDeviceName *uint16, iModeNum uint32, devMode *DEVMODE, dwFlags uint32) bool { - ret, _, _ := procEnumDisplaySettingsEx.Call( - uintptr(unsafe.Pointer(szDeviceName)), - uintptr(iModeNum), - uintptr(unsafe.Pointer(devMode)), - uintptr(dwFlags), - ) - return ret != 0 -} - -func ChangeDisplaySettingsEx(szDeviceName *uint16, devMode *DEVMODE, hwnd HWND, dwFlags uint32, lParam uintptr) int32 { - ret, _, _ := procChangeDisplaySettingsEx.Call( - uintptr(unsafe.Pointer(szDeviceName)), - uintptr(unsafe.Pointer(devMode)), - uintptr(hwnd), - uintptr(dwFlags), - lParam, - ) - return int32(ret) -} - -/* -func SendInput(inputs []INPUT) uint32 { - var validInputs []C.INPUT - - for _, oneInput := range inputs { - input := C.INPUT{_type: C.DWORD(oneInput.Type)} - - switch oneInput.Type { - case INPUT_MOUSE: - (*MouseInput)(unsafe.Pointer(&input)).mi = oneInput.Mi - case INPUT_KEYBOARD: - (*KbdInput)(unsafe.Pointer(&input)).ki = oneInput.Ki - case INPUT_HARDWARE: - (*HardwareInput)(unsafe.Pointer(&input)).hi = oneInput.Hi - default: - panic("unkown type") - } - - validInputs = append(validInputs, input) - } - - ret, _, _ := procSendInput.Call( - uintptr(len(validInputs)), - uintptr(unsafe.Pointer(&validInputs[0])), - uintptr(unsafe.Sizeof(C.INPUT{})), - ) - return uint32(ret) -}*/ - -func SetWindowsHookEx(idHook int, lpfn HOOKPROC, hMod HINSTANCE, dwThreadId DWORD) HHOOK { - ret, _, _ := procSetWindowsHookEx.Call( - uintptr(idHook), - uintptr(syscall.NewCallback(lpfn)), - uintptr(hMod), - uintptr(dwThreadId), - ) - return HHOOK(ret) -} - -func UnhookWindowsHookEx(hhk HHOOK) bool { - ret, _, _ := procUnhookWindowsHookEx.Call( - uintptr(hhk), - ) - return ret != 0 -} - -func CallNextHookEx(hhk HHOOK, nCode int, wParam WPARAM, lParam LPARAM) LRESULT { - ret, _, _ := procCallNextHookEx.Call( - uintptr(hhk), - uintptr(nCode), - uintptr(wParam), - uintptr(lParam), - ) - return LRESULT(ret) -} - -func GetKeyState(nVirtKey int32) int16 { - ret, _, _ := syscall.SyscallN(getKeyState, - uintptr(nVirtKey)) - return int16(ret) -} - -func DestroyMenu(hMenu HMENU) bool { - ret, _, _ := procDestroyMenu.Call(1, - uintptr(hMenu), - 0, - 0) - - return ret != 0 -} - -func GetWindowPlacement(hWnd HWND, lpwndpl *WINDOWPLACEMENT) bool { - ret, _, _ := syscall.SyscallN(getWindowPlacement, - hWnd, - uintptr(unsafe.Pointer(lpwndpl))) - return ret != 0 -} - -func SetWindowPlacement(hWnd HWND, lpwndpl *WINDOWPLACEMENT) bool { - ret, _, _ := syscall.SyscallN(setWindowPlacement, - hWnd, - uintptr(unsafe.Pointer(lpwndpl)), - 0) - - return ret != 0 -} - -func SetScrollInfo(hwnd HWND, fnBar int32, lpsi *SCROLLINFO, fRedraw bool) int32 { - ret, _, _ := syscall.Syscall6(setScrollInfo, 4, - hwnd, - uintptr(fnBar), - uintptr(unsafe.Pointer(lpsi)), - uintptr(BoolToBOOL(fRedraw)), - 0, - 0) - - return int32(ret) -} - -func GetScrollInfo(hwnd HWND, fnBar int32, lpsi *SCROLLINFO) bool { - ret, _, _ := syscall.SyscallN(getScrollInfo, - hwnd, - uintptr(fnBar), - uintptr(unsafe.Pointer(lpsi))) - - return ret != 0 -} diff --git a/v2/internal/frontend/desktop/windows/winc/w32/utils.go b/v2/internal/frontend/desktop/windows/winc/w32/utils.go deleted file mode 100644 index 4568b4849..000000000 --- a/v2/internal/frontend/desktop/windows/winc/w32/utils.go +++ /dev/null @@ -1,230 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved. - * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved. - */ - -package w32 - -import ( - "syscall" - "unicode/utf16" - "unsafe" -) - -func MustLoadLibrary(name string) uintptr { - lib, err := syscall.LoadLibrary(name) - if err != nil { - panic(err) - } - - return uintptr(lib) -} - -func MustGetProcAddress(lib uintptr, name string) uintptr { - addr, err := syscall.GetProcAddress(syscall.Handle(lib), name) - if err != nil { - panic(err) - } - - return uintptr(addr) -} - -func SUCCEEDED(hr HRESULT) bool { - return hr >= 0 -} - -func FAILED(hr HRESULT) bool { - return hr < 0 -} - -func LOWORD(dw uint32) uint16 { - return uint16(dw) -} - -func HIWORD(dw uint32) uint16 { - return uint16(dw >> 16 & 0xffff) -} - -func MAKELONG(lo, hi uint16) uint32 { - return uint32(uint32(lo) | ((uint32(hi)) << 16)) -} - -func BoolToBOOL(value bool) BOOL { - if value { - return 1 - } - - return 0 -} - -func UTF16PtrToString(cstr *uint16) string { - if cstr != nil { - us := make([]uint16, 0, 256) - for p := uintptr(unsafe.Pointer(cstr)); ; p += 2 { - u := *(*uint16)(unsafe.Pointer(p)) - if u == 0 { - return string(utf16.Decode(us)) - } - us = append(us, u) - } - } - - return "" -} - -func ComAddRef(unknown *IUnknown) int32 { - ret, _, _ := syscall.SyscallN(unknown.lpVtbl.pAddRef, - uintptr(unsafe.Pointer(unknown)), - 0, - 0) - return int32(ret) -} - -func ComRelease(unknown *IUnknown) int32 { - ret, _, _ := syscall.SyscallN(unknown.lpVtbl.pRelease, - uintptr(unsafe.Pointer(unknown)), - 0, - 0) - return int32(ret) -} - -func ComQueryInterface(unknown *IUnknown, id *GUID) *IDispatch { - var disp *IDispatch - hr, _, _ := syscall.SyscallN(unknown.lpVtbl.pQueryInterface, - uintptr(unsafe.Pointer(unknown)), - uintptr(unsafe.Pointer(id)), - uintptr(unsafe.Pointer(&disp))) - if hr != 0 { - panic("Invoke QieryInterface error.") - } - return disp -} - -func ComGetIDsOfName(disp *IDispatch, names []string) []int32 { - wnames := make([]*uint16, len(names)) - dispid := make([]int32, len(names)) - for i := 0; i < len(names); i++ { - wnames[i] = syscall.StringToUTF16Ptr(names[i]) - } - hr, _, _ := syscall.Syscall6(disp.lpVtbl.pGetIDsOfNames, 6, - uintptr(unsafe.Pointer(disp)), - uintptr(unsafe.Pointer(IID_NULL)), - uintptr(unsafe.Pointer(&wnames[0])), - uintptr(len(names)), - uintptr(GetUserDefaultLCID()), - uintptr(unsafe.Pointer(&dispid[0]))) - if hr != 0 { - panic("Invoke GetIDsOfName error.") - } - return dispid -} - -func ComInvoke(disp *IDispatch, dispid int32, dispatch int16, params ...interface{}) (result *VARIANT) { - var dispparams DISPPARAMS - - if dispatch&DISPATCH_PROPERTYPUT != 0 { - dispnames := [1]int32{DISPID_PROPERTYPUT} - dispparams.RgdispidNamedArgs = uintptr(unsafe.Pointer(&dispnames[0])) - dispparams.CNamedArgs = 1 - } - var vargs []VARIANT - if len(params) > 0 { - vargs = make([]VARIANT, len(params)) - for i, v := range params { - //n := len(params)-i-1 - n := len(params) - i - 1 - VariantInit(&vargs[n]) - switch v.(type) { - case bool: - if v.(bool) { - vargs[n] = VARIANT{VT_BOOL, 0, 0, 0, 0xffff} - } else { - vargs[n] = VARIANT{VT_BOOL, 0, 0, 0, 0} - } - case *bool: - vargs[n] = VARIANT{VT_BOOL | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*bool))))} - case byte: - vargs[n] = VARIANT{VT_I1, 0, 0, 0, int64(v.(byte))} - case *byte: - vargs[n] = VARIANT{VT_I1 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*byte))))} - case int16: - vargs[n] = VARIANT{VT_I2, 0, 0, 0, int64(v.(int16))} - case *int16: - vargs[n] = VARIANT{VT_I2 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*int16))))} - case uint16: - vargs[n] = VARIANT{VT_UI2, 0, 0, 0, int64(v.(int16))} - case *uint16: - vargs[n] = VARIANT{VT_UI2 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*uint16))))} - case int, int32: - vargs[n] = VARIANT{VT_UI4, 0, 0, 0, int64(v.(int))} - case *int, *int32: - vargs[n] = VARIANT{VT_I4 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*int))))} - case uint, uint32: - vargs[n] = VARIANT{VT_UI4, 0, 0, 0, int64(v.(uint))} - case *uint, *uint32: - vargs[n] = VARIANT{VT_UI4 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*uint))))} - case int64: - vargs[n] = VARIANT{VT_I8, 0, 0, 0, v.(int64)} - case *int64: - vargs[n] = VARIANT{VT_I8 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*int64))))} - case uint64: - vargs[n] = VARIANT{VT_UI8, 0, 0, 0, int64(v.(uint64))} - case *uint64: - vargs[n] = VARIANT{VT_UI8 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*uint64))))} - case float32: - vargs[n] = VARIANT{VT_R4, 0, 0, 0, int64(v.(float32))} - case *float32: - vargs[n] = VARIANT{VT_R4 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*float32))))} - case float64: - vargs[n] = VARIANT{VT_R8, 0, 0, 0, int64(v.(float64))} - case *float64: - vargs[n] = VARIANT{VT_R8 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*float64))))} - case string: - vargs[n] = VARIANT{VT_BSTR, 0, 0, 0, int64(uintptr(unsafe.Pointer(SysAllocString(v.(string)))))} - case *string: - vargs[n] = VARIANT{VT_BSTR | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*string))))} - case *IDispatch: - vargs[n] = VARIANT{VT_DISPATCH, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*IDispatch))))} - case **IDispatch: - vargs[n] = VARIANT{VT_DISPATCH | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(**IDispatch))))} - case nil: - vargs[n] = VARIANT{VT_NULL, 0, 0, 0, 0} - case *VARIANT: - vargs[n] = VARIANT{VT_VARIANT | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*VARIANT))))} - default: - panic("unknown type") - } - } - dispparams.Rgvarg = uintptr(unsafe.Pointer(&vargs[0])) - dispparams.CArgs = uint32(len(params)) - } - - var ret VARIANT - var excepInfo EXCEPINFO - VariantInit(&ret) - hr, _, _ := syscall.Syscall9(disp.lpVtbl.pInvoke, 8, - uintptr(unsafe.Pointer(disp)), - uintptr(dispid), - uintptr(unsafe.Pointer(IID_NULL)), - uintptr(GetUserDefaultLCID()), - uintptr(dispatch), - uintptr(unsafe.Pointer(&dispparams)), - uintptr(unsafe.Pointer(&ret)), - uintptr(unsafe.Pointer(&excepInfo)), - 0) - if hr != 0 { - if excepInfo.BstrDescription != nil { - bs := UTF16PtrToString(excepInfo.BstrDescription) - panic(bs) - } - } - for _, varg := range vargs { - if varg.VT == VT_BSTR && varg.Val != 0 { - SysFreeString(((*int16)(unsafe.Pointer(uintptr(varg.Val))))) - } - } - result = &ret - return -} diff --git a/v2/internal/frontend/desktop/windows/winc/w32/uxtheme.go b/v2/internal/frontend/desktop/windows/winc/w32/uxtheme.go deleted file mode 100644 index 8a14f0cb7..000000000 --- a/v2/internal/frontend/desktop/windows/winc/w32/uxtheme.go +++ /dev/null @@ -1,152 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved. - * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved. - */ - -package w32 - -import ( - "syscall" - "unsafe" -) - -// LISTVIEW parts -const ( - LVP_LISTITEM = 1 - LVP_LISTGROUP = 2 - LVP_LISTDETAIL = 3 - LVP_LISTSORTEDDETAIL = 4 - LVP_EMPTYTEXT = 5 - LVP_GROUPHEADER = 6 - LVP_GROUPHEADERLINE = 7 - LVP_EXPANDBUTTON = 8 - LVP_COLLAPSEBUTTON = 9 - LVP_COLUMNDETAIL = 10 -) - -// LVP_LISTITEM states -const ( - LISS_NORMAL = 1 - LISS_HOT = 2 - LISS_SELECTED = 3 - LISS_DISABLED = 4 - LISS_SELECTEDNOTFOCUS = 5 - LISS_HOTSELECTED = 6 -) - -// TREEVIEW parts -const ( - TVP_TREEITEM = 1 - TVP_GLYPH = 2 - TVP_BRANCH = 3 - TVP_HOTGLYPH = 4 -) - -// TVP_TREEITEM states -const ( - TREIS_NORMAL = 1 - TREIS_HOT = 2 - TREIS_SELECTED = 3 - TREIS_DISABLED = 4 - TREIS_SELECTEDNOTFOCUS = 5 - TREIS_HOTSELECTED = 6 -) - -type HTHEME HANDLE - -var ( - // Library - libuxtheme uintptr - - // Functions - closeThemeData uintptr - drawThemeBackground uintptr - drawThemeText uintptr - getThemeTextExtent uintptr - openThemeData uintptr - setWindowTheme uintptr -) - -func Init() { - // Library - libuxtheme = MustLoadLibrary("uxtheme.dll") - - // Functions - closeThemeData = MustGetProcAddress(libuxtheme, "CloseThemeData") - drawThemeBackground = MustGetProcAddress(libuxtheme, "DrawThemeBackground") - drawThemeText = MustGetProcAddress(libuxtheme, "DrawThemeText") - getThemeTextExtent = MustGetProcAddress(libuxtheme, "GetThemeTextExtent") - openThemeData = MustGetProcAddress(libuxtheme, "OpenThemeData") - setWindowTheme = MustGetProcAddress(libuxtheme, "SetWindowTheme") -} - -func CloseThemeData(hTheme HTHEME) HRESULT { - ret, _, _ := syscall.SyscallN(closeThemeData, - uintptr(hTheme), - 0, - 0) - - return HRESULT(ret) -} - -func DrawThemeBackground(hTheme HTHEME, hdc HDC, iPartId, iStateId int32, pRect, pClipRect *RECT) HRESULT { - ret, _, _ := syscall.Syscall6(drawThemeBackground, 6, - uintptr(hTheme), - uintptr(hdc), - uintptr(iPartId), - uintptr(iStateId), - uintptr(unsafe.Pointer(pRect)), - uintptr(unsafe.Pointer(pClipRect))) - - return HRESULT(ret) -} - -func DrawThemeText(hTheme HTHEME, hdc HDC, iPartId, iStateId int32, pszText *uint16, iCharCount int32, dwTextFlags, dwTextFlags2 uint32, pRect *RECT) HRESULT { - ret, _, _ := syscall.Syscall9(drawThemeText, 9, - uintptr(hTheme), - uintptr(hdc), - uintptr(iPartId), - uintptr(iStateId), - uintptr(unsafe.Pointer(pszText)), - uintptr(iCharCount), - uintptr(dwTextFlags), - uintptr(dwTextFlags2), - uintptr(unsafe.Pointer(pRect))) - - return HRESULT(ret) -} - -func GetThemeTextExtent(hTheme HTHEME, hdc HDC, iPartId, iStateId int32, pszText *uint16, iCharCount int32, dwTextFlags uint32, pBoundingRect, pExtentRect *RECT) HRESULT { - ret, _, _ := syscall.Syscall9(getThemeTextExtent, 9, - uintptr(hTheme), - uintptr(hdc), - uintptr(iPartId), - uintptr(iStateId), - uintptr(unsafe.Pointer(pszText)), - uintptr(iCharCount), - uintptr(dwTextFlags), - uintptr(unsafe.Pointer(pBoundingRect)), - uintptr(unsafe.Pointer(pExtentRect))) - - return HRESULT(ret) -} - -func OpenThemeData(hwnd HWND, pszClassList *uint16) HTHEME { - ret, _, _ := syscall.SyscallN(openThemeData, - uintptr(hwnd), - uintptr(unsafe.Pointer(pszClassList)), - 0) - - return HTHEME(ret) -} - -func SetWindowTheme(hwnd HWND, pszSubAppName, pszSubIdList *uint16) HRESULT { - ret, _, _ := syscall.SyscallN(setWindowTheme, - uintptr(hwnd), - uintptr(unsafe.Pointer(pszSubAppName)), - uintptr(unsafe.Pointer(pszSubIdList))) - - return HRESULT(ret) -} diff --git a/v2/internal/frontend/desktop/windows/winc/w32/vars.go b/v2/internal/frontend/desktop/windows/winc/w32/vars.go deleted file mode 100644 index cb69f9d19..000000000 --- a/v2/internal/frontend/desktop/windows/winc/w32/vars.go +++ /dev/null @@ -1,16 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved. - * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved. - */ - -package w32 - -var ( - IID_NULL = &GUID{0x00000000, 0x0000, 0x0000, [8]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}} - IID_IUnknown = &GUID{0x00000000, 0x0000, 0x0000, [8]byte{0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}} - IID_IDispatch = &GUID{0x00020400, 0x0000, 0x0000, [8]byte{0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}} - IID_IConnectionPointContainer = &GUID{0xB196B284, 0xBAB4, 0x101A, [8]byte{0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07}} - IID_IConnectionPoint = &GUID{0xB196B286, 0xBAB4, 0x101A, [8]byte{0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07}} -) diff --git a/v2/internal/frontend/desktop/windows/winc/w32/wda.go b/v2/internal/frontend/desktop/windows/winc/w32/wda.go deleted file mode 100644 index 3925f2805..000000000 --- a/v2/internal/frontend/desktop/windows/winc/w32/wda.go +++ /dev/null @@ -1,47 +0,0 @@ -//go:build windows - -package w32 - -import ( - "syscall" - - "github.com/wailsapp/wails/v2/internal/system/operatingsystem" -) - -var user32 = syscall.NewLazyDLL("user32.dll") -var procSetWindowDisplayAffinity = user32.NewProc("SetWindowDisplayAffinity") -var windowsVersion, _ = operatingsystem.GetWindowsVersionInfo() - -const ( - WDA_NONE = 0x00000000 - WDA_MONITOR = 0x00000001 - WDA_EXCLUDEFROMCAPTURE = 0x00000011 // windows 10 2004+ -) - -func isWindowsVersionAtLeast(major, minor, build int) bool { - if windowsVersion.Major > major { - return true - } - if windowsVersion.Major < major { - return false - } - if windowsVersion.Minor > minor { - return true - } - if windowsVersion.Minor < minor { - return false - } - return windowsVersion.Build >= build -} - -func SetWindowDisplayAffinity(hwnd uintptr, affinity uint32) bool { - if affinity == WDA_EXCLUDEFROMCAPTURE && !isWindowsVersionAtLeast(10, 0, 19041) { - // for older windows versions, use WDA_MONITOR - affinity = WDA_MONITOR - } - ret, _, _ := procSetWindowDisplayAffinity.Call( - hwnd, - uintptr(affinity), - ) - return ret != 0 -} diff --git a/v2/internal/frontend/desktop/windows/winc/wndproc.go b/v2/internal/frontend/desktop/windows/winc/wndproc.go deleted file mode 100644 index 3db1652c3..000000000 --- a/v2/internal/frontend/desktop/windows/winc/wndproc.go +++ /dev/null @@ -1,154 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2013 Allen Dang. All Rights Reserved. - */ - -package winc - -import ( - "unsafe" - - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" -) - -var wmInvokeCallback uint32 - -func init() { - wmInvokeCallback = RegisterWindowMessage("WincV0.InvokeCallback") -} - -func genPoint(p uintptr) (x, y int) { - x = int(w32.LOWORD(uint32(p))) - y = int(w32.HIWORD(uint32(p))) - return -} - -func genMouseEventArg(wparam, lparam uintptr) *MouseEventData { - var data MouseEventData - data.Button = int(wparam) - data.X, data.Y = genPoint(lparam) - - return &data -} - -func genDropFilesEventArg(wparam uintptr) *DropFilesEventData { - hDrop := w32.HDROP(wparam) - - var data DropFilesEventData - _, fileCount := w32.DragQueryFile(hDrop, 0xFFFFFFFF) - data.Files = make([]string, fileCount) - - var i uint - for i = 0; i < fileCount; i++ { - data.Files[i], _ = w32.DragQueryFile(hDrop, i) - } - - data.X, data.Y, _ = w32.DragQueryPoint(hDrop) - w32.DragFinish(hDrop) - return &data -} - -func generalWndProc(hwnd w32.HWND, msg uint32, wparam, lparam uintptr) uintptr { - - switch msg { - case w32.WM_HSCROLL: - //println("case w32.WM_HSCROLL") - - case w32.WM_VSCROLL: - //println("case w32.WM_VSCROLL") - } - - if controller := GetMsgHandler(hwnd); controller != nil { - ret := controller.WndProc(msg, wparam, lparam) - - switch msg { - case w32.WM_NOTIFY: //Reflect notification to control - nm := (*w32.NMHDR)(unsafe.Pointer(lparam)) - if controller := GetMsgHandler(nm.HwndFrom); controller != nil { - ret := controller.WndProc(msg, wparam, lparam) - if ret != 0 { - w32.SetWindowLong(hwnd, w32.DWL_MSGRESULT, uint32(ret)) - return w32.TRUE - } - } - case w32.WM_COMMAND: - if lparam != 0 { //Reflect message to control - h := w32.HWND(lparam) - if controller := GetMsgHandler(h); controller != nil { - ret := controller.WndProc(msg, wparam, lparam) - if ret != 0 { - w32.SetWindowLong(hwnd, w32.DWL_MSGRESULT, uint32(ret)) - return w32.TRUE - } - } - } - case w32.WM_CLOSE: - controller.OnClose().Fire(NewEvent(controller, nil)) - case w32.WM_KILLFOCUS: - controller.OnKillFocus().Fire(NewEvent(controller, nil)) - case w32.WM_SETFOCUS: - controller.OnSetFocus().Fire(NewEvent(controller, nil)) - case w32.WM_DROPFILES: - controller.OnDropFiles().Fire(NewEvent(controller, genDropFilesEventArg(wparam))) - case w32.WM_CONTEXTMENU: - if wparam != 0 { //Reflect message to control - h := w32.HWND(wparam) - if controller := GetMsgHandler(h); controller != nil { - contextMenu := controller.ContextMenu() - x, y := genPoint(lparam) - - if contextMenu != nil { - id := w32.TrackPopupMenuEx( - contextMenu.hMenu, - w32.TPM_NOANIMATION|w32.TPM_RETURNCMD, - int32(x), - int32(y), - controller.Handle(), - nil) - - item := findMenuItemByID(int(id)) - if item != nil { - item.OnClick().Fire(NewEvent(controller, genMouseEventArg(wparam, lparam))) - } - return 0 - } - } - } - - case w32.WM_LBUTTONDOWN: - controller.OnLBDown().Fire(NewEvent(controller, genMouseEventArg(wparam, lparam))) - case w32.WM_LBUTTONUP: - controller.OnLBUp().Fire(NewEvent(controller, genMouseEventArg(wparam, lparam))) - case w32.WM_LBUTTONDBLCLK: - controller.OnLBDbl().Fire(NewEvent(controller, genMouseEventArg(wparam, lparam))) - case w32.WM_MBUTTONDOWN: - controller.OnMBDown().Fire(NewEvent(controller, genMouseEventArg(wparam, lparam))) - case w32.WM_MBUTTONUP: - controller.OnMBUp().Fire(NewEvent(controller, genMouseEventArg(wparam, lparam))) - case w32.WM_RBUTTONDOWN: - controller.OnRBDown().Fire(NewEvent(controller, genMouseEventArg(wparam, lparam))) - case w32.WM_RBUTTONUP: - controller.OnRBUp().Fire(NewEvent(controller, genMouseEventArg(wparam, lparam))) - case w32.WM_RBUTTONDBLCLK: - controller.OnRBDbl().Fire(NewEvent(controller, genMouseEventArg(wparam, lparam))) - case w32.WM_MOUSEMOVE: - controller.OnMouseMove().Fire(NewEvent(controller, genMouseEventArg(wparam, lparam))) - case w32.WM_PAINT: - canvas := NewCanvasFromHwnd(hwnd) - defer canvas.Dispose() - controller.OnPaint().Fire(NewEvent(controller, &PaintEventData{Canvas: canvas})) - case w32.WM_KEYUP: - controller.OnKeyUp().Fire(NewEvent(controller, &KeyUpEventData{int(wparam), int(lparam)})) - case w32.WM_SIZE: - x, y := genPoint(lparam) - controller.OnSize().Fire(NewEvent(controller, &SizeEventData{uint(wparam), x, y})) - case wmInvokeCallback: - controller.invokeCallbacks() - } - return ret - } - - return w32.DefWindowProc(hwnd, uint32(msg), wparam, lparam) -} diff --git a/v2/internal/frontend/desktop/windows/window.go b/v2/internal/frontend/desktop/windows/window.go index b04d61814..8087e37fa 100644 --- a/v2/internal/frontend/desktop/windows/window.go +++ b/v2/internal/frontend/desktop/windows/window.go @@ -3,94 +3,48 @@ package windows import ( - "sync" - "unsafe" - - "github.com/wailsapp/go-webview2/pkg/edge" - - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/win32" - "github.com/wailsapp/wails/v2/internal/system/operatingsystem" - - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc" - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" + "github.com/leaanthony/winc" + "github.com/leaanthony/winc/w32" "github.com/wailsapp/wails/v2/pkg/menu" "github.com/wailsapp/wails/v2/pkg/options" - winoptions "github.com/wailsapp/wails/v2/pkg/options/windows" + "sync" ) type Window struct { winc.Form - frontendOptions *options.App - applicationMenu *menu.Menu - minWidth, minHeight, maxWidth, maxHeight int - versionInfo *operatingsystem.WindowsVersionInfo - isDarkMode bool - isActive bool - hasBeenShown bool - - // Theme - theme winoptions.Theme - themeChanged bool - - framelessWithDecorations bool - - OnSuspend func() - OnResume func() - - chromium *edge.Chromium - - // isMinimizing indicates whether the window is currently being minimized - // 标识窗口是否处于最小化状态,用于解决最小化/恢复时的闪屏问题 - // This flag is used to prevent unnecessary redraws during minimize/restore transitions for frameless windows - // 此标志用于防止无边框窗口在最小化/恢复过程中的不必要重绘 - // Reference: https://github.com/wailsapp/wails/issues/3951 - isMinimizing bool + frontendOptions *options.App + applicationMenu *menu.Menu + m sync.Mutex + dispatchq []func() } -func NewWindow(parent winc.Controller, appoptions *options.App, versionInfo *operatingsystem.WindowsVersionInfo, chromium *edge.Chromium) *Window { - windowsOptions := appoptions.Windows - - result := &Window{ - frontendOptions: appoptions, - minHeight: appoptions.MinHeight, - minWidth: appoptions.MinWidth, - maxHeight: appoptions.MaxHeight, - maxWidth: appoptions.MaxWidth, - versionInfo: versionInfo, - isActive: true, - themeChanged: true, - chromium: chromium, - - framelessWithDecorations: appoptions.Frameless && (windowsOptions == nil || !windowsOptions.DisableFramelessWindowDecorations), - } +func NewWindow(parent winc.Controller, options *options.App) *Window { + result := new(Window) + result.frontendOptions = options result.SetIsForm(true) var exStyle int - if windowsOptions != nil { + if options.Windows != nil { exStyle = w32.WS_EX_CONTROLPARENT | w32.WS_EX_APPWINDOW - if windowsOptions.WindowIsTranslucent { + if options.Windows.WindowIsTranslucent { exStyle |= w32.WS_EX_NOREDIRECTIONBITMAP } } - if appoptions.AlwaysOnTop { + if options.AlwaysOnTop { exStyle |= w32.WS_EX_TOPMOST } var dwStyle = w32.WS_OVERLAPPEDWINDOW - - windowClassName := "wailsWindow" - if windowsOptions != nil && windowsOptions.WindowClassName != "" { - windowClassName = windowsOptions.WindowClassName + if options.Frameless { + dwStyle = w32.WS_POPUP } - winc.RegClassOnlyOnce(windowClassName) - handle := winc.CreateWindow(windowClassName, parent, uint(exStyle), uint(dwStyle)) - result.SetHandle(handle) - winc.RegMsgHandler(result) + winc.RegClassOnlyOnce("wailsWindow") + result.SetHandle(winc.CreateWindow("wailsWindow", parent, uint(exStyle), uint(dwStyle))) result.SetParent(parent) loadIcon := true - if windowsOptions != nil && windowsOptions.DisableWindowIcon == true { + if options.Windows != nil && options.Windows.DisableWindowIcon == true { loadIcon = false } if loadIcon { @@ -99,269 +53,65 @@ func NewWindow(parent winc.Controller, appoptions *options.App, versionInfo *ope } } - if appoptions.BackgroundColour != nil { - win32.SetBackgroundColour(result.Handle(), appoptions.BackgroundColour.R, appoptions.BackgroundColour.G, appoptions.BackgroundColour.B) + result.SetSize(options.Width, options.Height) + result.SetText(options.Title) + if options.Frameless == false && !options.Fullscreen { + result.EnableMaxButton(!options.DisableResize) + result.EnableSizable(!options.DisableResize) + result.SetMinSize(options.MinWidth, options.MinHeight) + result.SetMaxSize(options.MaxWidth, options.MaxHeight) } - if windowsOptions != nil { - result.theme = windowsOptions.Theme - } else { - result.theme = winoptions.SystemDefault - } - - result.SetSize(appoptions.Width, appoptions.Height) - result.SetText(appoptions.Title) - result.EnableSizable(!appoptions.DisableResize) - if !appoptions.Fullscreen { - result.EnableMaxButton(!appoptions.DisableResize) - result.SetMinSize(appoptions.MinWidth, appoptions.MinHeight) - result.SetMaxSize(appoptions.MaxWidth, appoptions.MaxHeight) - } - - result.UpdateTheme() - - if windowsOptions != nil { - result.OnSuspend = windowsOptions.OnSuspend - result.OnResume = windowsOptions.OnResume - if windowsOptions.WindowIsTranslucent { - if !win32.SupportsBackdropTypes() { - result.SetTranslucentBackground() - } else { - win32.EnableTranslucency(result.Handle(), win32.BackdropType(windowsOptions.BackdropType)) - } + if options.Windows != nil { + if options.Windows.WindowIsTranslucent { + result.SetTranslucentBackground() } - if windowsOptions.ContentProtection { - w32.SetWindowDisplayAffinity(result.Handle(), w32.WDA_EXCLUDEFROMCAPTURE) - } - - if windowsOptions.DisableWindowIcon { + if options.Windows.DisableWindowIcon { result.DisableIcon() } } // Dlg forces display of focus rectangles, as soon as the user starts to type. w32.SendMessage(result.Handle(), w32.WM_CHANGEUISTATE, w32.UIS_INITIALIZE, 0) + winc.RegMsgHandler(result) result.SetFont(winc.DefaultFont) - if appoptions.Menu != nil { - result.SetApplicationMenu(appoptions.Menu) + if options.Menu != nil { + result.SetApplicationMenu(options.Menu) } return result } -func (w *Window) Fullscreen() { - if w.Form.IsFullScreen() { - return - } - if w.framelessWithDecorations { - win32.ExtendFrameIntoClientArea(w.Handle(), false) - } - w.Form.SetMaxSize(0, 0) - w.Form.SetMinSize(0, 0) - w.Form.Fullscreen() -} +func (w *Window) Run() int { + var m w32.MSG -func (w *Window) UnFullscreen() { - if !w.Form.IsFullScreen() { - return - } - if w.framelessWithDecorations { - win32.ExtendFrameIntoClientArea(w.Handle(), true) - } - w.Form.UnFullscreen() - w.SetMinSize(w.minWidth, w.minHeight) - w.SetMaxSize(w.maxWidth, w.maxHeight) -} - -func (w *Window) Restore() { - if w.Form.IsFullScreen() { - w.UnFullscreen() - } else { - w.Form.Restore() - } -} - -func (w *Window) SetMinSize(minWidth int, minHeight int) { - w.minWidth = minWidth - w.minHeight = minHeight - w.Form.SetMinSize(minWidth, minHeight) -} - -func (w *Window) SetMaxSize(maxWidth int, maxHeight int) { - w.maxWidth = maxWidth - w.maxHeight = maxHeight - w.Form.SetMaxSize(maxWidth, maxHeight) -} - -func (w *Window) IsVisible() bool { - return win32.IsVisible(w.Handle()) -} - -func (w *Window) WndProc(msg uint32, wparam, lparam uintptr) uintptr { - - switch msg { - case win32.WM_POWERBROADCAST: - switch wparam { - case win32.PBT_APMSUSPEND: - if w.OnSuspend != nil { - w.OnSuspend() - } - case win32.PBT_APMRESUMEAUTOMATIC: - if w.OnResume != nil { - w.OnResume() + for w32.GetMessage(&m, 0, 0, 0) != 0 { + if m.Message == w32.WM_APP { + // Credit: https://github.com/jchv/go-webview2 + w.m.Lock() + q := append([]func(){}, w.dispatchq...) + w.dispatchq = []func(){} + w.m.Unlock() + for _, v := range q { + v() } } - case w32.WM_SETTINGCHANGE: - settingChanged := w32.UTF16PtrToString((*uint16)(unsafe.Pointer(lparam))) - if settingChanged == "ImmersiveColorSet" { - w.themeChanged = true - w.UpdateTheme() - } - return 0 - case w32.WM_NCLBUTTONDOWN: - w32.SetFocus(w.Handle()) - case w32.WM_MOVE, w32.WM_MOVING: - w.chromium.NotifyParentWindowPositionChanged() - case w32.WM_ACTIVATE: - //if !w.frontendOptions.Frameless { - w.themeChanged = true - if int(wparam) == w32.WA_INACTIVE { - w.isActive = false - w.UpdateTheme() - } else { - w.isActive = true - w.UpdateTheme() - //} - } - - case 0x02E0: //w32.WM_DPICHANGED - newWindowSize := (*w32.RECT)(unsafe.Pointer(lparam)) - w32.SetWindowPos(w.Handle(), - uintptr(0), - int(newWindowSize.Left), - int(newWindowSize.Top), - int(newWindowSize.Right-newWindowSize.Left), - int(newWindowSize.Bottom-newWindowSize.Top), - w32.SWP_NOZORDER|w32.SWP_NOACTIVATE) - } - - if w.frontendOptions.Frameless { - switch msg { - case w32.WM_ACTIVATE: - // If we want to have a frameless window but with the default frame decorations, extend the DWM client area. - // This Option is not affected by returning 0 in WM_NCCALCSIZE. - // As a result we have hidden the titlebar but still have the default window frame styling. - // See: https://docs.microsoft.com/en-us/windows/win32/api/dwmapi/nf-dwmapi-dwmextendframeintoclientarea#remarks - if w.framelessWithDecorations { - win32.ExtendFrameIntoClientArea(w.Handle(), true) - } - case w32.WM_NCCALCSIZE: - // Disable the standard frame by allowing the client area to take the full - // window size. - // See: https://docs.microsoft.com/en-us/windows/win32/winmsg/wm-nccalcsize#remarks - // This hides the titlebar and also disables the resizing from user interaction because the standard frame is not - // shown. We still need the WS_THICKFRAME style to enable resizing from the frontend. - if wparam != 0 { - rgrc := (*w32.RECT)(unsafe.Pointer(lparam)) - if w.Form.IsFullScreen() { - // In Full-Screen mode we don't need to adjust anything - w.SetPadding(edge.Rect{}) - } else if w.IsMaximised() { - // If the window is maximized we must adjust the client area to the work area of the monitor. Otherwise - // some content goes beyond the visible part of the monitor. - // Make sure to use the provided RECT to get the monitor, because during maximizig there might be - // a wrong monitor returned in multi screen mode when using MonitorFromWindow. - // See: https://github.com/MicrosoftEdge/WebView2Feedback/issues/2549 - monitor := w32.MonitorFromRect(rgrc, w32.MONITOR_DEFAULTTONULL) - - var monitorInfo w32.MONITORINFO - monitorInfo.CbSize = uint32(unsafe.Sizeof(monitorInfo)) - if monitor != 0 && w32.GetMonitorInfo(monitor, &monitorInfo) { - *rgrc = monitorInfo.RcWork - - maxWidth := w.frontendOptions.MaxWidth - maxHeight := w.frontendOptions.MaxHeight - if maxWidth > 0 || maxHeight > 0 { - var dpiX, dpiY uint - w32.GetDPIForMonitor(monitor, w32.MDT_EFFECTIVE_DPI, &dpiX, &dpiY) - - maxWidth := int32(winc.ScaleWithDPI(maxWidth, dpiX)) - if maxWidth > 0 && rgrc.Right-rgrc.Left > maxWidth { - rgrc.Right = rgrc.Left + maxWidth - } - - maxHeight := int32(winc.ScaleWithDPI(maxHeight, dpiY)) - if maxHeight > 0 && rgrc.Bottom-rgrc.Top > maxHeight { - rgrc.Bottom = rgrc.Top + maxHeight - } - } - } - w.SetPadding(edge.Rect{}) - } else { - // This is needed to workaround the resize flickering in frameless mode with WindowDecorations - // See: https://stackoverflow.com/a/6558508 - // The workaround originally suggests to decrese the bottom 1px, but that seems to bring up a thin - // white line on some Windows-Versions, due to DrawBackground using also this reduces ClientSize. - // Increasing the bottom also worksaround the flickering but we would loose 1px of the WebView content - // therefore let's pad the content with 1px at the bottom. - rgrc.Bottom += 1 - w.SetPadding(edge.Rect{Bottom: 1}) - } - return 0 - } + if !w.PreTranslateMessage(&m) { + w32.TranslateMessage(&m) + w32.DispatchMessage(&m) } } - return w.Form.WndProc(msg, wparam, lparam) + + w32.GdiplusShutdown() + return int(m.WParam) } -func (w *Window) IsMaximised() bool { - return win32.IsWindowMaximised(w.Handle()) -} - -func (w *Window) IsMinimised() bool { - return win32.IsWindowMinimised(w.Handle()) -} - -func (w *Window) IsNormal() bool { - return win32.IsWindowNormal(w.Handle()) -} - -func (w *Window) IsFullScreen() bool { - return win32.IsWindowFullScreen(w.Handle()) -} - -func (w *Window) SetTheme(theme winoptions.Theme) { - w.theme = theme - w.themeChanged = true - w.Invoke(func() { - w.UpdateTheme() - }) -} - -func invokeSync[T any](cba *Window, fn func() (T, error)) (res T, err error) { - var wg sync.WaitGroup - wg.Add(1) - cba.Invoke(func() { - res, err = fn() - wg.Done() - }) - wg.Wait() - return res, err -} - -// SetPadding is a filter that wraps chromium.SetPadding to prevent unnecessary redraws during minimize/restore -// 包装了chromium.SetPadding的过滤器,用于防止窗口最小化/恢复过程中的不必要重绘 -// This fixes window flickering when minimizing/restoring frameless windows -// 这修复了无边框窗口在最小化/恢复时的闪烁问题 -// Reference: https://github.com/wailsapp/wails/issues/3951 -func (w *Window) SetPadding(padding edge.Rect) { - // Skip SetPadding if window is being minimized to prevent flickering - // 如果窗口正在最小化,跳过设置padding以防止闪烁 - if w.isMinimizing { - return - } - w.chromium.SetPadding(padding) +func (w *Window) Dispatch(f func()) { + w.m.Lock() + w.dispatchq = append(w.dispatchq, f) + w.m.Unlock() + w32.PostMainThreadMessage(w32.WM_APP, 0, 0) } diff --git a/v2/internal/frontend/devserver/devserver.go b/v2/internal/frontend/devserver/devserver.go index 8a130890d..e73828c5d 100644 --- a/v2/internal/frontend/devserver/devserver.go +++ b/v2/internal/frontend/devserver/devserver.go @@ -1,5 +1,4 @@ //go:build dev -// +build dev // Package devserver provides a web-based frontend so that // it is possible to run a Wails app in a browsers. @@ -9,216 +8,278 @@ import ( "context" "encoding/json" "fmt" + "io/fs" "log" - "net/http" - "net/http/httputil" - "net/url" + "path/filepath" "strings" "sync" + "time" - "github.com/wailsapp/wails/v2/pkg/assetserver" - - "github.com/wailsapp/wails/v2/internal/frontend/runtime" - - "github.com/gorilla/websocket" - "github.com/labstack/echo/v4" + "github.com/gofiber/fiber/v2" + "github.com/gofiber/websocket/v2" "github.com/wailsapp/wails/v2/internal/binding" "github.com/wailsapp/wails/v2/internal/frontend" + "github.com/wailsapp/wails/v2/internal/frontend/assetserver" "github.com/wailsapp/wails/v2/internal/logger" "github.com/wailsapp/wails/v2/internal/menumanager" + "github.com/wailsapp/wails/v2/pkg/menu" "github.com/wailsapp/wails/v2/pkg/options" ) -type Screen = frontend.Screen - -var upgrader = websocket.Upgrader{ - ReadBufferSize: 1024, - WriteBufferSize: 1024, - CheckOrigin: func(r *http.Request) bool { return true }, -} - type DevWebServer struct { - server *echo.Echo + server *fiber.App ctx context.Context appoptions *options.App logger *logger.Logger appBindings *binding.Bindings dispatcher frontend.Dispatcher + assetServer *assetserver.BrowserAssetServer socketMutex sync.Mutex websocketClients map[*websocket.Conn]*sync.Mutex menuManager *menumanager.Manager starttime string // Desktop frontend - frontend.Frontend + desktopFrontend frontend.Frontend +} - devServerAddr string +func (d *DevWebServer) WindowReload() { + d.broadcast("reload") } func (d *DevWebServer) Run(ctx context.Context) error { d.ctx = ctx - d.server.GET("/wails/reload", d.handleReload) - d.server.GET("/wails/ipc", d.handleIPCWebSocket) - - assetServerConfig, err := assetserver.BuildAssetServerConfig(d.appoptions) - if err != nil { - return err - } - - var myLogger assetserver.Logger - if _logger := ctx.Value("logger"); _logger != nil { - myLogger = _logger.(*logger.Logger) - } - - var wsHandler http.Handler - - _fronendDevServerURL, _ := ctx.Value("frontenddevserverurl").(string) - if _fronendDevServerURL == "" { - assetdir, _ := ctx.Value("assetdir").(string) - d.server.GET("/wails/assetdir", func(c echo.Context) error { - return c.String(http.StatusOK, assetdir) - }) - - } else { - externalURL, err := url.Parse(_fronendDevServerURL) - if err != nil { - return err - } - - // WebSockets aren't currently supported in prod mode, so a WebSocket connection is the result of the - // FrontendDevServer e.g. Vite to support auto reloads. - // Therefore we direct WebSockets directly to the FrontendDevServer instead of returning a NotImplementedStatus. - wsHandler = httputil.NewSingleHostReverseProxy(externalURL) - } - - assetHandler, err := assetserver.NewAssetHandler(assetServerConfig, myLogger) - if err != nil { - log.Fatal(err) - } - - // Setup internal dev server - bindingsJSON, err := d.appBindings.ToJSON() - if err != nil { - log.Fatal(err) - } - - assetServer, err := assetserver.NewDevAssetServer(assetHandler, bindingsJSON, ctx.Value("assetdir") != nil, myLogger, runtime.RuntimeAssetsBundle) - if err != nil { - log.Fatal(err) - } - - d.server.Any("/*", func(c echo.Context) error { - if c.IsWebSocket() { - wsHandler.ServeHTTP(c.Response(), c.Request()) - } else { - assetServer.ServeHTTP(c.Response(), c.Request()) - } + d.server.Get("/wails/reload", func(fctx *fiber.Ctx) error { + d.WindowReload() + d.desktopFrontend.WindowReload() return nil }) - if devServerAddr := d.devServerAddr; devServerAddr != "" { + d.server.Get("/wails/ipc", websocket.New(func(c *websocket.Conn) { + d.newWebsocketSession(c) + locker := d.websocketClients[c] + // websocket.Conn bindings https://pkg.go.dev/github.com/fasthttp/websocket?tab=doc#pkg-index + var ( + mt int + msg []byte + err error + ) + + for { + if mt, msg, err = c.ReadMessage(); err != nil { + break + } + // We do not support drag in browsers + if string(msg) == "drag" { + continue + } + + // Notify the other browsers of "EventEmit" + if len(msg) > 2 && strings.HasPrefix(string(msg), "EE") { + d.notifyExcludingSender(msg, c) + } + + // Send the message to dispatch to the frontend + result, err := d.dispatcher.ProcessMessage(string(msg), d) + if err != nil { + d.logger.Error(err.Error()) + } + if result != "" { + locker.Lock() + if err = c.WriteMessage(mt, []byte(result)); err != nil { + locker.Unlock() + break + } + locker.Unlock() + } + + } + })) + + _devServerURL := ctx.Value("devserverurl") + if _devServerURL == "http://localhost:34115" { + // Setup internal dev server + _assetdir := ctx.Value("assetdir") + if _assetdir == nil { + return fmt.Errorf("no assetdir provided") + } + if _assetdir != nil { + assetdir := _assetdir.(string) + bindingsJSON, err := d.appBindings.ToJSON() + if err != nil { + log.Fatal(err) + } + d.assetServer, err = assetserver.NewBrowserAssetServer(assetdir, bindingsJSON, d.appoptions) + if err != nil { + log.Fatal(err) + } + absdir, err := filepath.Abs(assetdir) + if err != nil { + return err + } + d.LogDebug("Serving assets from: %s", absdir) + } + + d.server.Get("*", d.loadAsset) + // Start server - go func(server *echo.Echo, log *logger.Logger) { - err := server.Start(devServerAddr) + go func(server *fiber.App, log *logger.Logger) { + err := server.Listen("localhost:34115") if err != nil { log.Error(err.Error()) } d.LogDebug("Shutdown completed") }(d.server, d.logger) - d.LogDebug("Serving DevServer at http://%s", devServerAddr) + d.LogDebug("Serving application at http://localhost:34115") + + defer func() { + err := d.server.Shutdown() + if err != nil { + d.logger.Error(err.Error()) + } + }() } // Launch desktop app - err = d.Frontend.Run(ctx) + err := d.desktopFrontend.Run(ctx) + d.LogDebug("Starting shutdown") return err } -func (d *DevWebServer) WindowReload() { - d.broadcast("reload") - d.Frontend.WindowReload() +func (d *DevWebServer) Quit() { + d.desktopFrontend.Quit() } -func (d *DevWebServer) WindowReloadApp() { - d.broadcast("reloadapp") - d.Frontend.WindowReloadApp() +func (d *DevWebServer) OpenFileDialog(dialogOptions frontend.OpenDialogOptions) (string, error) { + return d.desktopFrontend.OpenFileDialog(dialogOptions) +} + +func (d *DevWebServer) OpenMultipleFilesDialog(dialogOptions frontend.OpenDialogOptions) ([]string, error) { + return d.OpenMultipleFilesDialog(dialogOptions) +} + +func (d *DevWebServer) OpenDirectoryDialog(dialogOptions frontend.OpenDialogOptions) (string, error) { + return d.OpenDirectoryDialog(dialogOptions) +} + +func (d *DevWebServer) SaveFileDialog(dialogOptions frontend.SaveDialogOptions) (string, error) { + return d.desktopFrontend.SaveFileDialog(dialogOptions) +} + +func (d *DevWebServer) MessageDialog(dialogOptions frontend.MessageDialogOptions) (string, error) { + return d.desktopFrontend.MessageDialog(dialogOptions) +} + +func (d *DevWebServer) WindowSetTitle(title string) { + d.desktopFrontend.WindowSetTitle(title) +} + +func (d *DevWebServer) WindowShow() { + d.desktopFrontend.WindowShow() +} + +func (d *DevWebServer) WindowHide() { + d.desktopFrontend.WindowHide() +} + +func (d *DevWebServer) WindowCenter() { + d.desktopFrontend.WindowCenter() +} + +func (d *DevWebServer) WindowMaximise() { + d.desktopFrontend.WindowMaximise() +} + +func (d *DevWebServer) WindowUnmaximise() { + d.desktopFrontend.WindowUnmaximise() +} + +func (d *DevWebServer) WindowMinimise() { + d.desktopFrontend.WindowMinimise() +} + +func (d *DevWebServer) WindowUnminimise() { + d.desktopFrontend.WindowUnminimise() +} + +func (d *DevWebServer) WindowSetPos(x int, y int) { + d.desktopFrontend.WindowSetPos(x, y) +} + +func (d *DevWebServer) WindowGetPos() (int, int) { + return d.desktopFrontend.WindowGetPos() +} + +func (d *DevWebServer) WindowSetSize(width int, height int) { + d.desktopFrontend.WindowSetSize(width, height) +} + +func (d *DevWebServer) WindowGetSize() (int, int) { + return d.desktopFrontend.WindowGetSize() +} + +func (d *DevWebServer) WindowSetMinSize(width int, height int) { + d.desktopFrontend.WindowSetMinSize(width, height) +} + +func (d *DevWebServer) WindowSetMaxSize(width int, height int) { + d.desktopFrontend.WindowSetMaxSize(width, height) +} + +func (d *DevWebServer) WindowFullscreen() { + d.desktopFrontend.WindowFullscreen() +} + +func (d *DevWebServer) WindowUnFullscreen() { + d.desktopFrontend.WindowUnFullscreen() +} + +func (d *DevWebServer) WindowSetRGBA(col *options.RGBA) { + d.desktopFrontend.WindowSetRGBA(col) +} + +func (d *DevWebServer) MenuSetApplicationMenu(menu *menu.Menu) { + d.desktopFrontend.MenuSetApplicationMenu(menu) +} + +func (d *DevWebServer) MenuUpdateApplicationMenu() { + d.desktopFrontend.MenuUpdateApplicationMenu() +} + +// BrowserOpenURL uses the system default browser to open the url +func (d *DevWebServer) BrowserOpenURL(url string) { + d.desktopFrontend.BrowserOpenURL(url) } func (d *DevWebServer) Notify(name string, data ...interface{}) { d.notify(name, data...) } -func (d *DevWebServer) handleReload(c echo.Context) error { - d.WindowReload() - return c.NoContent(http.StatusNoContent) -} - -func (d *DevWebServer) handleReloadApp(c echo.Context) error { - d.WindowReloadApp() - return c.NoContent(http.StatusNoContent) -} - -func (d *DevWebServer) handleIPCWebSocket(c echo.Context) error { - conn, err := upgrader.Upgrade(c.Response(), c.Request(), nil) +func (d *DevWebServer) loadAsset(ctx *fiber.Ctx) error { + data, mimetype, err := d.assetServer.Load(ctx.Path()) + if err != nil { + _, ok := err.(*fs.PathError) + if !ok { + return err + } + err := ctx.SendStatus(404) + if err != nil { + return err + } + return nil + } + err = ctx.SendStatus(200) if err != nil { - d.logger.Error("WebSocket upgrade failed %v", err) return err } - d.LogDebug(fmt.Sprintf("WebSocket client %p connected", conn)) - - d.socketMutex.Lock() - d.websocketClients[conn] = &sync.Mutex{} - locker := d.websocketClients[conn] - d.socketMutex.Unlock() - - var wg sync.WaitGroup - - defer func() { - wg.Wait() - d.socketMutex.Lock() - delete(d.websocketClients, conn) - d.socketMutex.Unlock() - d.LogDebug(fmt.Sprintf("WebSocket client %p disconnected", conn)) - conn.Close() - }() - - for { - _, msgBytes, err := conn.ReadMessage() - if err != nil { - break - } - - msg := string(msgBytes) - wg.Add(1) - - go func(m string) { - defer wg.Done() - - if m == "drag" { - return - } - - if len(m) > 2 && strings.HasPrefix(m, "EE") { - d.notifyExcludingSender([]byte(m), conn) - } - - result, err := d.dispatcher.ProcessMessage(m, d) - if err != nil { - d.logger.Error(err.Error()) - } - - if result != "" { - locker.Lock() - defer locker.Unlock() - if err := conn.WriteMessage(websocket.TextMessage, []byte(result)); err != nil { - d.logger.Error("Websocket write message failed %v", err) - } - } - }(msg) + ctx.Set("Content-Type", mimetype) + err = ctx.Send(data) + if err != nil { + return err } - return nil } @@ -226,6 +287,20 @@ func (d *DevWebServer) LogDebug(message string, args ...interface{}) { d.logger.Debug("[DevWebServer] "+message, args...) } +func (d *DevWebServer) newWebsocketSession(c *websocket.Conn) { + d.socketMutex.Lock() + defer d.socketMutex.Unlock() + c.SetCloseHandler(func(code int, text string) error { + d.socketMutex.Lock() + defer d.socketMutex.Unlock() + delete(d.websocketClients, c) + d.LogDebug(fmt.Sprintf("Websocket client %p disconnected", c)) + return nil + }) + d.websocketClients[c] = &sync.Mutex{} + d.LogDebug(fmt.Sprintf("Websocket client %p connected", c)) +} + type EventNotify struct { Name string `json:"name"` Data []interface{} `json:"data"` @@ -235,7 +310,7 @@ func (d *DevWebServer) broadcast(message string) { d.socketMutex.Lock() defer d.socketMutex.Unlock() for client, locker := range d.websocketClients { - go func(client *websocket.Conn, locker *sync.Mutex) { + go func() { if client == nil { d.logger.Error("Lost connection to websocket server") return @@ -248,7 +323,7 @@ func (d *DevWebServer) broadcast(message string) { return } locker.Unlock() - }(client, locker) + }() } } @@ -270,7 +345,7 @@ func (d *DevWebServer) broadcastExcludingSender(message string, sender *websocke d.socketMutex.Lock() defer d.socketMutex.Unlock() for client, locker := range d.websocketClients { - go func(client *websocket.Conn, locker *sync.Mutex) { + go func() { if client == sender { return } @@ -282,7 +357,7 @@ func (d *DevWebServer) broadcastExcludingSender(message string, sender *websocke return } locker.Unlock() - }(client, locker) + }() } } @@ -296,24 +371,24 @@ func (d *DevWebServer) notifyExcludingSender(eventMessage []byte, sender *websoc d.logger.Error(err.Error()) return } - d.Frontend.Notify(notifyMessage.Name, notifyMessage.Data...) + d.desktopFrontend.Notify(notifyMessage.Name, notifyMessage.Data...) } func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.Logger, appBindings *binding.Bindings, dispatcher frontend.Dispatcher, menuManager *menumanager.Manager, desktopFrontend frontend.Frontend) *DevWebServer { result := &DevWebServer{ - ctx: ctx, - Frontend: desktopFrontend, - appoptions: appoptions, - logger: myLogger, - appBindings: appBindings, - dispatcher: dispatcher, - server: echo.New(), + ctx: ctx, + desktopFrontend: desktopFrontend, + appoptions: appoptions, + logger: myLogger, + appBindings: appBindings, + dispatcher: dispatcher, + server: fiber.New(fiber.Config{ + + ReadTimeout: time.Second * 5, + DisableStartupMessage: true, + }), menuManager: menuManager, websocketClients: make(map[*websocket.Conn]*sync.Mutex), } - - result.devServerAddr, _ = ctx.Value("devserver").(string) - result.server.HideBanner = true - result.server.HidePort = true return result } diff --git a/v2/internal/frontend/dispatcher/calls.go b/v2/internal/frontend/dispatcher/calls.go index ba1062913..ef19c6030 100644 --- a/v2/internal/frontend/dispatcher/calls.go +++ b/v2/internal/frontend/dispatcher/calls.go @@ -3,9 +3,8 @@ package dispatcher import ( "encoding/json" "fmt" - "strings" - "github.com/wailsapp/wails/v2/internal/frontend" + "strings" ) type callMessage struct { @@ -15,6 +14,7 @@ type callMessage struct { } func (d *Dispatcher) processCallMessage(message string, sender frontend.Frontend) (string, error) { + var payload callMessage err := json.Unmarshal([]byte(message[1:]), &payload) if err != nil { @@ -49,12 +49,7 @@ func (d *Dispatcher) processCallMessage(message string, sender frontend.Frontend CallbackID: payload.CallbackID, } if err != nil { - // Use the error formatter if one was provided - if d.errfmt != nil { - callbackMessage.Err = d.errfmt(err) - } else { - callbackMessage.Err = err.Error() - } + callbackMessage.Err = err.Error() } else { callbackMessage.Result = result } @@ -71,7 +66,7 @@ func (d *Dispatcher) processCallMessage(message string, sender frontend.Frontend // CallbackMessage defines a message that contains the result of a call type CallbackMessage struct { Result interface{} `json:"result"` - Err any `json:"error"` + Err string `json:"error"` CallbackID string `json:"callbackid"` } diff --git a/v2/internal/frontend/dispatcher/dispatcher.go b/v2/internal/frontend/dispatcher/dispatcher.go index 24a43cfef..a3091f41c 100644 --- a/v2/internal/frontend/dispatcher/dispatcher.go +++ b/v2/internal/frontend/dispatcher/dispatcher.go @@ -1,53 +1,29 @@ package dispatcher import ( - "context" - "fmt" "github.com/pkg/errors" "github.com/wailsapp/wails/v2/internal/binding" "github.com/wailsapp/wails/v2/internal/frontend" "github.com/wailsapp/wails/v2/internal/logger" - "github.com/wailsapp/wails/v2/pkg/options" ) type Dispatcher struct { - log *logger.Logger - bindings *binding.Bindings - events frontend.Events - bindingsDB *binding.DB - ctx context.Context - errfmt options.ErrorFormatter - disablePanicRecovery bool + log *logger.Logger + bindings *binding.Bindings + events frontend.Events + bindingsDB *binding.DB } -func NewDispatcher(ctx context.Context, log *logger.Logger, bindings *binding.Bindings, events frontend.Events, errfmt options.ErrorFormatter, disablePanicRecovery bool) *Dispatcher { +func NewDispatcher(log *logger.Logger, bindings *binding.Bindings, events frontend.Events) *Dispatcher { return &Dispatcher{ - log: log, - bindings: bindings, - events: events, - bindingsDB: bindings.DB(), - ctx: ctx, - errfmt: errfmt, - disablePanicRecovery: disablePanicRecovery, + log: log, + bindings: bindings, + events: events, + bindingsDB: bindings.DB(), } } -func (d *Dispatcher) ProcessMessage(message string, sender frontend.Frontend) (_ string, err error) { - if !d.disablePanicRecovery { - defer func() { - if e := recover(); e != nil { - if errPanic, ok := e.(error); ok { - err = errPanic - } else { - err = fmt.Errorf("%v", e) - } - } - if err != nil { - d.log.Error("process message error: %s -> %s", message, err) - } - }() - } - +func (d *Dispatcher) ProcessMessage(message string, sender frontend.Frontend) (string, error) { if message == "" { return "", errors.New("No message to process") } @@ -58,23 +34,13 @@ func (d *Dispatcher) ProcessMessage(message string, sender frontend.Frontend) (_ return d.processEventMessage(message, sender) case 'C': return d.processCallMessage(message, sender) - case 'c': - return d.processSecureCallMessage(message, sender) case 'W': return d.processWindowMessage(message, sender) case 'B': return d.processBrowserMessage(message, sender) - case 'D': - return d.processDragAndDropMessage(message) case 'Q': sender.Quit() return "", nil - case 'S': - sender.Show() - return "", nil - case 'H': - sender.Hide() - return "", nil default: return "", errors.New("Unknown message from front end: " + message) } diff --git a/v2/internal/frontend/dispatcher/draganddrop.go b/v2/internal/frontend/dispatcher/draganddrop.go deleted file mode 100644 index 8266ec712..000000000 --- a/v2/internal/frontend/dispatcher/draganddrop.go +++ /dev/null @@ -1,38 +0,0 @@ -package dispatcher - -import ( - "errors" - "strconv" - "strings" -) - -func (d *Dispatcher) processDragAndDropMessage(message string) (string, error) { - switch message[1] { - case 'D': - msg := strings.SplitN(message[3:], ":", 3) - if len(msg) != 3 { - return "", errors.New("Invalid drag and drop Message: " + message) - } - - x, err := strconv.Atoi(msg[0]) - if err != nil { - return "", errors.New("Invalid x coordinate in drag and drop Message: " + message) - } - - y, err := strconv.Atoi(msg[1]) - if err != nil { - return "", errors.New("Invalid y coordinate in drag and drop Message: " + message) - } - - paths := strings.Split(msg[2], "\n") - if len(paths) < 1 { - return "", errors.New("Invalid drag and drop Message: " + message) - } - - d.events.Emit("wails:file-drop", x, y, paths) - default: - return "", errors.New("Invalid drag and drop Message: " + message) - } - - return "", nil -} diff --git a/v2/internal/frontend/dispatcher/events.go b/v2/internal/frontend/dispatcher/events.go index 12fe7b89e..cb308b803 100644 --- a/v2/internal/frontend/dispatcher/events.go +++ b/v2/internal/frontend/dispatcher/events.go @@ -3,7 +3,6 @@ package dispatcher import ( "encoding/json" "errors" - "github.com/wailsapp/wails/v2/internal/frontend" ) @@ -24,7 +23,7 @@ func (d *Dispatcher) processEventMessage(message string, sender frontend.Fronten if err != nil { return "", err } - go d.events.Notify(sender, eventMessage.Name, eventMessage.Data...) + go d.events.Notify(sender, eventMessage.Name, eventMessage.Data) case 'X': eventName := message[2:] go d.events.Off(eventName) diff --git a/v2/internal/frontend/dispatcher/securecalls.go b/v2/internal/frontend/dispatcher/securecalls.go deleted file mode 100644 index 8cdcdfb85..000000000 --- a/v2/internal/frontend/dispatcher/securecalls.go +++ /dev/null @@ -1,57 +0,0 @@ -package dispatcher - -import ( - "encoding/json" - "fmt" - - "github.com/wailsapp/wails/v2/internal/frontend" -) - -type secureCallMessage struct { - ID int `json:"id"` - Args []json.RawMessage `json:"args"` - CallbackID string `json:"callbackID"` -} - -func (d *Dispatcher) processSecureCallMessage(message string, sender frontend.Frontend) (string, error) { - var payload secureCallMessage - err := json.Unmarshal([]byte(message[1:]), &payload) - if err != nil { - return "", err - } - - var result interface{} - - // Lookup method - registeredMethod := d.bindingsDB.GetObfuscatedMethod(payload.ID) - - // Check we have it - if registeredMethod == nil { - return "", fmt.Errorf("method '%d' not registered", payload.ID) - } - - args, err2 := registeredMethod.ParseArgs(payload.Args) - if err2 != nil { - errmsg := fmt.Errorf("error parsing arguments: %s", err2.Error()) - result, _ := d.NewErrorCallback(errmsg.Error(), payload.CallbackID) - return result, errmsg - } - result, err = registeredMethod.Call(args) - - callbackMessage := &CallbackMessage{ - CallbackID: payload.CallbackID, - } - if err != nil { - callbackMessage.Err = err.Error() - } else { - callbackMessage.Result = result - } - messageData, err := json.Marshal(callbackMessage) - d.log.Trace("json call result data: %+v\n", string(messageData)) - if err != nil { - // what now? - d.log.Fatal(err.Error()) - } - - return "c" + string(messageData), nil -} diff --git a/v2/internal/frontend/dispatcher/systemcalls.go b/v2/internal/frontend/dispatcher/systemcalls.go index b090a416e..8d23d54bf 100644 --- a/v2/internal/frontend/dispatcher/systemcalls.go +++ b/v2/internal/frontend/dispatcher/systemcalls.go @@ -1,13 +1,9 @@ package dispatcher import ( - "encoding/json" - "errors" "fmt" "strings" - "github.com/wailsapp/wails/v2/pkg/runtime" - "github.com/wailsapp/wails/v2/internal/frontend" ) @@ -24,44 +20,19 @@ type size struct { } func (d *Dispatcher) processSystemCall(payload callMessage, sender frontend.Frontend) (interface{}, error) { + // Strip prefix name := strings.TrimPrefix(payload.Name, systemCallPrefix) switch name { case "WindowGetPos": - x, y := sender.WindowGetPosition() + x, y := sender.WindowGetPos() return &position{x, y}, nil case "WindowGetSize": w, h := sender.WindowGetSize() return &size{w, h}, nil - case "ScreenGetAll": - return sender.ScreenGetAll() - case "WindowIsMaximised": - return sender.WindowIsMaximised(), nil - case "WindowIsMinimised": - return sender.WindowIsMinimised(), nil - case "WindowIsNormal": - return sender.WindowIsNormal(), nil - case "WindowIsFullscreen": - return sender.WindowIsFullscreen(), nil - case "Environment": - return runtime.Environment(d.ctx), nil - case "ClipboardGetText": - t, err := sender.ClipboardGetText() - return t, err - case "ClipboardSetText": - if len(payload.Args) < 1 { - return false, errors.New("empty argument, cannot set clipboard") - } - var arg string - if err := json.Unmarshal(payload.Args[0], &arg); err != nil { - return false, err - } - if err := sender.ClipboardSetText(arg); err != nil { - return false, err - } - return true, nil default: return nil, fmt.Errorf("unknown systemcall message: %s", payload.Name) } + } diff --git a/v2/internal/frontend/dispatcher/window.go b/v2/internal/frontend/dispatcher/window.go index 7e136e069..204eefbd5 100644 --- a/v2/internal/frontend/dispatcher/window.go +++ b/v2/internal/frontend/dispatcher/window.go @@ -3,11 +3,10 @@ package dispatcher import ( "encoding/json" "errors" - "strconv" - "strings" - "github.com/wailsapp/wails/v2/internal/frontend" "github.com/wailsapp/wails/v2/pkg/options" + "strconv" + "strings" ) func (d *Dispatcher) mustAtoI(input string) int { @@ -20,25 +19,10 @@ func (d *Dispatcher) mustAtoI(input string) int { func (d *Dispatcher) processWindowMessage(message string, sender frontend.Frontend) (string, error) { if len(message) < 2 { - return "", errors.New("Invalid Window Message: " + message) + return "", errors.New("Invalid Event Message: " + message) } switch message[1] { - case 'A': - switch message[2:] { - case "SDT": - go sender.WindowSetSystemDefaultTheme() - case "LT": - go sender.WindowSetLightTheme() - case "DT": - go sender.WindowSetDarkTheme() - case "TP:0", "TP:1": - if message[2:] == "TP:0" { - go sender.WindowSetAlwaysOnTop(false) - } else if message[2:] == "TP:1" { - go sender.WindowSetAlwaysOnTop(true) - } - } case 'c': go sender.WindowCenter() case 'T': @@ -47,7 +31,7 @@ func (d *Dispatcher) processWindowMessage(message string, sender frontend.Fronte case 'F': go sender.WindowFullscreen() case 'f': - go sender.WindowUnfullscreen() + go sender.WindowUnFullscreen() case 's': parts := strings.Split(message[3:], ":") w := d.mustAtoI(parts[0]) @@ -57,24 +41,20 @@ func (d *Dispatcher) processWindowMessage(message string, sender frontend.Fronte parts := strings.Split(message[3:], ":") x := d.mustAtoI(parts[0]) y := d.mustAtoI(parts[1]) - go sender.WindowSetPosition(x, y) + go sender.WindowSetPos(x, y) case 'H': go sender.WindowHide() case 'S': go sender.WindowShow() - case 'R': - go sender.WindowReloadApp() case 'r': var rgba options.RGBA err := json.Unmarshal([]byte(message[3:]), &rgba) if err != nil { return "", err } - go sender.WindowSetBackgroundColour(&rgba) + go sender.WindowSetRGBA(&rgba) case 'M': go sender.WindowMaximise() - case 't': - go sender.WindowToggleMaximise() case 'U': go sender.WindowUnmaximise() case 'm': diff --git a/v2/internal/frontend/events.go b/v2/internal/frontend/events.go index f690d28a8..484e3607a 100644 --- a/v2/internal/frontend/events.go +++ b/v2/internal/frontend/events.go @@ -1,11 +1,10 @@ package frontend type Events interface { - On(eventName string, callback func(...interface{})) func() - OnMultiple(eventName string, callback func(...interface{}), counter int) func() - Once(eventName string, callback func(...interface{})) func() + On(eventName string, callback func(...interface{})) + OnMultiple(eventName string, callback func(...interface{}), counter int) + Once(eventName string, callback func(...interface{})) Emit(eventName string, data ...interface{}) Off(eventName string) - OffAll() Notify(sender Frontend, name string, data ...interface{}) } diff --git a/v2/internal/frontend/frontend.go b/v2/internal/frontend/frontend.go index 6b2ccbcae..2a4862868 100644 --- a/v2/internal/frontend/frontend.go +++ b/v2/internal/frontend/frontend.go @@ -10,7 +10,7 @@ import ( // FileFilter defines a filter for dialog boxes type FileFilter struct { DisplayName string // Filter information EG: "Image Files (*.jpg, *.png)" - Pattern string // semicolon separated list of extensions, EG: "*.jpg;*.png" + Pattern string // semi-colon separated list of extensions, EG: "*.jpg;*.png" } // OpenDialogOptions contains the options for the OpenDialogOptions runtime method @@ -19,6 +19,8 @@ type OpenDialogOptions struct { DefaultFilename string Title string Filters []FileFilter + AllowFiles bool + AllowDirectories bool ShowHiddenFiles bool CanCreateDirectories bool ResolvesAliases bool @@ -45,26 +47,6 @@ const ( QuestionDialog DialogType = "question" ) -type Screen struct { - IsCurrent bool `json:"isCurrent"` - IsPrimary bool `json:"isPrimary"` - - // Deprecated: Please use Size and PhysicalSize - Width int `json:"width"` - // Deprecated: Please use Size and PhysicalSize - Height int `json:"height"` - - // Size is the size of the screen in logical pixel space, used when setting sizes in Wails - Size ScreenSize `json:"size"` - // PhysicalSize is the physical size of the screen in pixels - PhysicalSize ScreenSize `json:"physicalSize"` -} - -type ScreenSize struct { - Width int `json:"width"` - Height int `json:"height"` -} - // MessageDialogOptions contains the options for the Message dialogs, EG Info, Warning, etc runtime methods type MessageDialogOptions struct { Type DialogType @@ -73,15 +55,11 @@ type MessageDialogOptions struct { Buttons []string DefaultButton string CancelButton string - Icon []byte + Icon string } type Frontend interface { - Run(ctx context.Context) error - RunMainLoop() - ExecJS(js string) - Hide() - Show() + Run(context.Context) error Quit() // Dialog @@ -96,47 +74,32 @@ type Frontend interface { WindowShow() WindowHide() WindowCenter() - WindowToggleMaximise() WindowMaximise() WindowUnmaximise() WindowMinimise() WindowUnminimise() - WindowSetAlwaysOnTop(b bool) - WindowSetPosition(x int, y int) - WindowGetPosition() (int, int) + WindowSetPos(x int, y int) + WindowGetPos() (int, int) WindowSetSize(width int, height int) WindowGetSize() (int, int) WindowSetMinSize(width int, height int) WindowSetMaxSize(width int, height int) WindowFullscreen() - WindowUnfullscreen() - WindowSetBackgroundColour(col *options.RGBA) + WindowUnFullscreen() + WindowSetRGBA(col *options.RGBA) WindowReload() - WindowReloadApp() - WindowSetSystemDefaultTheme() - WindowSetLightTheme() - WindowSetDarkTheme() - WindowIsMaximised() bool - WindowIsMinimised() bool - WindowIsNormal() bool - WindowIsFullscreen() bool - WindowClose() - WindowPrint() - - // Screen - ScreenGetAll() ([]Screen, error) // Menus MenuSetApplicationMenu(menu *menu.Menu) MenuUpdateApplicationMenu() + //SetTrayMenu(menu *menu.TrayMenu) + //UpdateTrayMenuLabel(menu *menu.TrayMenu) + //UpdateContextMenu(contextMenu *menu.ContextMenu) + //DeleteTrayMenuByID(id string) // Events Notify(name string, data ...interface{}) // Browser BrowserOpenURL(url string) - - // Clipboard - ClipboardGetText() (string, error) - ClipboardSetText(text string) error } diff --git a/v2/internal/frontend/originvalidator/originValidator.go b/v2/internal/frontend/originvalidator/originValidator.go deleted file mode 100644 index fd416f945..000000000 --- a/v2/internal/frontend/originvalidator/originValidator.go +++ /dev/null @@ -1,116 +0,0 @@ -package originvalidator - -import ( - "fmt" - "net/url" - "regexp" - "strings" -) - -type OriginValidator struct { - allowedOrigins []string -} - -// NewOriginValidator creates a new validator from a comma-separated string of allowed origins -func NewOriginValidator(startUrl *url.URL, allowedOriginsString string) *OriginValidator { - allowedOrigins := startUrl.Scheme + "://" + startUrl.Host - if allowedOriginsString != "" { - allowedOrigins += "," + allowedOriginsString - } - validator := &OriginValidator{} - validator.parseAllowedOrigins(allowedOrigins) - return validator -} - -// parseAllowedOrigins parses the comma-separated origins string -func (v *OriginValidator) parseAllowedOrigins(originsString string) { - if originsString == "" { - v.allowedOrigins = []string{} - return - } - - origins := strings.Split(originsString, ",") - var trimmedOrigins []string - - for _, origin := range origins { - trimmed := strings.TrimSuffix(strings.TrimSpace(origin), "/") - if trimmed != "" { - trimmedOrigins = append(trimmedOrigins, trimmed) - } - } - - v.allowedOrigins = trimmedOrigins -} - -// IsOriginAllowed checks if the given origin is allowed -func (v *OriginValidator) IsOriginAllowed(origin string) bool { - if origin == "" { - return false - } - - for _, allowedOrigin := range v.allowedOrigins { - if v.matchesOriginPattern(allowedOrigin, origin) { - return true - } - } - - return false -} - -// matchesOriginPattern checks if origin matches the pattern (supports wildcards) -func (v *OriginValidator) matchesOriginPattern(pattern, origin string) bool { - // Exact match - if pattern == origin { - return true - } - - // Wildcard pattern matching - if strings.Contains(pattern, "*") { - regexPattern := v.wildcardPatternToRegex(pattern) - matched, err := regexp.MatchString(regexPattern, origin) - if err != nil { - return false - } - return matched - } - - return false -} - -// wildcardPatternToRegex converts wildcard pattern to regex -func (v *OriginValidator) wildcardPatternToRegex(wildcardPattern string) string { - // Escape special regex characters except * - specialChars := []string{"\\", ".", "+", "?", "^", "$", "{", "}", "(", ")", "|", "[", "]"} - - escaped := wildcardPattern - for _, specialChar := range specialChars { - escaped = strings.ReplaceAll(escaped, specialChar, "\\"+specialChar) - } - - // Replace * with .* (matches any characters) - escaped = strings.ReplaceAll(escaped, "*", ".*") - - // Anchor the pattern to match the entire string - return "^" + escaped + "$" -} - -// GetOriginFromURL extracts origin from URL string -func (v *OriginValidator) GetOriginFromURL(urlString string) (string, error) { - if urlString == "" { - return "", fmt.Errorf("empty URL") - } - - parsedURL, err := url.Parse(urlString) - if err != nil { - return "", fmt.Errorf("invalid URL: %v", err) - } - - if parsedURL.Scheme == "" || parsedURL.Host == "" { - return "", fmt.Errorf("URL missing scheme or host") - } - - // Build origin (scheme + host) - origin := parsedURL.Scheme + "://" + parsedURL.Host - - return origin, nil -} diff --git a/v2/internal/frontend/runtime/assets.go b/v2/internal/frontend/runtime/assets.go deleted file mode 100644 index 465452a18..000000000 --- a/v2/internal/frontend/runtime/assets.go +++ /dev/null @@ -1,26 +0,0 @@ -//go:build !dev - -package runtime - -var RuntimeAssetsBundle = &RuntimeAssets{ - desktopIPC: DesktopIPC, - runtimeDesktopJS: RuntimeDesktopJS, -} - -type RuntimeAssets struct { - desktopIPC []byte - websocketIPC []byte - runtimeDesktopJS []byte -} - -func (r *RuntimeAssets) DesktopIPC() []byte { - return r.desktopIPC -} - -func (r *RuntimeAssets) WebsocketIPC() []byte { - return r.websocketIPC -} - -func (r *RuntimeAssets) RuntimeDesktopJS() []byte { - return r.runtimeDesktopJS -} diff --git a/v2/internal/frontend/runtime/assets_dev.go b/v2/internal/frontend/runtime/assets_dev.go deleted file mode 100644 index 5821403e0..000000000 --- a/v2/internal/frontend/runtime/assets_dev.go +++ /dev/null @@ -1,27 +0,0 @@ -//go:build dev - -package runtime - -var RuntimeAssetsBundle = &RuntimeAssets{ - desktopIPC: DesktopIPC, - websocketIPC: WebsocketIPC, - runtimeDesktopJS: RuntimeDesktopJS, -} - -type RuntimeAssets struct { - desktopIPC []byte - websocketIPC []byte - runtimeDesktopJS []byte -} - -func (r *RuntimeAssets) DesktopIPC() []byte { - return r.desktopIPC -} - -func (r *RuntimeAssets) WebsocketIPC() []byte { - return r.websocketIPC -} - -func (r *RuntimeAssets) RuntimeDesktopJS() []byte { - return r.runtimeDesktopJS -} diff --git a/v2/internal/frontend/runtime/desktop/calls.js b/v2/internal/frontend/runtime/desktop/calls.js index b41a014b2..7b20cadb7 100644 --- a/v2/internal/frontend/runtime/desktop/calls.js +++ b/v2/internal/frontend/runtime/desktop/calls.js @@ -92,61 +92,15 @@ export function Call(name, args, timeout) { callbackID, }; - // Make the call - window.WailsInvoke('C' + JSON.stringify(payload)); - } catch (e) { - // eslint-disable-next-line - console.error(e); - } - }); + // Make the call + window.WailsInvoke('C' + JSON.stringify(payload)); + } catch (e) { + // eslint-disable-next-line + console.error(e); + } + }); } -window.ObfuscatedCall = (id, args, timeout) => { - - // Timeout infinite by default - if (timeout == null) { - timeout = 0; - } - - // Create a promise - return new Promise(function (resolve, reject) { - - // Create a unique callbackID - var callbackID; - do { - callbackID = id + '-' + randomFunc(); - } while (callbacks[callbackID]); - - var timeoutHandle; - // Set timeout - if (timeout > 0) { - timeoutHandle = setTimeout(function () { - reject(Error('Call to method ' + id + ' timed out. Request ID: ' + callbackID)); - }, timeout); - } - - // Store callback - callbacks[callbackID] = { - timeoutHandle: timeoutHandle, - reject: reject, - resolve: resolve - }; - - try { - const payload = { - id, - args, - callbackID, - }; - - // Make the call - window.WailsInvoke('c' + JSON.stringify(payload)); - } catch (e) { - // eslint-disable-next-line - console.error(e); - } - }); -}; /** @@ -157,17 +111,20 @@ window.ObfuscatedCall = (id, args, timeout) => { * @param {string} incomingMessage */ export function Callback(incomingMessage) { + // Decode the message - Credit: https://stackoverflow.com/a/13865680 + //incomingMessage = decodeURIComponent(incomingMessage.replace(/\s+/g, '').replace(/[0-9a-f]{2}/g, '%$&')); + // Parse the message - let message; + var message; try { message = JSON.parse(incomingMessage); } catch (e) { const error = `Invalid JSON passed to callback: ${e.message}. Message: ${incomingMessage}`; - runtime.LogDebug(error); + wails.LogDebug(error); throw new Error(error); } - let callbackID = message.callbackid; - let callbackData = callbacks[callbackID]; + var callbackID = message.callbackid; + var callbackData = callbacks[callbackID]; if (!callbackData) { const error = `Callback '${callbackID}' not registered!!!`; console.error(error); // eslint-disable-line diff --git a/v2/internal/frontend/runtime/desktop/clipboard.js b/v2/internal/frontend/runtime/desktop/clipboard.js deleted file mode 100644 index 292cdc32f..000000000 --- a/v2/internal/frontend/runtime/desktop/clipboard.js +++ /dev/null @@ -1,34 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -/* jshint esversion: 9 */ - -import {Call} from "./calls"; - -/** - * Set the Size of the window - * - * @export - * @param {string} text - */ -export function ClipboardSetText(text) { - return Call(":wails:ClipboardSetText", [text]); -} - -/** - * Get the text content of the clipboard - * - * @export - * @return {Promise<{string}>} Text content of the clipboard - - */ -export function ClipboardGetText() { - return Call(":wails:ClipboardGetText"); -} \ No newline at end of file diff --git a/v2/internal/frontend/runtime/desktop/contextmenu.js b/v2/internal/frontend/runtime/desktop/contextmenu.js deleted file mode 100644 index b9c397546..000000000 --- a/v2/internal/frontend/runtime/desktop/contextmenu.js +++ /dev/null @@ -1,50 +0,0 @@ -/* ---default-contextmenu: auto; (default) will show the default context menu if contentEditable is true OR text has been selected OR element is input or textarea ---default-contextmenu: show; will always show the default context menu ---default-contextmenu: hide; will always hide the default context menu - -This rule is inherited like normal CSS rules, so nesting works as expected -*/ -export function processDefaultContextMenu(event) { - // Process default context menu - const element = event.target; - const computedStyle = window.getComputedStyle(element); - const defaultContextMenuAction = computedStyle.getPropertyValue("--default-contextmenu").trim(); - switch (defaultContextMenuAction) { - case "show": - return; - case "hide": - event.preventDefault(); - return; - default: - // Check if contentEditable is true - if (element.isContentEditable) { - return; - } - - // Check if text has been selected and action is on the selected elements - const selection = window.getSelection(); - const hasSelection = (selection.toString().length > 0) - if (hasSelection) { - for (let i = 0; i < selection.rangeCount; i++) { - const range = selection.getRangeAt(i); - const rects = range.getClientRects(); - for (let j = 0; j < rects.length; j++) { - const rect = rects[j]; - if (document.elementFromPoint(rect.left, rect.top) === element) { - return; - } - } - } - } - // Check if tagname is input or textarea - if (element.tagName === "INPUT" || element.tagName === "TEXTAREA") { - if (hasSelection || (!element.readOnly && !element.disabled)) { - return; - } - } - - // hide default context menu - event.preventDefault(); - } -} diff --git a/v2/internal/frontend/runtime/desktop/draganddrop.js b/v2/internal/frontend/runtime/desktop/draganddrop.js deleted file mode 100644 index e470e4823..000000000 --- a/v2/internal/frontend/runtime/desktop/draganddrop.js +++ /dev/null @@ -1,276 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -/* jshint esversion: 9 */ - -import {EventsOn, EventsOff} from "./events"; - -const flags = { - registered: false, - defaultUseDropTarget: true, - useDropTarget: true, - nextDeactivate: null, - nextDeactivateTimeout: null, -}; - -const DROP_TARGET_ACTIVE = "wails-drop-target-active"; - -/** - * checkStyleDropTarget checks if the style has the drop target attribute - * - * @param {CSSStyleDeclaration} style - * @returns - */ -function checkStyleDropTarget(style) { - const cssDropValue = style.getPropertyValue(window.wails.flags.cssDropProperty).trim(); - if (cssDropValue) { - if (cssDropValue === window.wails.flags.cssDropValue) { - return true; - } - // if the element has the drop target attribute, but - // the value is not correct, terminate finding process. - // This can be useful to block some child elements from being drop targets. - return false; - } - return false; -} - -/** - * onDragOver is called when the dragover event is emitted. - * @param {DragEvent} e - * @returns - */ -function onDragOver(e) { - // Check if this is an external file drop or internal HTML drag - // External file drops will have "Files" in the types array - // Internal HTML drags typically have "text/plain", "text/html" or custom types - const isFileDrop = e.dataTransfer.types.includes("Files"); - - // Only handle external file drops, let internal HTML5 drag-and-drop work normally - if (!isFileDrop) { - return; - } - - // ALWAYS prevent default for file drops to stop browser navigation - e.preventDefault(); - e.dataTransfer.dropEffect = 'copy'; - - if (!window.wails.flags.enableWailsDragAndDrop) { - return; - } - - if (!flags.useDropTarget) { - return; - } - - const element = e.target; - - // Trigger debounce function to deactivate drop targets - if(flags.nextDeactivate) flags.nextDeactivate(); - - // if the element is null or element is not child of drop target element - if (!element || !checkStyleDropTarget(getComputedStyle(element))) { - return; - } - - let currentElement = element; - while (currentElement) { - // check if currentElement is drop target element - if (checkStyleDropTarget(getComputedStyle(currentElement))) { - currentElement.classList.add(DROP_TARGET_ACTIVE); - } - currentElement = currentElement.parentElement; - } -} - -/** - * onDragLeave is called when the dragleave event is emitted. - * @param {DragEvent} e - * @returns - */ -function onDragLeave(e) { - // Check if this is an external file drop or internal HTML drag - const isFileDrop = e.dataTransfer.types.includes("Files"); - - // Only handle external file drops, let internal HTML5 drag-and-drop work normally - if (!isFileDrop) { - return; - } - - // ALWAYS prevent default for file drops to stop browser navigation - e.preventDefault(); - - if (!window.wails.flags.enableWailsDragAndDrop) { - return; - } - - if (!flags.useDropTarget) { - return; - } - - // Find the close drop target element - if (!e.target || !checkStyleDropTarget(getComputedStyle(e.target))) { - return null; - } - - // Trigger debounce function to deactivate drop targets - if(flags.nextDeactivate) flags.nextDeactivate(); - - // Use debounce technique to tacle dragleave events on overlapping elements and drop target elements - flags.nextDeactivate = () => { - // Deactivate all drop targets, new drop target will be activated on next dragover event - Array.from(document.getElementsByClassName(DROP_TARGET_ACTIVE)).forEach(el => el.classList.remove(DROP_TARGET_ACTIVE)); - // Reset nextDeactivate - flags.nextDeactivate = null; - // Clear timeout - if (flags.nextDeactivateTimeout) { - clearTimeout(flags.nextDeactivateTimeout); - flags.nextDeactivateTimeout = null; - } - } - - // Set timeout to deactivate drop targets if not triggered by next drag event - flags.nextDeactivateTimeout = setTimeout(() => { - if(flags.nextDeactivate) flags.nextDeactivate(); - }, 50); -} - -/** - * onDrop is called when the drop event is emitted. - * @param {DragEvent} e - * @returns - */ -function onDrop(e) { - // Check if this is an external file drop or internal HTML drag - const isFileDrop = e.dataTransfer.types.includes("Files"); - - // Only handle external file drops, let internal HTML5 drag-and-drop work normally - if (!isFileDrop) { - return; - } - - // ALWAYS prevent default for file drops to stop browser navigation - e.preventDefault(); - - if (!window.wails.flags.enableWailsDragAndDrop) { - return; - } - - if (CanResolveFilePaths()) { - // process files - let files = []; - if (e.dataTransfer.items) { - files = [...e.dataTransfer.items].map((item, i) => { - if (item.kind === 'file') { - return item.getAsFile(); - } - }); - } else { - files = [...e.dataTransfer.files]; - } - window.runtime.ResolveFilePaths(e.x, e.y, files); - } - - if (!flags.useDropTarget) { - return; - } - - // Trigger debounce function to deactivate drop targets - if(flags.nextDeactivate) flags.nextDeactivate(); - - // Deactivate all drop targets - Array.from(document.getElementsByClassName(DROP_TARGET_ACTIVE)).forEach(el => el.classList.remove(DROP_TARGET_ACTIVE)); -} - -/** - * postMessageWithAdditionalObjects checks the browser's capability of sending postMessageWithAdditionalObjects - * - * @returns {boolean} - * @constructor - */ -export function CanResolveFilePaths() { - return window.chrome?.webview?.postMessageWithAdditionalObjects != null; -} - -/** - * ResolveFilePaths sends drop events to the GO side to resolve file paths on windows. - * - * @param {number} x - * @param {number} y - * @param {any[]} files - * @constructor - */ -export function ResolveFilePaths(x, y, files) { - // Only for windows webview2 >= 1.0.1774.30 - // https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2webmessagereceivedeventargs2?view=webview2-1.0.1823.32#applies-to - if (window.chrome?.webview?.postMessageWithAdditionalObjects) { - chrome.webview.postMessageWithAdditionalObjects(`file:drop:${x}:${y}`, files); - } -} - -/** - * Callback for OnFileDrop returns a slice of file path strings when a drop is finished. - * - * @export - * @callback OnFileDropCallback - * @param {number} x - x coordinate of the drop - * @param {number} y - y coordinate of the drop - * @param {string[]} paths - A list of file paths. - */ - -/** - * OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings. - * - * @export - * @param {OnFileDropCallback} callback - Callback for OnFileDrop returns a slice of file path strings when a drop is finished. - * @param {boolean} [useDropTarget=true] - Only call the callback when the drop finished on an element that has the drop target style. (--wails-drop-target) - */ -export function OnFileDrop(callback, useDropTarget) { - if (typeof callback !== "function") { - console.error("DragAndDropCallback is not a function"); - return; - } - - if (flags.registered) { - return; - } - flags.registered = true; - - const uDTPT = typeof useDropTarget; - flags.useDropTarget = uDTPT === "undefined" || uDTPT !== "boolean" ? flags.defaultUseDropTarget : useDropTarget; - window.addEventListener('dragover', onDragOver); - window.addEventListener('dragleave', onDragLeave); - window.addEventListener('drop', onDrop); - - let cb = callback; - if (flags.useDropTarget) { - cb = function (x, y, paths) { - const element = document.elementFromPoint(x, y) - // if the element is null or element is not child of drop target element, return null - if (!element || !checkStyleDropTarget(getComputedStyle(element))) { - return null; - } - callback(x, y, paths); - } - } - - EventsOn("wails:file-drop", cb); -} - -/** - * OnFileDropOff removes the drag and drop listeners and handlers. - */ -export function OnFileDropOff() { - window.removeEventListener('dragover', onDragOver); - window.removeEventListener('dragleave', onDragLeave); - window.removeEventListener('drop', onDrop); - EventsOff("wails:file-drop"); - flags.registered = false; -} diff --git a/v2/internal/frontend/runtime/desktop/events.js b/v2/internal/frontend/runtime/desktop/events.js index e665a8aff..464a72c55 100644 --- a/v2/internal/frontend/runtime/desktop/events.js +++ b/v2/internal/frontend/runtime/desktop/events.js @@ -19,26 +19,24 @@ The electron alternative for Go class Listener { /** * Creates an instance of Listener. - * @param {string} eventName * @param {function} callback * @param {number} maxCallbacks * @memberof Listener */ - constructor(eventName, callback, maxCallbacks) { - this.eventName = eventName; + constructor(callback, maxCallbacks) { // Default of -1 means infinite - this.maxCallbacks = maxCallbacks || -1; + maxCallbacks = maxCallbacks || -1; // Callback invokes the callback with the given data // Returns true if this listener should be destroyed this.Callback = (data) => { callback.apply(null, data); // If maxCallbacks is infinite, return false (do not destroy) - if (this.maxCallbacks === -1) { + if (maxCallbacks === -1) { return false; } // Decrement maxCallbacks. Return true if now 0, otherwise false - this.maxCallbacks -= 1; - return this.maxCallbacks === 0; + maxCallbacks -= 1; + return maxCallbacks === 0; }; } } @@ -52,13 +50,11 @@ export const eventListeners = {}; * @param {string} eventName * @param {function} callback * @param {number} maxCallbacks - * @returns {function} A function to cancel the listener */ export function EventsOnMultiple(eventName, callback, maxCallbacks) { eventListeners[eventName] = eventListeners[eventName] || []; - const thisListener = new Listener(eventName, callback, maxCallbacks); + const thisListener = new Listener(callback, maxCallbacks); eventListeners[eventName].push(thisListener); - return () => listenerOff(thisListener); } /** @@ -67,10 +63,9 @@ export function EventsOnMultiple(eventName, callback, maxCallbacks) { * @export * @param {string} eventName * @param {function} callback - * @returns {function} A function to cancel the listener */ export function EventsOn(eventName, callback) { - return EventsOnMultiple(eventName, callback, -1); + EventsOnMultiple(eventName, callback, -1); } /** @@ -79,10 +74,9 @@ export function EventsOn(eventName, callback) { * @export * @param {string} eventName * @param {function} callback - * @returns {function} A function to cancel the listener */ export function EventsOnce(eventName, callback) { - return EventsOnMultiple(eventName, callback, 1); + EventsOnMultiple(eventName, callback, 1); } function notifyListeners(eventData) { @@ -90,17 +84,17 @@ function notifyListeners(eventData) { // Get the event name let eventName = eventData.name; - // Keep a list of listener indexes to destroy - const newEventListenerList = eventListeners[eventName]?.slice() || []; - // Check if we have any listeners for this event - if (newEventListenerList.length) { + if (eventListeners[eventName]) { + + // Keep a list of listener indexes to destroy + const newEventListenerList = eventListeners[eventName].slice(); // Iterate listeners - for (let count = newEventListenerList.length - 1; count >= 0; count -= 1) { + for (let count = 0; count < eventListeners[eventName].length; count += 1) { // Get next listener - const listener = newEventListenerList[count]; + const listener = eventListeners[eventName][count]; let data = eventData.data; @@ -113,11 +107,7 @@ function notifyListeners(eventData) { } // Update callbacks with new list of listeners - if (newEventListenerList.length === 0) { - removeListener(eventName); - } else { - eventListeners[eventName] = newEventListenerList; - } + eventListeners[eventName] = newEventListenerList; } } @@ -160,55 +150,10 @@ export function EventsEmit(eventName) { window.WailsInvoke('EE' + JSON.stringify(payload)); } -function removeListener(eventName) { +export function EventsOff(eventName) { // Remove local listeners - delete eventListeners[eventName]; + eventListeners.delete(eventName); // Notify Go listeners window.WailsInvoke('EX' + eventName); -} - -/** - * Off unregisters a listener previously registered with On, - * optionally multiple listeneres can be unregistered via `additionalEventNames` - * - * @param {string} eventName - * @param {...string} additionalEventNames - */ -export function EventsOff(eventName, ...additionalEventNames) { - removeListener(eventName) - - if (additionalEventNames.length > 0) { - additionalEventNames.forEach(eventName => { - removeListener(eventName) - }) - } -} - -/** - * Off unregisters all event listeners previously registered with On - */ - export function EventsOffAll() { - const eventNames = Object.keys(eventListeners); - eventNames.forEach(eventName => { - removeListener(eventName) - }) -} - -/** - * listenerOff unregisters a listener previously registered with EventsOn - * - * @param {Listener} listener - */ - function listenerOff(listener) { - const eventName = listener.eventName; - if (eventListeners[eventName] === undefined) return; - - // Remove local listener - eventListeners[eventName] = eventListeners[eventName].filter(l => l !== listener); - - // Clean up if there are no event listeners left - if (eventListeners[eventName].length === 0) { - removeListener(eventName); - } -} +} \ No newline at end of file diff --git a/v2/internal/frontend/runtime/desktop/events.test.js b/v2/internal/frontend/runtime/desktop/events.test.js deleted file mode 100644 index 69ece676f..000000000 --- a/v2/internal/frontend/runtime/desktop/events.test.js +++ /dev/null @@ -1,132 +0,0 @@ -import { EventsOnMultiple, EventsNotify, eventListeners, EventsOn, EventsEmit, EventsOffAll, EventsOnce, EventsOff } from './events' -import { expect, describe, it, beforeAll, vi, afterEach, beforeEach } from 'vitest' -// Edit an assertion and save to see HMR in action - -beforeAll(() => { - window.WailsInvoke = vi.fn(() => {}) -}) - -afterEach(() => { - EventsOffAll(); - vi.resetAllMocks() -}) - -describe('EventsOnMultiple', () => { - it('should stop after a specified number of times', () => { - const cb = vi.fn() - EventsOnMultiple('a', cb, 5) - EventsNotify(JSON.stringify({name: 'a', data: {}})) - EventsNotify(JSON.stringify({name: 'a', data: {}})) - EventsNotify(JSON.stringify({name: 'a', data: {}})) - EventsNotify(JSON.stringify({name: 'a', data: {}})) - EventsNotify(JSON.stringify({name: 'a', data: {}})) - EventsNotify(JSON.stringify({name: 'a', data: {}})) - expect(cb).toBeCalledTimes(5); - expect(window.WailsInvoke).toBeCalledTimes(1); - expect(window.WailsInvoke).toHaveBeenLastCalledWith('EXa'); - }) - - it('should return a cancel fn', () => { - const cb = vi.fn() - const cancel = EventsOnMultiple('a', cb, 5) - EventsNotify(JSON.stringify({name: 'a', data: {}})) - EventsNotify(JSON.stringify({name: 'a', data: {}})) - cancel() - EventsNotify(JSON.stringify({name: 'a', data: {}})) - EventsNotify(JSON.stringify({name: 'a', data: {}})) - expect(cb).toBeCalledTimes(2) - expect(window.WailsInvoke).toBeCalledTimes(1); - expect(window.WailsInvoke).toHaveBeenLastCalledWith('EXa'); - }) -}) - -describe('EventsOn', () => { - it('should create a listener with a count of -1', () => { - EventsOn('a', () => {}) - expect(eventListeners['a'][0].maxCallbacks).toBe(-1) - }) - - it('should return a cancel fn', () => { - const cancel = EventsOn('a', () => {}) - cancel(); - expect(window.WailsInvoke).toBeCalledTimes(1); - expect(window.WailsInvoke).toHaveBeenLastCalledWith('EXa'); - }) -}) - -describe('EventsOnce', () => { - it('should create a listener with a count of 1', () => { - EventsOnce('a', () => {}) - expect(eventListeners['a'][0].maxCallbacks).toBe(1) - }) - - it('should return a cancel fn', () => { - const cancel = EventsOn('a', () => {}) - cancel(); - expect(window.WailsInvoke).toBeCalledTimes(1); - expect(window.WailsInvoke).toHaveBeenLastCalledWith('EXa'); - }) -}) - -describe('EventsNotify', () => { - it('should inform a listener', () => { - const cb = vi.fn() - EventsOn('a', cb) - EventsNotify(JSON.stringify({name: 'a', data: ["one", "two", "three"]})) - expect(cb).toBeCalledTimes(1); - expect(cb).toHaveBeenLastCalledWith("one", "two", "three"); - expect(window.WailsInvoke).toBeCalledTimes(0); - }) -}) - -describe('EventsEmit', () => { - it('should emit an event', () => { - EventsEmit('a', 'one', 'two', 'three') - expect(window.WailsInvoke).toBeCalledTimes(1); - const calledWith = window.WailsInvoke.calls[0][0]; - expect(calledWith.slice(0, 2)).toBe('EE') - expect(JSON.parse(calledWith.slice(2))).toStrictEqual({data: ["one", "two", "three"], name: "a"}) - }) -}) - -describe('EventsOff', () => { - beforeEach(() => { - EventsOn('a', () => {}) - EventsOn('a', () => {}) - EventsOn('a', () => {}) - EventsOn('b', () => {}) - EventsOn('c', () => {}) - }) - - it('should cancel all event listeners for a single type', () => { - EventsOff('a') - expect(eventListeners['a']).toBeUndefined() - expect(eventListeners['b']).not.toBeUndefined() - expect(eventListeners['c']).not.toBeUndefined() - expect(window.WailsInvoke).toBeCalledTimes(1); - expect(window.WailsInvoke).toHaveBeenLastCalledWith('EXa'); - }) - - it('should cancel all event listeners for multiple types', () => { - EventsOff('a', 'b') - expect(eventListeners['a']).toBeUndefined() - expect(eventListeners['b']).toBeUndefined() - expect(eventListeners['c']).not.toBeUndefined() - expect(window.WailsInvoke).toBeCalledTimes(2); - expect(window.WailsInvoke.calls).toStrictEqual([['EXa'], ['EXb']]); - }) -}) - -describe('EventsOffAll', () => { - it('should cancel all event listeners', () => { - EventsOn('a', () => {}) - EventsOn('a', () => {}) - EventsOn('a', () => {}) - EventsOn('b', () => {}) - EventsOn('c', () => {}) - EventsOffAll() - expect(eventListeners).toStrictEqual({}) - expect(window.WailsInvoke).toBeCalledTimes(3); - expect(window.WailsInvoke.calls).toStrictEqual([['EXa'], ['EXb'], ['EXc']]); - }) -}) diff --git a/v2/internal/frontend/runtime/desktop/ipc.js b/v2/internal/frontend/runtime/desktop/ipc.js index 12a23bede..fee96ac38 100644 --- a/v2/internal/frontend/runtime/desktop/ipc.js +++ b/v2/internal/frontend/runtime/desktop/ipc.js @@ -23,9 +23,9 @@ The electron alternative for Go return obj; }; let windows = _deeptest(["chrome", "webview", "postMessage"]); - let mac_linux = _deeptest(["webkit", "messageHandlers", "external", "postMessage"]); + let mac = _deeptest(["webkit", "messageHandlers", "external", "postMessage"]); - if (!windows && !mac_linux) { + if (!windows && !mac) { console.error("Unsupported Platform"); return; } @@ -33,7 +33,7 @@ The electron alternative for Go if (windows) { window.WailsInvoke = (message) => window.chrome.webview.postMessage(message); } - if (mac_linux) { + if (mac) { window.WailsInvoke = (message) => window.webkit.messageHandlers.external.postMessage(message); } })(); \ No newline at end of file diff --git a/v2/internal/frontend/runtime/desktop/main.js b/v2/internal/frontend/runtime/desktop/main.js index 3fda7ef36..5e0b6feb5 100644 --- a/v2/internal/frontend/runtime/desktop/main.js +++ b/v2/internal/frontend/runtime/desktop/main.js @@ -9,58 +9,27 @@ The electron alternative for Go */ /* jshint esversion: 9 */ import * as Log from './log'; -import { - eventListeners, - EventsEmit, - EventsNotify, - EventsOff, - EventsOffAll, - EventsOn, - EventsOnce, - EventsOnMultiple, -} from "./events"; -import { Call, Callback, callbacks } from './calls'; -import { SetBindings } from "./bindings"; +import {eventListeners, EventsEmit, EventsNotify, EventsOff, EventsOn, EventsOnce, EventsOnMultiple} from './events'; +import {Callback, callbacks} from './calls'; +import {SetBindings} from "./bindings"; import * as Window from "./window"; -import * as Screen from "./screen"; import * as Browser from "./browser"; -import * as Clipboard from "./clipboard"; -import * as DragAndDrop from "./draganddrop"; -import * as ContextMenu from "./contextmenu"; + export function Quit() { window.WailsInvoke('Q'); } -export function Show() { - window.WailsInvoke('S'); -} - -export function Hide() { - window.WailsInvoke('H'); -} - -export function Environment() { - return Call(":wails:Environment"); -} - // The JS runtime window.runtime = { ...Log, ...Window, ...Browser, - ...Screen, - ...Clipboard, - ...DragAndDrop, EventsOn, EventsOnce, EventsOnMultiple, EventsEmit, EventsOff, - EventsOffAll, - Environment, - Show, - Hide, Quit }; @@ -73,147 +42,46 @@ window.wails = { callbacks, flags: { disableScrollbarDrag: false, - disableDefaultContextMenu: false, - enableResize: false, - defaultCursor: null, - borderThickness: 6, - shouldDrag: false, - deferDragToMouseMove: true, - cssDragProperty: "--wails-draggable", - cssDragValue: "drag", - cssDropProperty: "--wails-drop-target", - cssDropValue: "drop", - enableWailsDragAndDrop: false, + disableWailsDefaultContextMenu: false, } }; // Set the bindings -if (window.wailsbindings) { - window.wails.SetBindings(window.wailsbindings); - delete window.wails.SetBindings; -} +window.wails.SetBindings(window.wailsbindings); +delete window.wails.SetBindings; -// (bool) This is evaluated at build time in package.json -if (!DEBUG) { +// This is evaluated at build time in package.json +// const dev = 0; +// const production = 1; +if (ENV === 0) { delete window.wailsbindings; } -let dragTest = function(e) { - var val = window.getComputedStyle(e.target).getPropertyValue(window.wails.flags.cssDragProperty); - if (val) { - val = val.trim(); - } - - if (val !== window.wails.flags.cssDragValue) { - return false; - } - - if (e.buttons !== 1) { - // Do not start dragging if not the primary button has been clicked. - return false; - } - - if (e.detail !== 1) { - // Do not start dragging if more than once has been clicked, e.g. when double clicking - return false; - } - - return true; -}; - -window.wails.setCSSDragProperties = function(property, value) { - window.wails.flags.cssDragProperty = property; - window.wails.flags.cssDragValue = value; -} - -window.wails.setCSSDropProperties = function(property, value) { - window.wails.flags.cssDropProperty = property; - window.wails.flags.cssDropValue = value; -} - +// Setup drag handler +// Based on code from: https://github.com/patr0nus/DeskGap window.addEventListener('mousedown', (e) => { - // Check for resizing - if (window.wails.flags.resizeEdge) { - window.WailsInvoke("resize:" + window.wails.flags.resizeEdge); - e.preventDefault(); - return; - } - - if (dragTest(e)) { - if (window.wails.flags.disableScrollbarDrag) { - // This checks for clicks on the scroll bar - if (e.offsetX > e.target.clientWidth || e.offsetY > e.target.clientHeight) { - return; + let currentElement = e.target; + while (currentElement != null) { + if (currentElement.hasAttribute('data-wails-no-drag')) { + break; + } else if (currentElement.hasAttribute('data-wails-drag')) { + if (window.wails.flags.disableScrollbarDrag) { + // This checks for clicks on the scroll bar + if (e.offsetX > e.target.clientWidth || e.offsetY > e.target.clientHeight) { + break; + } } - } - if (window.wails.flags.deferDragToMouseMove) { - window.wails.flags.shouldDrag = true; - } else { - e.preventDefault() window.WailsInvoke("drag"); + e.preventDefault(); + break; } - return; - } else { - window.wails.flags.shouldDrag = false; + currentElement = currentElement.parentElement; } }); -window.addEventListener('mouseup', () => { - window.wails.flags.shouldDrag = false; -}); - -function setResize(cursor) { - document.documentElement.style.cursor = cursor || window.wails.flags.defaultCursor; - window.wails.flags.resizeEdge = cursor; -} - -window.addEventListener('mousemove', function(e) { - if (window.wails.flags.shouldDrag) { - window.wails.flags.shouldDrag = false; - let mousePressed = e.buttons !== undefined ? e.buttons : e.which; - if (mousePressed > 0) { - window.WailsInvoke("drag"); - return; - } - } - if (!window.wails.flags.enableResize) { - return; - } - if (window.wails.flags.defaultCursor == null) { - window.wails.flags.defaultCursor = document.documentElement.style.cursor; - } - if (window.outerWidth - e.clientX < window.wails.flags.borderThickness && window.outerHeight - e.clientY < window.wails.flags.borderThickness) { - document.documentElement.style.cursor = "se-resize"; - } - let rightBorder = window.outerWidth - e.clientX < window.wails.flags.borderThickness; - let leftBorder = e.clientX < window.wails.flags.borderThickness; - let topBorder = e.clientY < window.wails.flags.borderThickness; - let bottomBorder = window.outerHeight - e.clientY < window.wails.flags.borderThickness; - - // If we aren't on an edge, but were, reset the cursor to default - if (!leftBorder && !rightBorder && !topBorder && !bottomBorder && window.wails.flags.resizeEdge !== undefined) { - setResize(); - } else if (rightBorder && bottomBorder) setResize("se-resize"); - else if (leftBorder && bottomBorder) setResize("sw-resize"); - else if (leftBorder && topBorder) setResize("nw-resize"); - else if (topBorder && rightBorder) setResize("ne-resize"); - else if (leftBorder) setResize("w-resize"); - else if (topBorder) setResize("n-resize"); - else if (bottomBorder) setResize("s-resize"); - else if (rightBorder) setResize("e-resize"); - -}); - // Setup context menu hook -window.addEventListener('contextmenu', function(e) { - // always show the contextmenu in debug & dev - if (DEBUG) return; - - if (window.wails.flags.disableDefaultContextMenu) { +window.addEventListener('contextmenu', function (e) { + if (window.wails.flags.disableWailsDefaultContextMenu) { e.preventDefault(); - } else { - ContextMenu.processDefaultContextMenu(e); } -}); - -window.WailsInvoke("runtime:ready"); \ No newline at end of file +}); \ No newline at end of file diff --git a/v2/internal/frontend/runtime/desktop/screen.js b/v2/internal/frontend/runtime/desktop/screen.js deleted file mode 100644 index f2afb0506..000000000 --- a/v2/internal/frontend/runtime/desktop/screen.js +++ /dev/null @@ -1,25 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -/* jshint esversion: 9 */ - - -import {Call} from "./calls"; - - -/** - * Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system. - * @export - * @typedef {import('../wrapper/runtime').Screen} Screen - * @return {Promise<{Screen[]}>} The screens - */ -export function ScreenGetAll() { - return Call(":wails:ScreenGetAll"); -} diff --git a/v2/internal/frontend/runtime/desktop/window.js b/v2/internal/frontend/runtime/desktop/window.js index f24cdd9c2..448dc5e3d 100644 --- a/v2/internal/frontend/runtime/desktop/window.js +++ b/v2/internal/frontend/runtime/desktop/window.js @@ -17,22 +17,6 @@ export function WindowReload() { window.location.reload(); } -export function WindowReloadApp() { - window.WailsInvoke('WR'); -} - -export function WindowSetSystemDefaultTheme() { - window.WailsInvoke('WASDT'); -} - -export function WindowSetLightTheme() { - window.WailsInvoke('WALT'); -} - -export function WindowSetDarkTheme() { - window.WailsInvoke('WADT'); -} - /** * Place the window in the center of the screen * @@ -66,20 +50,10 @@ export function WindowFullscreen() { * * @export */ -export function WindowUnfullscreen() { +export function WindowUnFullscreen() { window.WailsInvoke('Wf'); } -/** - * Returns the state of the window, i.e. whether the window is in full screen mode or not. - * - * @export - * @return {Promise} The state of the window - */ -export function WindowIsFullscreen() { - return Call(":wails:WindowIsFullscreen"); -} - /** * Set the Size of the window * @@ -124,21 +98,6 @@ export function WindowSetMinSize(width, height) { window.WailsInvoke('Wz:' + width + ':' + height); } - - -/** - * Set the window AlwaysOnTop or not on top - * - * @export - */ -export function WindowSetAlwaysOnTop(b) { - - window.WailsInvoke('WATP:' + (b ? '1' : '0')); -} - - - - /** * Set the Position of the window * @@ -187,15 +146,6 @@ export function WindowMaximise() { window.WailsInvoke('WM'); } -/** - * Toggle the Maximise of the Window - * - * @export - */ -export function WindowToggleMaximise() { - window.WailsInvoke('Wt'); -} - /** * Unmaximise the Window * @@ -205,16 +155,6 @@ export function WindowUnmaximise() { window.WailsInvoke('WU'); } -/** - * Returns the state of the window, i.e. whether the window is maximised or not. - * - * @export - * @return {Promise} The state of the window - */ -export function WindowIsMaximised() { - return Call(":wails:WindowIsMaximised"); -} - /** * Minimise the Window * @@ -233,37 +173,15 @@ export function WindowUnminimise() { window.WailsInvoke('Wu'); } -/** - * Returns the state of the window, i.e. whether the window is minimised or not. - * - * @export - * @return {Promise} The state of the window - */ -export function WindowIsMinimised() { - return Call(":wails:WindowIsMinimised"); -} - -/** - * Returns the state of the window, i.e. whether the window is normal or not. - * - * @export - * @return {Promise} The state of the window - */ -export function WindowIsNormal() { - return Call(":wails:WindowIsNormal"); -} /** * Sets the background colour of the window * * @export - * @param {number} R Red - * @param {number} G Green - * @param {number} B Blue - * @param {number} A Alpha + * @param {RGBA} RGBA background colour */ -export function WindowSetBackgroundColour(R, G, B, A) { - let rgba = JSON.stringify({r: R || 0, g: G || 0, b: B || 0, a: A || 255}); +export function WindowSetRGBA(RGBA) { + let rgba = JSON.stringify(RGBA); window.WailsInvoke('Wr:' + rgba); } diff --git a/v2/internal/frontend/runtime/dev/main.js b/v2/internal/frontend/runtime/dev/main.js index c7f31b0f2..dac1a8782 100644 --- a/v2/internal/frontend/runtime/dev/main.js +++ b/v2/internal/frontend/runtime/dev/main.js @@ -14,17 +14,14 @@ import Overlay from "./Overlay.svelte"; import {hideOverlay, showOverlay} from "./store"; let components = {}; +window.ipcCallbacks = []; +window.ipcCallbackNames = []; -let wailsInvokeInternal = null; -let messageQueue = []; - -window.WailsInvoke = (message) => { - if (!wailsInvokeInternal) { - console.log("Queueing: " + message); - messageQueue.push(message); - return; - } - wailsInvokeInternal(message); +window.awaitIPC = (name, callback) => { + if (!window.ipcCallbacks) return callback; + log("Queuing '" + name + "' for execution once ipc ready."); + window.ipcCallbackNames.push(name); + window.ipcCallbacks.push(callback); }; window.addEventListener('DOMContentLoaded', () => { @@ -50,14 +47,15 @@ window.onbeforeunload = function () { connect(); function setupIPCBridge() { - wailsInvokeInternal = (message) => { + window.WailsInvoke = (message) => { websocket.send(message); }; - for (let i = 0; i < messageQueue.length; i++) { - console.log("sending queued message: " + messageQueue[i]); - window.WailsInvoke(messageQueue[i]); + for (let i = 0; i < window.ipcCallbacks.length; i++) { + log("Executing JS: " + window.ipcCallbackNames[i]); + window.ipcCallbacks[i](); } - messageQueue = []; + delete window.ipcCallbacks; + delete window.ipcCallbackNames; } // Handles incoming websocket connections @@ -80,7 +78,7 @@ function handleDisconnect() { function _connect() { if (websocket == null) { - websocket = new WebSocket((window.location.protocol.startsWith("https") ? "wss://" : "ws://") + window.location.host + "/wails/ipc"); + websocket = new WebSocket('ws://' + window.location.hostname + ':34115/wails/ipc'); websocket.onopen = handleConnect; websocket.onerror = function (e) { e.stopImmediatePropagation(); @@ -104,10 +102,6 @@ function handleMessage(message) { window.runtime.WindowReload(); return; } - if (message.data === "reloadapp") { - window.runtime.WindowReloadApp() - return; - } // As a bridge we ignore js and css injections switch (message.data[0]) { diff --git a/v2/internal/frontend/runtime/dev/package-lock.json b/v2/internal/frontend/runtime/dev/package-lock.json index e1bdd46df..4413e7f6b 100644 --- a/v2/internal/frontend/runtime/dev/package-lock.json +++ b/v2/internal/frontend/runtime/dev/package-lock.json @@ -1,885 +1,8 @@ { "name": "dev", "version": "2.0.0", - "lockfileVersion": 2, + "lockfileVersion": 1, "requires": true, - "packages": { - "": { - "name": "dev", - "version": "2.0.0", - "license": "ISC", - "devDependencies": { - "esbuild": "^0.12.17", - "esbuild-svelte": "^0.5.6", - "npm-run-all": "^4.1.5", - "svelte": "^3.49.0" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "engines": { - "node": ">=4.8" - } - }, - "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "dependencies": { - "object-keys": "^1.0.12" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.18.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.5.tgz", - "integrity": "sha512-DDggyJLoS91CkJjgauM5c0yZMjiD1uK3KcaCeAmffGwZ+ODWzOkPN4QwRbsK5DOFf06fywmyLci3ZD8jLGhVYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.3", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", - "object-inspect": "^1.11.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/esbuild": { - "version": "0.12.21", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.21.tgz", - "integrity": "sha512-7hyXbU3g94aREufI/5nls7Xcc+RGQeZWZApm6hoBaFvt2BPtpT4TjFMQ9Tb1jU8XyBGz00ShmiyflCogphMHFQ==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - } - }, - "node_modules/esbuild-svelte": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/esbuild-svelte/-/esbuild-svelte-0.5.6.tgz", - "integrity": "sha512-Bz8nU45FrT6sP/Tf3M2rQUuBGxnDSNSPZNIoYwSNt5H+wjSyo/t+zm94tgnOZsR6GgpDMbNQgo4jGbK0NLvEfw==", - "dev": true, - "dependencies": { - "svelte": "^3.42.6" - }, - "peerDependencies": { - "esbuild": ">=0.9.6" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "node_modules/internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.6.0.tgz", - "integrity": "sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "node_modules/load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/memorystream": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", - "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=", - "dev": true, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/npm-run-all": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", - "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "chalk": "^2.4.1", - "cross-spawn": "^6.0.5", - "memorystream": "^0.3.1", - "minimatch": "^3.0.4", - "pidtree": "^0.3.0", - "read-pkg": "^3.0.0", - "shell-quote": "^1.6.1", - "string.prototype.padend": "^3.0.0" - }, - "bin": { - "npm-run-all": "bin/npm-run-all/index.js", - "run-p": "bin/run-p/index.js", - "run-s": "bin/run-s/index.js" - }, - "engines": { - "node": ">= 4" - } - }, - "node_modules/object-inspect": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "dependencies": { - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pidtree": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", - "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", - "dev": true, - "bin": { - "pidtree": "bin/pidtree.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, - "dependencies": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dev": true, - "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shell-quote": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", - "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==", - "dev": true - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.10.tgz", - "integrity": "sha512-oie3/+gKf7QtpitB0LYLETe+k8SifzsX4KixvpOsbI6S0kRiRQ5MKOio8eMSAKQ17N06+wdEOXRiId+zOxo0hA==", - "dev": true - }, - "node_modules/string.prototype.padend": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.2.tgz", - "integrity": "sha512-/AQFLdYvePENU3W5rgurfWSMU6n+Ww8n/3cUt7E+vPBB/D7YDG8x+qjoFs4M/alR2bW7Qg6xMjVwWUOvuQ0XpQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/svelte": { - "version": "3.52.0", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.52.0.tgz", - "integrity": "sha512-FxcnEUOAVfr10vDU5dVgJN19IvqeHQCS1zfe8vayTfis9A2t5Fhx+JDe5uv/C3j//bB1umpLJ6quhgs9xyUbCQ==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - } - }, "dependencies": { "ansi-styles": { "version": "3.2.1", @@ -1028,6 +151,14 @@ "dev": true, "requires": { "svelte": "^3.42.6" + }, + "dependencies": { + "svelte": { + "version": "3.43.1", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.43.1.tgz", + "integrity": "sha512-nvPIaKx4HLzYlSdquISZpgG1Kqr2VAWQjZOt3Iwm3UhbqmA0LnSx4k1YpRMEhjQYW3ZCqQoK8Egto9tv4YewMA==", + "dev": true + } } }, "escape-string-regexp": { @@ -1235,9 +366,9 @@ "dev": true }, "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { "brace-expansion": "^1.1.7" @@ -1388,9 +519,9 @@ "dev": true }, "shell-quote": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", - "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz", + "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==", "dev": true }, "side-channel": { @@ -1483,9 +614,9 @@ } }, "svelte": { - "version": "3.52.0", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.52.0.tgz", - "integrity": "sha512-FxcnEUOAVfr10vDU5dVgJN19IvqeHQCS1zfe8vayTfis9A2t5Fhx+JDe5uv/C3j//bB1umpLJ6quhgs9xyUbCQ==", + "version": "3.42.2", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.42.2.tgz", + "integrity": "sha512-FOyNYKXb8wdE0Ot+Ctt2/OyDLsNBP8+V6PUE9ag6ZKeLslIou0LnMu1fhtWUA+HjzKTbAM1yj+4PFLtg/3pMJA==", "dev": true }, "unbox-primitive": { diff --git a/v2/internal/frontend/runtime/dev/package.json b/v2/internal/frontend/runtime/dev/package.json index 567681f32..a8fdade52 100644 --- a/v2/internal/frontend/runtime/dev/package.json +++ b/v2/internal/frontend/runtime/dev/package.json @@ -11,8 +11,8 @@ "license": "ISC", "devDependencies": { "esbuild": "^0.12.17", - "esbuild-svelte": "^0.5.6", "npm-run-all": "^4.1.5", - "svelte": "^3.49.0" + "svelte": "^3.42.2", + "esbuild-svelte": "^0.5.6" } } diff --git a/v2/internal/frontend/runtime/events.go b/v2/internal/frontend/runtime/events.go index 1f2e0a6e4..d5a63855f 100644 --- a/v2/internal/frontend/runtime/events.go +++ b/v2/internal/frontend/runtime/events.go @@ -1,16 +1,11 @@ package runtime import ( - "sync" - - "github.com/samber/lo" "github.com/wailsapp/wails/v2/internal/frontend" + "github.com/wailsapp/wails/v2/internal/logger" + "sync" ) -type Logger interface { - Trace(format string, v ...interface{}) -} - // eventListener holds a callback function which is invoked when // the event listened for is emitted. It has a counter which indicates // how the total number of events it is interested in. A value of zero @@ -23,7 +18,7 @@ type eventListener struct { // Events handles eventing type Events struct { - log Logger + log *logger.Logger frontend []frontend.Frontend // Go event listeners @@ -41,16 +36,16 @@ func (e *Events) Notify(sender frontend.Frontend, name string, data ...interface } } -func (e *Events) On(eventName string, callback func(...interface{})) func() { - return e.registerListener(eventName, callback, -1) +func (e *Events) On(eventName string, callback func(...interface{})) { + e.registerListener(eventName, callback, -1) } -func (e *Events) OnMultiple(eventName string, callback func(...interface{}), counter int) func() { - return e.registerListener(eventName, callback, counter) +func (e *Events) OnMultiple(eventName string, callback func(...interface{}), counter int) { + e.registerListener(eventName, callback, counter) } -func (e *Events) Once(eventName string, callback func(...interface{})) func() { - return e.registerListener(eventName, callback, 1) +func (e *Events) Once(eventName string, callback func(...interface{})) { + e.registerListener(eventName, callback, 1) } func (e *Events) Emit(eventName string, data ...interface{}) { @@ -64,16 +59,8 @@ func (e *Events) Off(eventName string) { e.unRegisterListener(eventName) } -func (e *Events) OffAll() { - e.notifyLock.Lock() - for eventName := range e.listeners { - delete(e.listeners, eventName) - } - e.notifyLock.Unlock() -} - // NewEvents creates a new log subsystem -func NewEvents(log Logger) *Events { +func NewEvents(log *logger.Logger) *Events { result := &Events{ log: log, listeners: make(map[string][]*eventListener), @@ -82,7 +69,7 @@ func NewEvents(log Logger) *Events { } // registerListener provides a means of subscribing to events of type "eventName" -func (e *Events) registerListener(eventName string, callback func(...interface{}), counter int) func() { +func (e *Events) registerListener(eventName string, callback func(...interface{}), counter int) { // Create new eventListener thisListener := &eventListener{ callback: callback, @@ -93,17 +80,6 @@ func (e *Events) registerListener(eventName string, callback func(...interface{} // Append the new listener to the listeners slice e.listeners[eventName] = append(e.listeners[eventName], thisListener) e.notifyLock.Unlock() - return func() { - e.notifyLock.Lock() - defer e.notifyLock.Unlock() - - if _, ok := e.listeners[eventName]; !ok { - return - } - e.listeners[eventName] = lo.Filter(e.listeners[eventName], func(l *eventListener, i int) bool { - return l != thisListener - }) - } } // unRegisterListener provides a means of unsubscribing to events of type "eventName" @@ -116,8 +92,6 @@ func (e *Events) unRegisterListener(eventName string) { // Notify backend for the given event name func (e *Events) notifyBackend(eventName string, data ...interface{}) { - e.notifyLock.Lock() - defer e.notifyLock.Unlock() // Get list of event listeners listeners := e.listeners[eventName] @@ -126,6 +100,9 @@ func (e *Events) notifyBackend(eventName string, data ...interface{}) { return } + // Lock the listeners + e.notifyLock.Lock() + // We have a dirty flag to indicate that there are items to delete itemsToDelete := false @@ -143,7 +120,7 @@ func (e *Events) notifyBackend(eventName string, data ...interface{}) { } // Do we have items to delete? - if itemsToDelete { + if itemsToDelete == true { // Create a new Listeners slice var newListeners []*eventListener @@ -163,6 +140,9 @@ func (e *Events) notifyBackend(eventName string, data ...interface{}) { delete(e.listeners, eventName) } } + + // Unlock + e.notifyLock.Unlock() } func (e *Events) AddFrontend(appFrontend frontend.Frontend) { diff --git a/v2/internal/frontend/runtime/events_test.go b/v2/internal/frontend/runtime/events_test.go deleted file mode 100644 index 5795befd0..000000000 --- a/v2/internal/frontend/runtime/events_test.go +++ /dev/null @@ -1,38 +0,0 @@ -package runtime_test - -import ( - "fmt" - "github.com/wailsapp/wails/v2/internal/frontend/runtime" - "sync" - "testing" -) -import "github.com/matryer/is" - -type mockLogger struct { - Log string -} - -func (t *mockLogger) Trace(format string, args ...interface{}) { - t.Log = fmt.Sprintf(format, args...) -} - -func Test_EventsOn(t *testing.T) { - i := is.New(t) - l := &mockLogger{} - manager := runtime.NewEvents(l) - - // Test On - eventName := "test" - counter := 0 - var wg sync.WaitGroup - wg.Add(1) - manager.On(eventName, func(args ...interface{}) { - // This is called in a goroutine - counter++ - wg.Done() - }) - manager.Emit(eventName, "test payload") - wg.Wait() - i.Equal(1, counter) - -} diff --git a/v2/internal/frontend/runtime/ipc.go b/v2/internal/frontend/runtime/ipc.go index 8f7631c42..1f8873796 100644 --- a/v2/internal/frontend/runtime/ipc.go +++ b/v2/internal/frontend/runtime/ipc.go @@ -1,3 +1,5 @@ +//go:build darwin || windows + package runtime import _ "embed" diff --git a/v2/internal/frontend/runtime/ipc.js b/v2/internal/frontend/runtime/ipc.js index 257d503f4..6947faa84 100644 --- a/v2/internal/frontend/runtime/ipc.js +++ b/v2/internal/frontend/runtime/ipc.js @@ -1 +1 @@ -(()=>{(function(){let n=function(e){for(var s=window[e.shift()];s&&e.length;)s=s[e.shift()];return s},o=n(["chrome","webview","postMessage"]),t=n(["webkit","messageHandlers","external","postMessage"]);if(!o&&!t){console.error("Unsupported Platform");return}o&&(window.WailsInvoke=e=>window.chrome.webview.postMessage(e)),t&&(window.WailsInvoke=e=>window.webkit.messageHandlers.external.postMessage(e))})();})(); +(()=>{(function(){let o=function(e){for(var s=window[e.shift()];s&&e.length;)s=s[e.shift()];return s},t=o(["chrome","webview","postMessage"]),n=o(["webkit","messageHandlers","external","postMessage"]);if(!t&&!n){console.error("Unsupported Platform");return}t&&(window.WailsInvoke=e=>window.chrome.webview.postMessage(e)),n&&(window.WailsInvoke=e=>window.webkit.messageHandlers.external.postMessage(e))})();})(); diff --git a/v2/internal/frontend/runtime/ipc_websocket.go b/v2/internal/frontend/runtime/ipc_websocket.go index f8722ed3f..e0b5ca1f2 100644 --- a/v2/internal/frontend/runtime/ipc_websocket.go +++ b/v2/internal/frontend/runtime/ipc_websocket.go @@ -1,5 +1,4 @@ //go:build dev -// +build dev package runtime diff --git a/v2/internal/frontend/runtime/ipc_websocket.js b/v2/internal/frontend/runtime/ipc_websocket.js index 1ca048df1..16774652b 100644 --- a/v2/internal/frontend/runtime/ipc_websocket.js +++ b/v2/internal/frontend/runtime/ipc_websocket.js @@ -1,10 +1,10 @@ -(()=>{function D(t){console.log("%c wails dev %c "+t+" ","background: #aa0000; color: #fff; border-radius: 3px 0px 0px 3px; padding: 1px; font-size: 0.7rem","background: #009900; color: #fff; border-radius: 0px 3px 3px 0px; padding: 1px; font-size: 0.7rem")}function _(){}var A=t=>t;function N(t){return t()}function it(){return Object.create(null)}function b(t){t.forEach(N)}function w(t){return typeof t=="function"}function L(t,e){return t!=t?e==e:t!==e||t&&typeof t=="object"||typeof t=="function"}function ot(t){return Object.keys(t).length===0}function rt(t,...e){if(t==null)return _;let n=t.subscribe(...e);return n.unsubscribe?()=>n.unsubscribe():n}function st(t,e,n){t.$$.on_destroy.push(rt(e,n))}var ct=typeof window!="undefined",Ot=ct?()=>window.performance.now():()=>Date.now(),P=ct?t=>requestAnimationFrame(t):_;var x=new Set;function lt(t){x.forEach(e=>{e.c(t)||(x.delete(e),e.f())}),x.size!==0&&P(lt)}function Dt(t){let e;return x.size===0&&P(lt),{promise:new Promise(n=>{x.add(e={c:t,f:n})}),abort(){x.delete(e)}}}var ut=!1;function At(){ut=!0}function Lt(){ut=!1}function Bt(t,e){t.appendChild(e)}function at(t,e,n){let i=R(t);if(!i.getElementById(e)){let o=B("style");o.id=e,o.textContent=n,ft(i,o)}}function R(t){if(!t)return document;let e=t.getRootNode?t.getRootNode():t.ownerDocument;return e&&e.host?e:t.ownerDocument}function Tt(t){let e=B("style");return ft(R(t),e),e.sheet}function ft(t,e){return Bt(t.head||t,e),e.sheet}function W(t,e,n){t.insertBefore(e,n||null)}function S(t){t.parentNode.removeChild(t)}function B(t){return document.createElement(t)}function Jt(t){return document.createTextNode(t)}function dt(){return Jt("")}function ht(t,e,n){n==null?t.removeAttribute(e):t.getAttribute(e)!==n&&t.setAttribute(e,n)}function zt(t){return Array.from(t.childNodes)}function Ht(t,e,{bubbles:n=!1,cancelable:i=!1}={}){let o=document.createEvent("CustomEvent");return o.initCustomEvent(t,n,i,e),o}var T=new Map,J=0;function Gt(t){let e=5381,n=t.length;for(;n--;)e=(e<<5)-e^t.charCodeAt(n);return e>>>0}function qt(t,e){let n={stylesheet:Tt(e),rules:{}};return T.set(t,n),n}function pt(t,e,n,i,o,c,s,l=0){let f=16.666/i,r=`{ -`;for(let g=0;g<=1;g+=f){let F=e+(n-e)*c(g);r+=g*100+`%{${s(F,1-F)}} +(()=>{function F(t){console.log("%c wails dev %c "+t+" ","background: #aa0000; color: #fff; border-radius: 3px 0px 0px 3px; padding: 1px; font-size: 0.7rem","background: #009900; color: #fff; border-radius: 0px 3px 3px 0px; padding: 1px; font-size: 0.7rem")}function _(){}var j=t=>t;function G(t){return t()}function tt(){return Object.create(null)}function b(t){t.forEach(G)}function S(t){return typeof t=="function"}function O(t,e){return t!=t?e==e:t!==e||t&&typeof t=="object"||typeof t=="function"}function et(t){return Object.keys(t).length===0}function nt(t,...e){if(t==null)return _;let n=t.subscribe(...e);return n.unsubscribe?()=>n.unsubscribe():n}function it(t,e,n){t.$$.on_destroy.push(nt(e,n))}var ot=typeof window!="undefined",Et=ot?()=>window.performance.now():()=>Date.now(),q=ot?t=>requestAnimationFrame(t):_;var x=new Set;function rt(t){x.forEach(e=>{e.c(t)||(x.delete(e),e.f())}),x.size!==0&&q(rt)}function jt(t){let e;return x.size===0&&q(rt),{promise:new Promise(n=>{x.add(e={c:t,f:n})}),abort(){x.delete(e)}}}var st=!1;function Ot(){st=!0}function Dt(){st=!1}function At(t,e){t.appendChild(e)}function ct(t,e,n){let i=K(t);if(!i.getElementById(e)){let o=A("style");o.id=e,o.textContent=n,lt(i,o)}}function K(t){if(!t)return document;let e=t.getRootNode?t.getRootNode():t.ownerDocument;return e.host?e:document}function Lt(t){let e=A("style");return lt(K(t),e),e}function lt(t,e){At(t.head||t,e)}function P(t,e,n){t.insertBefore(e,n||null)}function D(t){t.parentNode.removeChild(t)}function A(t){return document.createElement(t)}function Bt(t){return document.createTextNode(t)}function ut(){return Bt("")}function at(t,e,n){n==null?t.removeAttribute(e):t.getAttribute(e)!==n&&t.setAttribute(e,n)}function Jt(t){return Array.from(t.childNodes)}function zt(t,e,n=!1){let i=document.createEvent("CustomEvent");return i.initCustomEvent(t,n,!1,e),i}var N=new Set,L=0;function Tt(t){let e=5381,n=t.length;for(;n--;)e=(e<<5)-e^t.charCodeAt(n);return e>>>0}function ft(t,e,n,i,o,c,s,l=0){let a=16.666/i,r=`{ +`;for(let g=0;g<=1;g+=a){let v=e+(n-e)*c(g);r+=g*100+`%{${s(v,1-v)}} `}let y=r+`100% {${s(n,1-n)}} -}`,a=`__svelte_${Gt(y)}_${l}`,u=R(t),{stylesheet:h,rules:p}=T.get(u)||qt(u,t);p[a]||(p[a]=!0,h.insertRule(`@keyframes ${a} ${y}`,h.cssRules.length));let v=t.style.animation||"";return t.style.animation=`${v?`${v}, `:""}${a} ${i}ms linear ${o}ms 1 both`,J+=1,a}function Kt(t,e){let n=(t.style.animation||"").split(", "),i=n.filter(e?c=>c.indexOf(e)<0:c=>c.indexOf("__svelte")===-1),o=n.length-i.length;o&&(t.style.animation=i.join(", "),J-=o,J||Nt())}function Nt(){P(()=>{J||(T.forEach(t=>{let{ownerNode:e}=t.stylesheet;e&&S(e)}),T.clear())})}var V;function C(t){V=t}var k=[];var _t=[],z=[],mt=[],Pt=Promise.resolve(),U=!1;function Rt(){U||(U=!0,Pt.then(yt))}function $(t){z.push(t)}var X=new Set,H=0;function yt(){let t=V;do{for(;H{E=null})),E}function Z(t,e,n){t.dispatchEvent(Ht(`${e?"intro":"outro"}${n}`))}var G=new Set,m;function gt(){m={r:0,c:[],p:m}}function bt(){m.r||b(m.c),m=m.p}function I(t,e){t&&t.i&&(G.delete(t),t.i(e))}function Q(t,e,n,i){if(t&&t.o){if(G.has(t))return;G.add(t),m.c.push(()=>{G.delete(t),i&&(n&&t.d(1),i())}),t.o(e)}else i&&i()}var Ut={duration:0};function Y(t,e,n,i){let o=e(t,n),c=i?0:1,s=null,l=null,f=null;function r(){f&&Kt(t,f)}function y(u,h){let p=u.b-c;return h*=Math.abs(p),{a:c,b:u.b,d:p,duration:h,start:u.start,end:u.start+h,group:u.group}}function a(u){let{delay:h=0,duration:p=300,easing:v=A,tick:g=_,css:F}=o||Ut,K={start:Ot()+h,b:u};u||(K.group=m,m.r+=1),s||l?l=K:(F&&(r(),f=pt(t,c,u,p,h,v,F)),u&&g(0,1),s=y(K,p),$(()=>Z(t,u,"start")),Dt(O=>{if(l&&O>l.start&&(s=y(l,p),l=null,Z(t,s.b,"start"),F&&(r(),f=pt(t,c,s.b,s.duration,0,v,o.css))),s){if(O>=s.end)g(c=s.b,1-c),Z(t,s.b,"end"),l||(s.b?r():--s.group.r||b(s.group.c)),s=null;else if(O>=s.start){let jt=O-s.start;c=s.a+s.d*v(jt/s.duration),g(c,1-c)}}return!!(s||l)}))}return{run(u){w(o)?Vt().then(()=>{o=o(),a(u)}):a(u)},end(){r(),s=l=null}}}var le=typeof window!="undefined"?window:typeof globalThis!="undefined"?globalThis:global;var ue=new Set(["allowfullscreen","allowpaymentrequest","async","autofocus","autoplay","checked","controls","default","defer","disabled","formnovalidate","hidden","inert","ismap","itemscope","loop","multiple","muted","nomodule","novalidate","open","playsinline","readonly","required","reversed","selected"]);function Xt(t,e,n,i){let{fragment:o,after_update:c}=t.$$;o&&o.m(e,n),i||$(()=>{let s=t.$$.on_mount.map(N).filter(w);t.$$.on_destroy?t.$$.on_destroy.push(...s):b(s),t.$$.on_mount=[]}),c.forEach($)}function wt(t,e){let n=t.$$;n.fragment!==null&&(b(n.on_destroy),n.fragment&&n.fragment.d(e),n.on_destroy=n.fragment=null,n.ctx=[])}function Zt(t,e){t.$$.dirty[0]===-1&&(k.push(t),Rt(),t.$$.dirty.fill(0)),t.$$.dirty[e/31|0]|=1<{let p=h.length?h[0]:u;return r.ctx&&o(r.ctx[a],r.ctx[a]=p)&&(!r.skip_bound&&r.bound[a]&&r.bound[a](p),y&&Zt(t,a)),u}):[],r.update(),y=!0,b(r.before_update),r.fragment=i?i(r.ctx):!1,e.target){if(e.hydrate){At();let a=zt(e.target);r.fragment&&r.fragment.l(a),a.forEach(S)}else r.fragment&&r.fragment.c();e.intro&&I(t.$$.fragment),Xt(t,e.target,e.anchor,e.customElement),Lt(),yt()}C(f)}var Qt;typeof HTMLElement=="function"&&(Qt=class extends HTMLElement{constructor(){super();this.attachShadow({mode:"open"})}connectedCallback(){let{on_mount:t}=this.$$;this.$$.on_disconnect=t.map(N).filter(w);for(let e in this.$$.slotted)this.appendChild(this.$$.slotted[e])}attributeChangedCallback(t,e,n){this[t]=n}disconnectedCallback(){b(this.$$.on_disconnect)}$destroy(){wt(this,1),this.$destroy=_}$on(t,e){if(!w(e))return _;let n=this.$$.callbacks[t]||(this.$$.callbacks[t]=[]);return n.push(e),()=>{let i=n.indexOf(e);i!==-1&&n.splice(i,1)}}$set(t){this.$$set&&!ot(t)&&(this.$$.skip_bound=!0,this.$$set(t),this.$$.skip_bound=!1)}});var tt=class{$destroy(){wt(this,1),this.$destroy=_}$on(e,n){if(!w(n))return _;let i=this.$$.callbacks[e]||(this.$$.callbacks[e]=[]);return i.push(n),()=>{let o=i.indexOf(n);o!==-1&&i.splice(o,1)}}$set(e){this.$$set&&!ot(e)&&(this.$$.skip_bound=!0,this.$$set(e),this.$$.skip_bound=!1)}};var M=[];function Ft(t,e=_){let n,i=new Set;function o(l){if(L(t,l)&&(t=l,n)){let f=!M.length;for(let r of i)r[1](),M.push(r,t);if(f){for(let r=0;r{i.delete(r),i.size===0&&(n(),n=null)}}return{set:o,update:c,subscribe:s}}var q=Ft(!1);function xt(){q.set(!0)}function $t(){q.set(!1)}function et(t,{delay:e=0,duration:n=400,easing:i=A}={}){let o=+getComputedStyle(t).opacity;return{delay:e,duration:n,easing:i,css:c=>`opacity: ${c*o}`}}function Yt(t){at(t,"svelte-181h7z",`.wails-reconnect-overlay.svelte-181h7z{position:fixed;top:0;left:0;width:100%;height:100%;backdrop-filter:blur(2px) saturate(0%) contrast(50%) brightness(25%);z-index:999999\r - }.wails-reconnect-overlay-content.svelte-181h7z{position:relative;top:50%;transform:translateY(-50%);margin:0;background-image:url(data:image/png;base64,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);background-repeat:no-repeat;background-position:center\r - }.wails-reconnect-overlay-loadingspinner.svelte-181h7z{pointer-events:none;width:2.5em;height:2.5em;border:.4em solid transparent;border-color:#f00 #eee0 #f00 #eee0;border-radius:50%;animation:svelte-181h7z-loadingspin 1s linear infinite;margin:auto;padding:2.5em\r - }@keyframes svelte-181h7z-loadingspin{100%{transform:rotate(360deg)}}`)}function Mt(t){let e,n,i;return{c(){e=B("div"),e.innerHTML='
',ht(e,"class","wails-reconnect-overlay svelte-181h7z")},m(o,c){W(o,e,c),i=!0},i(o){i||($(()=>{n||(n=Y(e,et,{duration:300},!0)),n.run(1)}),i=!0)},o(o){n||(n=Y(e,et,{duration:300},!1)),n.run(0),i=!1},d(o){o&&S(e),o&&n&&n.end()}}}function te(t){let e,n,i=t[0]&&Mt(t);return{c(){i&&i.c(),e=dt()},m(o,c){i&&i.m(o,c),W(o,e,c),n=!0},p(o,[c]){o[0]?i?c&1&&I(i,1):(i=Mt(o),i.c(),I(i,1),i.m(e.parentNode,e)):i&&(gt(),Q(i,1,1,()=>{i=null}),bt())},i(o){n||(I(i),n=!0)},o(o){Q(i),n=!1},d(o){i&&i.d(o),o&&S(e)}}}function ee(t,e,n){let i;return st(t,q,o=>n(0,i=o)),[i]}var St=class extends tt{constructor(e){super();vt(this,e,ee,te,L,{},Yt)}},Ct=St;var ne={},nt=null,j=[];window.WailsInvoke=t=>{if(!nt){console.log("Queueing: "+t),j.push(t);return}nt(t)};window.addEventListener("DOMContentLoaded",()=>{ne.overlay=new Ct({target:document.body,anchor:document.querySelector("#wails-spinner")})});var d=null,kt;window.onbeforeunload=function(){d&&(d.onclose=function(){},d.close(),d=null)};It();function ie(){nt=t=>{d.send(t)};for(let t=0;tc.indexOf(e)<0:c=>c.indexOf("__svelte")===-1),o=n.length-i.length;o&&(t.style.animation=i.join(", "),L-=o,L||Gt())}function Gt(){q(()=>{L||(N.forEach(t=>{let e=t.__svelte_stylesheet,n=e.cssRules.length;for(;n--;)e.deleteRule(n);t.__svelte_rules={}}),N.clear())})}var dt;function B(t){dt=t}var k=[];var ht=[],J=[],pt=[],qt=Promise.resolve(),R=!1;function Kt(){R||(R=!0,qt.then(_t))}function M(t){J.push(t)}var W=!1,V=new Set;function _t(){if(!W){W=!0;do{for(let t=0;t{$=null})),$}function U(t,e,n){t.dispatchEvent(zt(`${e?"intro":"outro"}${n}`))}var z=new Set,m;function mt(){m={r:0,c:[],p:m}}function yt(){m.r||b(m.c),m=m.p}function I(t,e){t&&t.i&&(z.delete(t),t.i(e))}function X(t,e,n,i){if(t&&t.o){if(z.has(t))return;z.add(t),m.c.push(()=>{z.delete(t),i&&(n&&t.d(1),i())}),t.o(e)}}var Rt={duration:0};function Z(t,e,n,i){let o=e(t,n),c=i?0:1,s=null,l=null,a=null;function r(){a&&Ht(t,a)}function y(u,h){let p=u.b-c;return h*=Math.abs(p),{a:c,b:u.b,d:p,duration:h,start:u.start,end:u.start+h,group:u.group}}function f(u){let{delay:h=0,duration:p=300,easing:w=j,tick:g=_,css:v}=o||Rt,H={start:Et()+h,b:u};u||(H.group=m,m.r+=1),s||l?l=H:(v&&(r(),a=ft(t,c,u,p,h,w,v)),u&&g(0,1),s=y(H,p),M(()=>U(t,u,"start")),jt(E=>{if(l&&E>l.start&&(s=y(l,p),l=null,U(t,s.b,"start"),v&&(r(),a=ft(t,c,s.b,s.duration,0,w,o.css))),s){if(E>=s.end)g(c=s.b,1-c),U(t,s.b,"end"),l||(s.b?r():--s.group.r||b(s.group.c)),s=null;else if(E>=s.start){let It=E-s.start;c=s.a+s.d*w(It/s.duration),g(c,1-c)}}return!!(s||l)}))}return{run(u){S(o)?Nt().then(()=>{o=o(),f(u)}):f(u)},end(){r(),s=l=null}}}var re=typeof window!="undefined"?window:typeof globalThis!="undefined"?globalThis:global;var se=new Set(["allowfullscreen","allowpaymentrequest","async","autofocus","autoplay","checked","controls","default","defer","disabled","formnovalidate","hidden","ismap","loop","multiple","muted","nomodule","novalidate","open","playsinline","readonly","required","reversed","selected"]);function Wt(t,e,n,i){let{fragment:o,on_mount:c,on_destroy:s,after_update:l}=t.$$;o&&o.m(e,n),i||M(()=>{let a=c.map(G).filter(S);s?s.push(...a):b(a),t.$$.on_mount=[]}),l.forEach(M)}function gt(t,e){let n=t.$$;n.fragment!==null&&(b(n.on_destroy),n.fragment&&n.fragment.d(e),n.on_destroy=n.fragment=null,n.ctx=[])}function Vt(t,e){t.$$.dirty[0]===-1&&(k.push(t),Kt(),t.$$.dirty.fill(0)),t.$$.dirty[e/31|0]|=1<{let p=h.length?h[0]:u;return r.ctx&&o(r.ctx[f],r.ctx[f]=p)&&(!r.skip_bound&&r.bound[f]&&r.bound[f](p),y&&Vt(t,f)),u}):[],r.update(),y=!0,b(r.before_update),r.fragment=i?i(r.ctx):!1,e.target){if(e.hydrate){Ot();let f=Jt(e.target);r.fragment&&r.fragment.l(f),f.forEach(D)}else r.fragment&&r.fragment.c();e.intro&&I(t.$$.fragment),Wt(t,e.target,e.anchor,e.customElement),Dt(),_t()}B(a)}var Ut;typeof HTMLElement=="function"&&(Ut=class extends HTMLElement{constructor(){super();this.attachShadow({mode:"open"})}connectedCallback(){let{on_mount:t}=this.$$;this.$$.on_disconnect=t.map(G).filter(S);for(let e in this.$$.slotted)this.appendChild(this.$$.slotted[e])}attributeChangedCallback(t,e,n){this[t]=n}disconnectedCallback(){b(this.$$.on_disconnect)}$destroy(){gt(this,1),this.$destroy=_}$on(t,e){let n=this.$$.callbacks[t]||(this.$$.callbacks[t]=[]);return n.push(e),()=>{let i=n.indexOf(e);i!==-1&&n.splice(i,1)}}$set(t){this.$$set&&!et(t)&&(this.$$.skip_bound=!0,this.$$set(t),this.$$.skip_bound=!1)}});var Q=class{$destroy(){gt(this,1),this.$destroy=_}$on(e,n){let i=this.$$.callbacks[e]||(this.$$.callbacks[e]=[]);return i.push(n),()=>{let o=i.indexOf(n);o!==-1&&i.splice(o,1)}}$set(e){this.$$set&&!et(e)&&(this.$$.skip_bound=!0,this.$$set(e),this.$$.skip_bound=!1)}};var C=[];function wt(t,e=_){let n,i=new Set;function o(l){if(O(t,l)&&(t=l,n)){let a=!C.length;for(let r of i)r[1](),C.push(r,t);if(a){for(let r=0;r{i.delete(r),i.size===0&&(n(),n=null)}}return{set:o,update:c,subscribe:s}}var T=wt(!1);function vt(){T.set(!0)}function Ft(){T.set(!1)}function Y(t,{delay:e=0,duration:n=400,easing:i=j}={}){let o=+getComputedStyle(t).opacity;return{delay:e,duration:n,easing:i,css:c=>`opacity: ${c*o}`}}function Xt(t){ct(t,"svelte-181h7z",`.wails-reconnect-overlay.svelte-181h7z{position:fixed;top:0;left:0;width:100%;height:100%;backdrop-filter:blur(2px) saturate(0%) contrast(50%) brightness(25%);z-index:999999 + }.wails-reconnect-overlay-content.svelte-181h7z{position:relative;top:50%;transform:translateY(-50%);margin:0;background-image:url(data:image/png;base64,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);background-repeat:no-repeat;background-position:center + }.wails-reconnect-overlay-loadingspinner.svelte-181h7z{pointer-events:none;width:2.5em;height:2.5em;border:.4em solid transparent;border-color:#f00 #eee0 #f00 #eee0;border-radius:50%;animation:svelte-181h7z-loadingspin 1s linear infinite;margin:auto;padding:2.5em + }@keyframes svelte-181h7z-loadingspin{100%{transform:rotate(360deg)}}`)}function xt(t){let e,n,i;return{c(){e=A("div"),e.innerHTML='
',at(e,"class","wails-reconnect-overlay svelte-181h7z")},m(o,c){P(o,e,c),i=!0},i(o){i||(M(()=>{n||(n=Z(e,Y,{duration:300},!0)),n.run(1)}),i=!0)},o(o){n||(n=Z(e,Y,{duration:300},!1)),n.run(0),i=!1},d(o){o&&D(e),o&&n&&n.end()}}}function Zt(t){let e,n,i=t[0]&&xt(t);return{c(){i&&i.c(),e=ut()},m(o,c){i&&i.m(o,c),P(o,e,c),n=!0},p(o,[c]){o[0]?i?c&1&&I(i,1):(i=xt(o),i.c(),I(i,1),i.m(e.parentNode,e)):i&&(mt(),X(i,1,1,()=>{i=null}),yt())},i(o){n||(I(i),n=!0)},o(o){X(i),n=!1},d(o){i&&i.d(o),o&&D(e)}}}function Qt(t,e,n){let i;return it(t,T,o=>n(0,i=o)),[i]}var Mt=class extends Q{constructor(e){super();bt(this,e,Qt,Zt,O,{},Xt)}},Ct=Mt;var Yt={};window.ipcCallbacks=[];window.ipcCallbackNames=[];window.awaitIPC=(t,e)=>{if(!window.ipcCallbacks)return e;F("Queuing '"+t+"' for execution once ipc ready."),window.ipcCallbackNames.push(t),window.ipcCallbacks.push(e)};window.addEventListener("DOMContentLoaded",()=>{Yt.overlay=new Ct({target:document.body,anchor:document.querySelector("#wails-spinner")})});var d=null,St;window.onbeforeunload=function(){d&&(d.onclose=function(){},d.close(),d=null)};$t();function te(){window.WailsInvoke=t=>{d.send(t)};for(let t=0;t=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.12.tgz", - "integrity": "sha512-tZEowDjvU7O7I04GYvWQOS4yyP9E/7YlsB0jjw1Ycukgr2ycEzKyIk5tms5WnLBymaewc6VmRKnn5IJWgK4eFw==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@types/chai": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.3.tgz", - "integrity": "sha512-hC7OMnszpxhZPduX+m+nrx+uFoLkWOMiR4oa/AZF3MuSETYTZmFfJAHqZEM8MVlvfG7BEUcgvtwoCTxBp6hm3g==", - "dev": true - }, - "node_modules/@types/chai-subset": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@types/chai-subset/-/chai-subset-1.3.3.tgz", - "integrity": "sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==", - "dev": true, - "dependencies": { - "@types/chai": "*" - } - }, - "node_modules/@types/concat-stream": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.1.tgz", - "integrity": "sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/form-data": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz", - "integrity": "sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/node": { - "version": "18.11.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.3.tgz", - "integrity": "sha512-fNjDQzzOsZeKZu5NATgXUPsaFaTxeRgFXoosrHivTl8RGeV733OLawXsGfEk9a8/tySyZUyiZ6E8LcjPFZ2y1A==", - "dev": true - }, - "node_modules/@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "dev": true - }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true - }, - "node_modules/chai": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz", - "integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==", - "dev": true, - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^3.0.1", - "get-func-name": "^2.0.0", - "loupe": "^2.3.1", - "pathval": "^1.1.1", - "type-detect": "^4.0.5" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "engines": [ - "node >= 0.8" - ], - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "engines": { - "node": ">=4.8" - } - }, - "node_modules/css.escape": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", - "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", - "dev": true - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-eql": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", - "dev": true, - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "dependencies": { - "object-keys": "^1.0.12" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.18.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.5.tgz", - "integrity": "sha512-DDggyJLoS91CkJjgauM5c0yZMjiD1uK3KcaCeAmffGwZ+ODWzOkPN4QwRbsK5DOFf06fywmyLci3ZD8jLGhVYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.3", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", - "object-inspect": "^1.11.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/esbuild": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.12.tgz", - "integrity": "sha512-PcT+/wyDqJQsRVhaE9uX/Oq4XLrFh0ce/bs2TJh4CSaw9xuvI+xFrH2nAYOADbhQjUgAhNWC5LKoUsakm4dxng==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/android-arm": "0.15.12", - "@esbuild/linux-loong64": "0.15.12", - "esbuild-android-64": "0.15.12", - "esbuild-android-arm64": "0.15.12", - "esbuild-darwin-64": "0.15.12", - "esbuild-darwin-arm64": "0.15.12", - "esbuild-freebsd-64": "0.15.12", - "esbuild-freebsd-arm64": "0.15.12", - "esbuild-linux-32": "0.15.12", - "esbuild-linux-64": "0.15.12", - "esbuild-linux-arm": "0.15.12", - "esbuild-linux-arm64": "0.15.12", - "esbuild-linux-mips64le": "0.15.12", - "esbuild-linux-ppc64le": "0.15.12", - "esbuild-linux-riscv64": "0.15.12", - "esbuild-linux-s390x": "0.15.12", - "esbuild-netbsd-64": "0.15.12", - "esbuild-openbsd-64": "0.15.12", - "esbuild-sunos-64": "0.15.12", - "esbuild-windows-32": "0.15.12", - "esbuild-windows-64": "0.15.12", - "esbuild-windows-arm64": "0.15.12" - } - }, - "node_modules/esbuild-android-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.12.tgz", - "integrity": "sha512-MJKXwvPY9g0rGps0+U65HlTsM1wUs9lbjt5CU19RESqycGFDRijMDQsh68MtbzkqWSRdEtiKS1mtPzKneaAI0Q==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-android-arm64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.12.tgz", - "integrity": "sha512-Hc9SEcZbIMhhLcvhr1DH+lrrec9SFTiRzfJ7EGSBZiiw994gfkVV6vG0sLWqQQ6DD7V4+OggB+Hn0IRUdDUqvA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-darwin-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.12.tgz", - "integrity": "sha512-qkmqrTVYPFiePt5qFjP8w/S+GIUMbt6k8qmiPraECUWfPptaPJUGkCKrWEfYFRWB7bY23FV95rhvPyh/KARP8Q==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-darwin-arm64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.12.tgz", - "integrity": "sha512-z4zPX02tQ41kcXMyN3c/GfZpIjKoI/BzHrdKUwhC/Ki5BAhWv59A9M8H+iqaRbwpzYrYidTybBwiZAIWCLJAkw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-freebsd-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.12.tgz", - "integrity": "sha512-XFL7gKMCKXLDiAiBjhLG0XECliXaRLTZh6hsyzqUqPUf/PY4C6EJDTKIeqqPKXaVJ8+fzNek88285krSz1QECw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-freebsd-arm64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.12.tgz", - "integrity": "sha512-jwEIu5UCUk6TjiG1X+KQnCGISI+ILnXzIzt9yDVrhjug2fkYzlLbl0K43q96Q3KB66v6N1UFF0r5Ks4Xo7i72g==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-32": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.12.tgz", - "integrity": "sha512-uSQuSEyF1kVzGzuIr4XM+v7TPKxHjBnLcwv2yPyCz8riV8VUCnO/C4BF3w5dHiVpCd5Z1cebBtZJNlC4anWpwA==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.12.tgz", - "integrity": "sha512-QcgCKb7zfJxqT9o5z9ZUeGH1k8N6iX1Y7VNsEi5F9+HzN1OIx7ESxtQXDN9jbeUSPiRH1n9cw6gFT3H4qbdvcA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-arm": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.12.tgz", - "integrity": "sha512-Wf7T0aNylGcLu7hBnzMvsTfEXdEdJY/hY3u36Vla21aY66xR0MS5I1Hw8nVquXjTN0A6fk/vnr32tkC/C2lb0A==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-arm64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.12.tgz", - "integrity": "sha512-HtNq5xm8fUpZKwWKS2/YGwSfTF+339L4aIA8yphNKYJckd5hVdhfdl6GM2P3HwLSCORS++++7++//ApEwXEuAQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-mips64le": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.12.tgz", - "integrity": "sha512-Qol3+AvivngUZkTVFgLpb0H6DT+N5/zM3V1YgTkryPYFeUvuT5JFNDR3ZiS6LxhyF8EE+fiNtzwlPqMDqVcc6A==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-ppc64le": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.12.tgz", - "integrity": "sha512-4D8qUCo+CFKaR0cGXtGyVsOI7w7k93Qxb3KFXWr75An0DHamYzq8lt7TNZKoOq/Gh8c40/aKaxvcZnTgQ0TJNg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-riscv64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.12.tgz", - "integrity": "sha512-G9w6NcuuCI6TUUxe6ka0enjZHDnSVK8bO+1qDhMOCtl7Tr78CcZilJj8SGLN00zO5iIlwNRZKHjdMpfFgNn1VA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-s390x": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.12.tgz", - "integrity": "sha512-Lt6BDnuXbXeqSlVuuUM5z18GkJAZf3ERskGZbAWjrQoi9xbEIsj/hEzVnSAFLtkfLuy2DE4RwTcX02tZFunXww==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-netbsd-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.12.tgz", - "integrity": "sha512-jlUxCiHO1dsqoURZDQts+HK100o0hXfi4t54MNRMCAqKGAV33JCVvMplLAa2FwviSojT/5ZG5HUfG3gstwAG8w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-openbsd-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.12.tgz", - "integrity": "sha512-1o1uAfRTMIWNOmpf8v7iudND0L6zRBYSH45sofCZywrcf7NcZA+c7aFsS1YryU+yN7aRppTqdUK1PgbZVaB1Dw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-sunos-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.12.tgz", - "integrity": "sha512-nkl251DpoWoBO9Eq9aFdoIt2yYmp4I3kvQjba3jFKlMXuqQ9A4q+JaqdkCouG3DHgAGnzshzaGu6xofGcXyPXg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-32": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.12.tgz", - "integrity": "sha512-WlGeBZHgPC00O08luIp5B2SP4cNCp/PcS+3Pcg31kdcJPopHxLkdCXtadLU9J82LCfw4TVls21A6lilQ9mzHrw==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.12.tgz", - "integrity": "sha512-VActO3WnWZSN//xjSfbiGOSyC+wkZtI8I4KlgrTo5oHJM6z3MZZBCuFaZHd8hzf/W9KPhF0lY8OqlmWC9HO5AA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-arm64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.12.tgz", - "integrity": "sha512-Of3MIacva1OK/m4zCNIvBfz8VVROBmQT+gRX6pFTLPngFYcj6TFH/12VveAqq1k9VB2l28EoVMNMUCcmsfwyuA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/form-data": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", - "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-port": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", - "integrity": "sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true - }, - "node_modules/happy-dom": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-7.6.0.tgz", - "integrity": "sha512-QnNsiblZdyVDzW5ts6E7ub79JnabqHJeJgt+1WGNq9fSYqS/r/RzzTVXCZSDl6EVkipdwI48B4bgXAnMZPecIw==", - "dev": true, - "dependencies": { - "css.escape": "^1.5.1", - "he": "^1.2.0", - "node-fetch": "^2.x.x", - "sync-request": "^6.1.0", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^2.0.0", - "whatwg-mimetype": "^3.0.0" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "bin": { - "he": "bin/he" - } - }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "node_modules/http-basic": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz", - "integrity": "sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==", - "dev": true, - "dependencies": { - "caseless": "^0.12.0", - "concat-stream": "^1.6.2", - "http-response-object": "^3.0.1", - "parse-cache-control": "^1.0.1" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/http-response-object": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz", - "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==", - "dev": true, - "dependencies": { - "@types/node": "^10.0.3" - } - }, - "node_modules/http-response-object/node_modules/@types/node": { - "version": "10.17.60", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", - "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", - "dev": true - }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "node_modules/is-bigint": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz", - "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz", - "integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", - "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.4.tgz", - "integrity": "sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz", - "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-regex": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", - "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-string": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", - "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "node_modules/load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/local-pkg": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.2.tgz", - "integrity": "sha512-mlERgSPrbxU3BP4qBqAvvwlgW4MTg78iwJdGGnv7kibKjWcJksrG3t6LB5lXI93wXRDvG4NpUgJFmTG4T6rdrg==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/loupe": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz", - "integrity": "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==", - "dev": true, - "dependencies": { - "get-func-name": "^2.0.0" - } - }, - "node_modules/memorystream": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", - "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=", - "dev": true, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dev": true, - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/npm-run-all": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", - "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "chalk": "^2.4.1", - "cross-spawn": "^6.0.5", - "memorystream": "^0.3.1", - "minimatch": "^3.0.4", - "pidtree": "^0.3.0", - "read-pkg": "^3.0.0", - "shell-quote": "^1.6.1", - "string.prototype.padend": "^3.0.0" - }, - "bin": { - "npm-run-all": "bin/npm-run-all/index.js", - "run-p": "bin/run-p/index.js", - "run-s": "bin/run-s/index.js" - }, - "engines": { - "node": ">= 4" - } - }, - "node_modules/object-inspect": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/parse-cache-control": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", - "integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==", - "dev": true - }, - "node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "dependencies": { - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "node_modules/pidtree": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", - "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", - "dev": true, - "bin": { - "pidtree": "bin/pidtree.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss": { - "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "node_modules/promise": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/promise/-/promise-8.2.0.tgz", - "integrity": "sha512-+CMAlLHqwRYwBMXKCP+o8ns7DN+xHDUiI+0nArsiJ9y+kJVPLFxEaSw6Ha9s9H0tftxg2Yzl25wqj9G7m5wLZg==", - "dev": true, - "dependencies": { - "asap": "~2.0.6" - } - }, - "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dev": true, - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, - "dependencies": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/rollup": { - "version": "2.79.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", - "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", - "dev": true, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=10.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shell-quote": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", - "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==", - "dev": true - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz", - "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==", - "dev": true - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string.prototype.padend": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.2.tgz", - "integrity": "sha512-/AQFLdYvePENU3W5rgurfWSMU6n+Ww8n/3cUt7E+vPBB/D7YDG8x+qjoFs4M/alR2bW7Qg6xMjVwWUOvuQ0XpQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-literal": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-0.4.2.tgz", - "integrity": "sha512-pv48ybn4iE1O9RLgCAN0iU4Xv7RlBTiit6DKmMiErbs9x1wH6vXBs45tWc0H5wUIF6TLTrKweqkmYF/iraQKNw==", - "dev": true, - "dependencies": { - "acorn": "^8.8.0" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/svelte": { - "version": "3.49.0", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.49.0.tgz", - "integrity": "sha512-+lmjic1pApJWDfPCpUUTc1m8azDqYCG1JN9YEngrx/hUyIcFJo6VZhj0A1Ai0wqoHcEIuQy+e9tk+4uDgdtsFA==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/sync-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.1.0.tgz", - "integrity": "sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==", - "dev": true, - "dependencies": { - "http-response-object": "^3.0.1", - "sync-rpc": "^1.2.1", - "then-request": "^6.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/sync-rpc": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.6.tgz", - "integrity": "sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==", - "dev": true, - "dependencies": { - "get-port": "^3.1.0" - } - }, - "node_modules/then-request": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.2.tgz", - "integrity": "sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==", - "dev": true, - "dependencies": { - "@types/concat-stream": "^1.6.0", - "@types/form-data": "0.0.33", - "@types/node": "^8.0.0", - "@types/qs": "^6.2.31", - "caseless": "~0.12.0", - "concat-stream": "^1.6.0", - "form-data": "^2.2.0", - "http-basic": "^8.1.1", - "http-response-object": "^3.0.1", - "promise": "^8.0.0", - "qs": "^6.4.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/then-request/node_modules/@types/node": { - "version": "8.10.66", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz", - "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==", - "dev": true - }, - "node_modules/tinybench": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.3.1.tgz", - "integrity": "sha512-hGYWYBMPr7p4g5IarQE7XhlyWveh1EKhy4wUBS1LrHXCKYgvz+4/jCqgmJqZxxldesn05vccrtME2RLLZNW7iA==", - "dev": true - }, - "node_modules/tinypool": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.3.0.tgz", - "integrity": "sha512-NX5KeqHOBZU6Bc0xj9Vr5Szbb1j8tUHIeD18s41aDJaPeC5QTdEhK0SpdpUrZlj2nv5cctNcSjaKNanXlfcVEQ==", - "dev": true, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tinyspy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-1.0.2.tgz", - "integrity": "sha512-bSGlgwLBYf7PnUsQ6WOc6SJ3pGOcd+d8AA6EUnLDDM0kWEstC1JIlSZA3UNliDXhd9ABoS7hiRBDCu+XP/sf1Q==", - "dev": true, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", - "dev": true - }, - "node_modules/unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/vite": { - "version": "3.2.10", - "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.10.tgz", - "integrity": "sha512-Dx3olBo/ODNiMVk/cA5Yft9Ws+snLOXrhLtrI3F4XLt4syz2Yg8fayZMWScPKoz12v5BUv7VEmQHnsfpY80fYw==", - "dev": true, - "dependencies": { - "esbuild": "^0.15.9", - "postcss": "^8.4.18", - "resolve": "^1.22.1", - "rollup": "^2.79.1" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - }, - "peerDependencies": { - "@types/node": ">= 14", - "less": "*", - "sass": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "sass": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - }, - "node_modules/vitest": { - "version": "0.24.3", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.24.3.tgz", - "integrity": "sha512-aM0auuPPgMSstWvr851hB74g/LKaKBzSxcG3da7ejfZbx08Y21JpZmbmDYrMTCGhVZKqTGwzcnLMwyfz2WzkhQ==", - "dev": true, - "dependencies": { - "@types/chai": "^4.3.3", - "@types/chai-subset": "^1.3.3", - "@types/node": "*", - "chai": "^4.3.6", - "debug": "^4.3.4", - "local-pkg": "^0.4.2", - "strip-literal": "^0.4.2", - "tinybench": "^2.3.0", - "tinypool": "^0.3.0", - "tinyspy": "^1.0.2", - "vite": "^3.0.0" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": ">=v14.16.0" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@vitest/browser": "*", - "@vitest/ui": "*", - "happy-dom": "*", - "jsdom": "*" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@vitest/browser": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - } - } - }, - "node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-encoding": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", - "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", - "dev": true, - "dependencies": { - "iconv-lite": "0.6.3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-mimetype": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", - "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/whatwg-url/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true - }, - "node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - } - }, "dependencies": { - "@esbuild/android-arm": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.12.tgz", - "integrity": "sha512-IC7TqIqiyE0MmvAhWkl/8AEzpOtbhRNDo7aph47We1NbE5w2bt/Q+giAhe0YYeVpYnIhGMcuZY92qDK6dQauvA==", - "dev": true, - "optional": true - }, - "@esbuild/linux-loong64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.12.tgz", - "integrity": "sha512-tZEowDjvU7O7I04GYvWQOS4yyP9E/7YlsB0jjw1Ycukgr2ycEzKyIk5tms5WnLBymaewc6VmRKnn5IJWgK4eFw==", - "dev": true, - "optional": true - }, - "@types/chai": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.3.tgz", - "integrity": "sha512-hC7OMnszpxhZPduX+m+nrx+uFoLkWOMiR4oa/AZF3MuSETYTZmFfJAHqZEM8MVlvfG7BEUcgvtwoCTxBp6hm3g==", - "dev": true - }, - "@types/chai-subset": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@types/chai-subset/-/chai-subset-1.3.3.tgz", - "integrity": "sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==", - "dev": true, - "requires": { - "@types/chai": "*" - } - }, - "@types/concat-stream": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.1.tgz", - "integrity": "sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/form-data": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz", - "integrity": "sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/node": { - "version": "18.11.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.3.tgz", - "integrity": "sha512-fNjDQzzOsZeKZu5NATgXUPsaFaTxeRgFXoosrHivTl8RGeV733OLawXsGfEk9a8/tySyZUyiZ6E8LcjPFZ2y1A==", - "dev": true - }, - "@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", - "dev": true - }, - "acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "dev": true - }, "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", @@ -2115,24 +13,6 @@ "color-convert": "^1.9.0" } }, - "asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "dev": true - }, - "assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true - }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -2149,12 +29,6 @@ "concat-map": "0.0.1" } }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, "call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -2165,27 +39,6 @@ "get-intrinsic": "^1.0.2" } }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true - }, - "chai": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz", - "integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==", - "dev": true, - "requires": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^3.0.1", - "get-func-name": "^2.0.0", - "loupe": "^2.3.1", - "pathval": "^1.1.1", - "type-detect": "^4.0.5" - } - }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -2197,12 +50,6 @@ "supports-color": "^5.3.0" } }, - "check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", - "dev": true - }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -2218,39 +65,12 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "requires": { - "delayed-stream": "~1.0.0" - } - }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -2264,30 +84,6 @@ "which": "^1.2.9" } }, - "css.escape": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", - "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", - "dev": true - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "deep-eql": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", - "dev": true, - "requires": { - "type-detect": "^4.0.0" - } - }, "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", @@ -2297,12 +93,6 @@ "object-keys": "^1.0.12" } }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true - }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -2349,174 +139,10 @@ } }, "esbuild": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.12.tgz", - "integrity": "sha512-PcT+/wyDqJQsRVhaE9uX/Oq4XLrFh0ce/bs2TJh4CSaw9xuvI+xFrH2nAYOADbhQjUgAhNWC5LKoUsakm4dxng==", - "dev": true, - "requires": { - "@esbuild/android-arm": "0.15.12", - "@esbuild/linux-loong64": "0.15.12", - "esbuild-android-64": "0.15.12", - "esbuild-android-arm64": "0.15.12", - "esbuild-darwin-64": "0.15.12", - "esbuild-darwin-arm64": "0.15.12", - "esbuild-freebsd-64": "0.15.12", - "esbuild-freebsd-arm64": "0.15.12", - "esbuild-linux-32": "0.15.12", - "esbuild-linux-64": "0.15.12", - "esbuild-linux-arm": "0.15.12", - "esbuild-linux-arm64": "0.15.12", - "esbuild-linux-mips64le": "0.15.12", - "esbuild-linux-ppc64le": "0.15.12", - "esbuild-linux-riscv64": "0.15.12", - "esbuild-linux-s390x": "0.15.12", - "esbuild-netbsd-64": "0.15.12", - "esbuild-openbsd-64": "0.15.12", - "esbuild-sunos-64": "0.15.12", - "esbuild-windows-32": "0.15.12", - "esbuild-windows-64": "0.15.12", - "esbuild-windows-arm64": "0.15.12" - } - }, - "esbuild-android-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.12.tgz", - "integrity": "sha512-MJKXwvPY9g0rGps0+U65HlTsM1wUs9lbjt5CU19RESqycGFDRijMDQsh68MtbzkqWSRdEtiKS1mtPzKneaAI0Q==", - "dev": true, - "optional": true - }, - "esbuild-android-arm64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.12.tgz", - "integrity": "sha512-Hc9SEcZbIMhhLcvhr1DH+lrrec9SFTiRzfJ7EGSBZiiw994gfkVV6vG0sLWqQQ6DD7V4+OggB+Hn0IRUdDUqvA==", - "dev": true, - "optional": true - }, - "esbuild-darwin-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.12.tgz", - "integrity": "sha512-qkmqrTVYPFiePt5qFjP8w/S+GIUMbt6k8qmiPraECUWfPptaPJUGkCKrWEfYFRWB7bY23FV95rhvPyh/KARP8Q==", - "dev": true, - "optional": true - }, - "esbuild-darwin-arm64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.12.tgz", - "integrity": "sha512-z4zPX02tQ41kcXMyN3c/GfZpIjKoI/BzHrdKUwhC/Ki5BAhWv59A9M8H+iqaRbwpzYrYidTybBwiZAIWCLJAkw==", - "dev": true, - "optional": true - }, - "esbuild-freebsd-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.12.tgz", - "integrity": "sha512-XFL7gKMCKXLDiAiBjhLG0XECliXaRLTZh6hsyzqUqPUf/PY4C6EJDTKIeqqPKXaVJ8+fzNek88285krSz1QECw==", - "dev": true, - "optional": true - }, - "esbuild-freebsd-arm64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.12.tgz", - "integrity": "sha512-jwEIu5UCUk6TjiG1X+KQnCGISI+ILnXzIzt9yDVrhjug2fkYzlLbl0K43q96Q3KB66v6N1UFF0r5Ks4Xo7i72g==", - "dev": true, - "optional": true - }, - "esbuild-linux-32": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.12.tgz", - "integrity": "sha512-uSQuSEyF1kVzGzuIr4XM+v7TPKxHjBnLcwv2yPyCz8riV8VUCnO/C4BF3w5dHiVpCd5Z1cebBtZJNlC4anWpwA==", - "dev": true, - "optional": true - }, - "esbuild-linux-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.12.tgz", - "integrity": "sha512-QcgCKb7zfJxqT9o5z9ZUeGH1k8N6iX1Y7VNsEi5F9+HzN1OIx7ESxtQXDN9jbeUSPiRH1n9cw6gFT3H4qbdvcA==", - "dev": true, - "optional": true - }, - "esbuild-linux-arm": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.12.tgz", - "integrity": "sha512-Wf7T0aNylGcLu7hBnzMvsTfEXdEdJY/hY3u36Vla21aY66xR0MS5I1Hw8nVquXjTN0A6fk/vnr32tkC/C2lb0A==", - "dev": true, - "optional": true - }, - "esbuild-linux-arm64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.12.tgz", - "integrity": "sha512-HtNq5xm8fUpZKwWKS2/YGwSfTF+339L4aIA8yphNKYJckd5hVdhfdl6GM2P3HwLSCORS++++7++//ApEwXEuAQ==", - "dev": true, - "optional": true - }, - "esbuild-linux-mips64le": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.12.tgz", - "integrity": "sha512-Qol3+AvivngUZkTVFgLpb0H6DT+N5/zM3V1YgTkryPYFeUvuT5JFNDR3ZiS6LxhyF8EE+fiNtzwlPqMDqVcc6A==", - "dev": true, - "optional": true - }, - "esbuild-linux-ppc64le": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.12.tgz", - "integrity": "sha512-4D8qUCo+CFKaR0cGXtGyVsOI7w7k93Qxb3KFXWr75An0DHamYzq8lt7TNZKoOq/Gh8c40/aKaxvcZnTgQ0TJNg==", - "dev": true, - "optional": true - }, - "esbuild-linux-riscv64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.12.tgz", - "integrity": "sha512-G9w6NcuuCI6TUUxe6ka0enjZHDnSVK8bO+1qDhMOCtl7Tr78CcZilJj8SGLN00zO5iIlwNRZKHjdMpfFgNn1VA==", - "dev": true, - "optional": true - }, - "esbuild-linux-s390x": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.12.tgz", - "integrity": "sha512-Lt6BDnuXbXeqSlVuuUM5z18GkJAZf3ERskGZbAWjrQoi9xbEIsj/hEzVnSAFLtkfLuy2DE4RwTcX02tZFunXww==", - "dev": true, - "optional": true - }, - "esbuild-netbsd-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.12.tgz", - "integrity": "sha512-jlUxCiHO1dsqoURZDQts+HK100o0hXfi4t54MNRMCAqKGAV33JCVvMplLAa2FwviSojT/5ZG5HUfG3gstwAG8w==", - "dev": true, - "optional": true - }, - "esbuild-openbsd-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.12.tgz", - "integrity": "sha512-1o1uAfRTMIWNOmpf8v7iudND0L6zRBYSH45sofCZywrcf7NcZA+c7aFsS1YryU+yN7aRppTqdUK1PgbZVaB1Dw==", - "dev": true, - "optional": true - }, - "esbuild-sunos-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.12.tgz", - "integrity": "sha512-nkl251DpoWoBO9Eq9aFdoIt2yYmp4I3kvQjba3jFKlMXuqQ9A4q+JaqdkCouG3DHgAGnzshzaGu6xofGcXyPXg==", - "dev": true, - "optional": true - }, - "esbuild-windows-32": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.12.tgz", - "integrity": "sha512-WlGeBZHgPC00O08luIp5B2SP4cNCp/PcS+3Pcg31kdcJPopHxLkdCXtadLU9J82LCfw4TVls21A6lilQ9mzHrw==", - "dev": true, - "optional": true - }, - "esbuild-windows-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.12.tgz", - "integrity": "sha512-VActO3WnWZSN//xjSfbiGOSyC+wkZtI8I4KlgrTo5oHJM6z3MZZBCuFaZHd8hzf/W9KPhF0lY8OqlmWC9HO5AA==", - "dev": true, - "optional": true - }, - "esbuild-windows-arm64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.12.tgz", - "integrity": "sha512-Of3MIacva1OK/m4zCNIvBfz8VVROBmQT+gRX6pFTLPngFYcj6TFH/12VveAqq1k9VB2l28EoVMNMUCcmsfwyuA==", - "dev": true, - "optional": true + "version": "0.12.17", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.17.tgz", + "integrity": "sha512-GshKJyVYUnlSXIZj/NheC2O0Kblh42CS7P1wJyTbbIHevTG4jYMS9NNw8EOd8dDWD0dzydYHS01MpZoUcQXB4g==", + "dev": true }, "escape-string-regexp": { "version": "1.0.5", @@ -2524,36 +150,12 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, - "form-data": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", - "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "optional": true - }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, - "get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", - "dev": true - }, "get-intrinsic": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", @@ -2565,33 +167,12 @@ "has-symbols": "^1.0.1" } }, - "get-port": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", - "integrity": "sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg==", - "dev": true - }, "graceful-fs": { "version": "4.2.6", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", "dev": true }, - "happy-dom": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-7.6.0.tgz", - "integrity": "sha512-QnNsiblZdyVDzW5ts6E7ub79JnabqHJeJgt+1WGNq9fSYqS/r/RzzTVXCZSDl6EVkipdwI48B4bgXAnMZPecIw==", - "dev": true, - "requires": { - "css.escape": "^1.5.1", - "he": "^1.2.0", - "node-fetch": "^2.x.x", - "sync-request": "^6.1.0", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^2.0.0", - "whatwg-mimetype": "^3.0.0" - } - }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -2619,62 +200,12 @@ "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", "dev": true }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, "hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, - "http-basic": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz", - "integrity": "sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==", - "dev": true, - "requires": { - "caseless": "^0.12.0", - "concat-stream": "^1.6.2", - "http-response-object": "^3.0.1", - "parse-cache-control": "^1.0.1" - } - }, - "http-response-object": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz", - "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==", - "dev": true, - "requires": { - "@types/node": "^10.0.3" - }, - "dependencies": { - "@types/node": { - "version": "10.17.60", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", - "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", - "dev": true - } - } - }, - "iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, "internal-slot": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", @@ -2714,9 +245,9 @@ "dev": true }, "is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.5.0.tgz", + "integrity": "sha512-TXCMSDsEHMEEZ6eCA8rwRDbLu55MRGmrctljsBX/2v1d9/GzqHOxW5c5oPSgrUt2vBFXebu9rGqckXGPWOlYpg==", "dev": true, "requires": { "has": "^1.0.3" @@ -2765,12 +296,6 @@ "has-symbols": "^1.0.2" } }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true - }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -2795,78 +320,27 @@ "strip-bom": "^3.0.0" } }, - "local-pkg": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.2.tgz", - "integrity": "sha512-mlERgSPrbxU3BP4qBqAvvwlgW4MTg78iwJdGGnv7kibKjWcJksrG3t6LB5lXI93wXRDvG4NpUgJFmTG4T6rdrg==", - "dev": true - }, - "loupe": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz", - "integrity": "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==", - "dev": true, - "requires": { - "get-func-name": "^2.0.0" - } - }, "memorystream": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=", "dev": true }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "requires": { - "mime-db": "1.52.0" - } - }, "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { "brace-expansion": "^1.1.7" } }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", - "dev": true - }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, - "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dev": true, - "requires": { - "whatwg-url": "^5.0.0" - } - }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -2920,12 +394,6 @@ "object-keys": "^1.1.1" } }, - "parse-cache-control": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", - "integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==", - "dev": true - }, "parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -2957,18 +425,6 @@ "pify": "^3.0.0" } }, - "pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, "pidtree": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", @@ -2981,41 +437,6 @@ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "dev": true }, - "postcss": { - "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", - "dev": true, - "requires": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - } - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "promise": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/promise/-/promise-8.2.0.tgz", - "integrity": "sha512-+CMAlLHqwRYwBMXKCP+o8ns7DN+xHDUiI+0nArsiJ9y+kJVPLFxEaSw6Ha9s9H0tftxg2Yzl25wqj9G7m5wLZg==", - "dev": true, - "requires": { - "asap": "~2.0.6" - } - }, - "qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dev": true, - "requires": { - "side-channel": "^1.0.4" - } - }, "read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", @@ -3027,57 +448,20 @@ "path-type": "^3.0.0" } }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, "resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", "dev": true, "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" } }, - "rollup": { - "version": "2.79.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", - "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", - "dev": true, - "requires": { - "fsevents": "~2.3.2" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, "semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true }, "shebang-command": { @@ -3096,9 +480,9 @@ "dev": true }, "shell-quote": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", - "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz", + "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==", "dev": true }, "side-channel": { @@ -3112,12 +496,6 @@ "object-inspect": "^1.9.0" } }, - "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true - }, "spdx-correct": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", @@ -3150,15 +528,6 @@ "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==", "dev": true }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, "string.prototype.padend": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.2.tgz", @@ -3196,15 +565,6 @@ "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true }, - "strip-literal": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-0.4.2.tgz", - "integrity": "sha512-pv48ybn4iE1O9RLgCAN0iU4Xv7RlBTiit6DKmMiErbs9x1wH6vXBs45tWc0H5wUIF6TLTrKweqkmYF/iraQKNw==", - "dev": true, - "requires": { - "acorn": "^8.8.0" - } - }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -3214,99 +574,10 @@ "has-flag": "^3.0.0" } }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true - }, "svelte": { - "version": "3.49.0", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.49.0.tgz", - "integrity": "sha512-+lmjic1pApJWDfPCpUUTc1m8azDqYCG1JN9YEngrx/hUyIcFJo6VZhj0A1Ai0wqoHcEIuQy+e9tk+4uDgdtsFA==", - "dev": true - }, - "sync-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.1.0.tgz", - "integrity": "sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==", - "dev": true, - "requires": { - "http-response-object": "^3.0.1", - "sync-rpc": "^1.2.1", - "then-request": "^6.0.0" - } - }, - "sync-rpc": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.6.tgz", - "integrity": "sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==", - "dev": true, - "requires": { - "get-port": "^3.1.0" - } - }, - "then-request": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.2.tgz", - "integrity": "sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==", - "dev": true, - "requires": { - "@types/concat-stream": "^1.6.0", - "@types/form-data": "0.0.33", - "@types/node": "^8.0.0", - "@types/qs": "^6.2.31", - "caseless": "~0.12.0", - "concat-stream": "^1.6.0", - "form-data": "^2.2.0", - "http-basic": "^8.1.1", - "http-response-object": "^3.0.1", - "promise": "^8.0.0", - "qs": "^6.4.0" - }, - "dependencies": { - "@types/node": { - "version": "8.10.66", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz", - "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==", - "dev": true - } - } - }, - "tinybench": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.3.1.tgz", - "integrity": "sha512-hGYWYBMPr7p4g5IarQE7XhlyWveh1EKhy4wUBS1LrHXCKYgvz+4/jCqgmJqZxxldesn05vccrtME2RLLZNW7iA==", - "dev": true - }, - "tinypool": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.3.0.tgz", - "integrity": "sha512-NX5KeqHOBZU6Bc0xj9Vr5Szbb1j8tUHIeD18s41aDJaPeC5QTdEhK0SpdpUrZlj2nv5cctNcSjaKNanXlfcVEQ==", - "dev": true - }, - "tinyspy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-1.0.2.tgz", - "integrity": "sha512-bSGlgwLBYf7PnUsQ6WOc6SJ3pGOcd+d8AA6EUnLDDM0kWEstC1JIlSZA3UNliDXhd9ABoS7hiRBDCu+XP/sf1Q==", - "dev": true - }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true - }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "version": "3.42.5", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.42.5.tgz", + "integrity": "sha512-+y9ivcwMojAb0e87W7vR/UP7go44zc/3gtEciIMb8CUoIkUx6UJmPloBvVuO9MDXoGkUZM5SHr5PbLze9fJQVw==", "dev": true }, "unbox-primitive": { @@ -3321,12 +592,6 @@ "which-boxed-primitive": "^1.0.2" } }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, "validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -3337,77 +602,6 @@ "spdx-expression-parse": "^3.0.0" } }, - "vite": { - "version": "3.2.10", - "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.10.tgz", - "integrity": "sha512-Dx3olBo/ODNiMVk/cA5Yft9Ws+snLOXrhLtrI3F4XLt4syz2Yg8fayZMWScPKoz12v5BUv7VEmQHnsfpY80fYw==", - "dev": true, - "requires": { - "esbuild": "^0.15.9", - "fsevents": "~2.3.2", - "postcss": "^8.4.18", - "resolve": "^1.22.1", - "rollup": "^2.79.1" - } - }, - "vitest": { - "version": "0.24.3", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.24.3.tgz", - "integrity": "sha512-aM0auuPPgMSstWvr851hB74g/LKaKBzSxcG3da7ejfZbx08Y21JpZmbmDYrMTCGhVZKqTGwzcnLMwyfz2WzkhQ==", - "dev": true, - "requires": { - "@types/chai": "^4.3.3", - "@types/chai-subset": "^1.3.3", - "@types/node": "*", - "chai": "^4.3.6", - "debug": "^4.3.4", - "local-pkg": "^0.4.2", - "strip-literal": "^0.4.2", - "tinybench": "^2.3.0", - "tinypool": "^0.3.0", - "tinyspy": "^1.0.2", - "vite": "^3.0.0" - } - }, - "webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "dev": true - }, - "whatwg-encoding": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", - "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", - "dev": true, - "requires": { - "iconv-lite": "0.6.3" - } - }, - "whatwg-mimetype": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", - "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", - "dev": true - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - }, - "dependencies": { - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true - } - } - }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", diff --git a/v2/internal/frontend/runtime/package.json b/v2/internal/frontend/runtime/package.json index 09ff4d50f..28e9ddfba 100644 --- a/v2/internal/frontend/runtime/package.json +++ b/v2/internal/frontend/runtime/package.json @@ -5,19 +5,18 @@ "main": "index.js", "scripts": { "build": "run-p build:*", - "build:ipc-desktop": "npx esbuild desktop/ipc.js --bundle --minify --outfile=ipc.js", - "build:ipc-dev": "cd dev && npm install && npm run build", - "build:runtime-desktop-prod": "npx esbuild desktop/main.js --bundle --minify --outfile=runtime_prod_desktop.js --define:DEBUG=false", - "build:runtime-desktop-debug": "npx esbuild desktop/main.js --bundle --sourcemap=inline --outfile=runtime_debug_desktop.js --define:DEBUG=true", - "test": "vitest" + "build:ipc-desktop": "esbuild desktop/ipc.js --bundle --minify --outfile=ipc.js", + "build:ipc-dev": "cd dev && npm run build", + "build:runtime-desktop-prod": "esbuild desktop/main.js --bundle --minify --outfile=runtime_prod_desktop.js --define:ENV=1", + "build:runtime-desktop-dev": "esbuild desktop/main.js --bundle --sourcemap=inline --outfile=runtime_dev_desktop.js --define:ENV=0", + "build:runtime-wrapper": "cd wrapper && esbuild main.js --bundle --minify --outfile=runtime.js", + "test": "echo \"Error: no test specified\" && exit 1" }, "author": "Lea Anthony ", "license": "ISC", "devDependencies": { - "esbuild": "^0.15.6", - "happy-dom": "^7.6.0", + "esbuild": "^0.12.17", "npm-run-all": "^4.1.5", - "svelte": "^3.49.0", - "vitest": "^0.24.3" + "svelte": "^3.42.2" } } diff --git a/v2/internal/frontend/runtime/runtime_debug_desktop.go b/v2/internal/frontend/runtime/runtime_debug_desktop.go deleted file mode 100644 index 8dff343c0..000000000 --- a/v2/internal/frontend/runtime/runtime_debug_desktop.go +++ /dev/null @@ -1,8 +0,0 @@ -//go:build debug || !production - -package runtime - -import _ "embed" - -//go:embed runtime_debug_desktop.js -var RuntimeDesktopJS []byte diff --git a/v2/internal/frontend/runtime/runtime_debug_desktop.js b/v2/internal/frontend/runtime/runtime_debug_desktop.js deleted file mode 100644 index a5f6068e9..000000000 --- a/v2/internal/frontend/runtime/runtime_debug_desktop.js +++ /dev/null @@ -1,792 +0,0 @@ -(() => { - var __defProp = Object.defineProperty; - var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); - }; - - // desktop/log.js - var log_exports = {}; - __export(log_exports, { - LogDebug: () => LogDebug, - LogError: () => LogError, - LogFatal: () => LogFatal, - LogInfo: () => LogInfo, - LogLevel: () => LogLevel, - LogPrint: () => LogPrint, - LogTrace: () => LogTrace, - LogWarning: () => LogWarning, - SetLogLevel: () => SetLogLevel - }); - function sendLogMessage(level, message) { - window.WailsInvoke("L" + level + message); - } - function LogTrace(message) { - sendLogMessage("T", message); - } - function LogPrint(message) { - sendLogMessage("P", message); - } - function LogDebug(message) { - sendLogMessage("D", message); - } - function LogInfo(message) { - sendLogMessage("I", message); - } - function LogWarning(message) { - sendLogMessage("W", message); - } - function LogError(message) { - sendLogMessage("E", message); - } - function LogFatal(message) { - sendLogMessage("F", message); - } - function SetLogLevel(loglevel) { - sendLogMessage("S", loglevel); - } - var LogLevel = { - TRACE: 1, - DEBUG: 2, - INFO: 3, - WARNING: 4, - ERROR: 5 - }; - - // desktop/events.js - var Listener = class { - constructor(eventName, callback, maxCallbacks) { - this.eventName = eventName; - this.maxCallbacks = maxCallbacks || -1; - this.Callback = (data) => { - callback.apply(null, data); - if (this.maxCallbacks === -1) { - return false; - } - this.maxCallbacks -= 1; - return this.maxCallbacks === 0; - }; - } - }; - var eventListeners = {}; - function EventsOnMultiple(eventName, callback, maxCallbacks) { - eventListeners[eventName] = eventListeners[eventName] || []; - const thisListener = new Listener(eventName, callback, maxCallbacks); - eventListeners[eventName].push(thisListener); - return () => listenerOff(thisListener); - } - function EventsOn(eventName, callback) { - return EventsOnMultiple(eventName, callback, -1); - } - function EventsOnce(eventName, callback) { - return EventsOnMultiple(eventName, callback, 1); - } - function notifyListeners(eventData) { - let eventName = eventData.name; - const newEventListenerList = eventListeners[eventName]?.slice() || []; - if (newEventListenerList.length) { - for (let count = newEventListenerList.length - 1; count >= 0; count -= 1) { - const listener = newEventListenerList[count]; - let data = eventData.data; - const destroy = listener.Callback(data); - if (destroy) { - newEventListenerList.splice(count, 1); - } - } - if (newEventListenerList.length === 0) { - removeListener(eventName); - } else { - eventListeners[eventName] = newEventListenerList; - } - } - } - function EventsNotify(notifyMessage) { - let message; - try { - message = JSON.parse(notifyMessage); - } catch (e) { - const error = "Invalid JSON passed to Notify: " + notifyMessage; - throw new Error(error); - } - notifyListeners(message); - } - function EventsEmit(eventName) { - const payload = { - name: eventName, - data: [].slice.apply(arguments).slice(1) - }; - notifyListeners(payload); - window.WailsInvoke("EE" + JSON.stringify(payload)); - } - function removeListener(eventName) { - delete eventListeners[eventName]; - window.WailsInvoke("EX" + eventName); - } - function EventsOff(eventName, ...additionalEventNames) { - removeListener(eventName); - if (additionalEventNames.length > 0) { - additionalEventNames.forEach((eventName2) => { - removeListener(eventName2); - }); - } - } - function EventsOffAll() { - const eventNames = Object.keys(eventListeners); - eventNames.forEach((eventName) => { - removeListener(eventName); - }); - } - function listenerOff(listener) { - const eventName = listener.eventName; - if (eventListeners[eventName] === void 0) - return; - eventListeners[eventName] = eventListeners[eventName].filter((l) => l !== listener); - if (eventListeners[eventName].length === 0) { - removeListener(eventName); - } - } - - // desktop/calls.js - var callbacks = {}; - function cryptoRandom() { - var array = new Uint32Array(1); - return window.crypto.getRandomValues(array)[0]; - } - function basicRandom() { - return Math.random() * 9007199254740991; - } - var randomFunc; - if (window.crypto) { - randomFunc = cryptoRandom; - } else { - randomFunc = basicRandom; - } - function Call(name, args, timeout) { - if (timeout == null) { - timeout = 0; - } - return new Promise(function(resolve, reject) { - var callbackID; - do { - callbackID = name + "-" + randomFunc(); - } while (callbacks[callbackID]); - var timeoutHandle; - if (timeout > 0) { - timeoutHandle = setTimeout(function() { - reject(Error("Call to " + name + " timed out. Request ID: " + callbackID)); - }, timeout); - } - callbacks[callbackID] = { - timeoutHandle, - reject, - resolve - }; - try { - const payload = { - name, - args, - callbackID - }; - window.WailsInvoke("C" + JSON.stringify(payload)); - } catch (e) { - console.error(e); - } - }); - } - window.ObfuscatedCall = (id, args, timeout) => { - if (timeout == null) { - timeout = 0; - } - return new Promise(function(resolve, reject) { - var callbackID; - do { - callbackID = id + "-" + randomFunc(); - } while (callbacks[callbackID]); - var timeoutHandle; - if (timeout > 0) { - timeoutHandle = setTimeout(function() { - reject(Error("Call to method " + id + " timed out. Request ID: " + callbackID)); - }, timeout); - } - callbacks[callbackID] = { - timeoutHandle, - reject, - resolve - }; - try { - const payload = { - id, - args, - callbackID - }; - window.WailsInvoke("c" + JSON.stringify(payload)); - } catch (e) { - console.error(e); - } - }); - }; - function Callback(incomingMessage) { - let message; - try { - message = JSON.parse(incomingMessage); - } catch (e) { - const error = `Invalid JSON passed to callback: ${e.message}. Message: ${incomingMessage}`; - runtime.LogDebug(error); - throw new Error(error); - } - let callbackID = message.callbackid; - let callbackData = callbacks[callbackID]; - if (!callbackData) { - const error = `Callback '${callbackID}' not registered!!!`; - console.error(error); - throw new Error(error); - } - clearTimeout(callbackData.timeoutHandle); - delete callbacks[callbackID]; - if (message.error) { - callbackData.reject(message.error); - } else { - callbackData.resolve(message.result); - } - } - - // desktop/bindings.js - window.go = {}; - function SetBindings(bindingsMap) { - try { - bindingsMap = JSON.parse(bindingsMap); - } catch (e) { - console.error(e); - } - window.go = window.go || {}; - Object.keys(bindingsMap).forEach((packageName) => { - window.go[packageName] = window.go[packageName] || {}; - Object.keys(bindingsMap[packageName]).forEach((structName) => { - window.go[packageName][structName] = window.go[packageName][structName] || {}; - Object.keys(bindingsMap[packageName][structName]).forEach((methodName) => { - window.go[packageName][structName][methodName] = function() { - let timeout = 0; - function dynamic() { - const args = [].slice.call(arguments); - return Call([packageName, structName, methodName].join("."), args, timeout); - } - dynamic.setTimeout = function(newTimeout) { - timeout = newTimeout; - }; - dynamic.getTimeout = function() { - return timeout; - }; - return dynamic; - }(); - }); - }); - }); - } - - // desktop/window.js - var window_exports = {}; - __export(window_exports, { - WindowCenter: () => WindowCenter, - WindowFullscreen: () => WindowFullscreen, - WindowGetPosition: () => WindowGetPosition, - WindowGetSize: () => WindowGetSize, - WindowHide: () => WindowHide, - WindowIsFullscreen: () => WindowIsFullscreen, - WindowIsMaximised: () => WindowIsMaximised, - WindowIsMinimised: () => WindowIsMinimised, - WindowIsNormal: () => WindowIsNormal, - WindowMaximise: () => WindowMaximise, - WindowMinimise: () => WindowMinimise, - WindowReload: () => WindowReload, - WindowReloadApp: () => WindowReloadApp, - WindowSetAlwaysOnTop: () => WindowSetAlwaysOnTop, - WindowSetBackgroundColour: () => WindowSetBackgroundColour, - WindowSetDarkTheme: () => WindowSetDarkTheme, - WindowSetLightTheme: () => WindowSetLightTheme, - WindowSetMaxSize: () => WindowSetMaxSize, - WindowSetMinSize: () => WindowSetMinSize, - WindowSetPosition: () => WindowSetPosition, - WindowSetSize: () => WindowSetSize, - WindowSetSystemDefaultTheme: () => WindowSetSystemDefaultTheme, - WindowSetTitle: () => WindowSetTitle, - WindowShow: () => WindowShow, - WindowToggleMaximise: () => WindowToggleMaximise, - WindowUnfullscreen: () => WindowUnfullscreen, - WindowUnmaximise: () => WindowUnmaximise, - WindowUnminimise: () => WindowUnminimise - }); - function WindowReload() { - window.location.reload(); - } - function WindowReloadApp() { - window.WailsInvoke("WR"); - } - function WindowSetSystemDefaultTheme() { - window.WailsInvoke("WASDT"); - } - function WindowSetLightTheme() { - window.WailsInvoke("WALT"); - } - function WindowSetDarkTheme() { - window.WailsInvoke("WADT"); - } - function WindowCenter() { - window.WailsInvoke("Wc"); - } - function WindowSetTitle(title) { - window.WailsInvoke("WT" + title); - } - function WindowFullscreen() { - window.WailsInvoke("WF"); - } - function WindowUnfullscreen() { - window.WailsInvoke("Wf"); - } - function WindowIsFullscreen() { - return Call(":wails:WindowIsFullscreen"); - } - function WindowSetSize(width, height) { - window.WailsInvoke("Ws:" + width + ":" + height); - } - function WindowGetSize() { - return Call(":wails:WindowGetSize"); - } - function WindowSetMaxSize(width, height) { - window.WailsInvoke("WZ:" + width + ":" + height); - } - function WindowSetMinSize(width, height) { - window.WailsInvoke("Wz:" + width + ":" + height); - } - function WindowSetAlwaysOnTop(b) { - window.WailsInvoke("WATP:" + (b ? "1" : "0")); - } - function WindowSetPosition(x, y) { - window.WailsInvoke("Wp:" + x + ":" + y); - } - function WindowGetPosition() { - return Call(":wails:WindowGetPos"); - } - function WindowHide() { - window.WailsInvoke("WH"); - } - function WindowShow() { - window.WailsInvoke("WS"); - } - function WindowMaximise() { - window.WailsInvoke("WM"); - } - function WindowToggleMaximise() { - window.WailsInvoke("Wt"); - } - function WindowUnmaximise() { - window.WailsInvoke("WU"); - } - function WindowIsMaximised() { - return Call(":wails:WindowIsMaximised"); - } - function WindowMinimise() { - window.WailsInvoke("Wm"); - } - function WindowUnminimise() { - window.WailsInvoke("Wu"); - } - function WindowIsMinimised() { - return Call(":wails:WindowIsMinimised"); - } - function WindowIsNormal() { - return Call(":wails:WindowIsNormal"); - } - function WindowSetBackgroundColour(R, G, B, A) { - let rgba = JSON.stringify({ r: R || 0, g: G || 0, b: B || 0, a: A || 255 }); - window.WailsInvoke("Wr:" + rgba); - } - - // desktop/screen.js - var screen_exports = {}; - __export(screen_exports, { - ScreenGetAll: () => ScreenGetAll - }); - function ScreenGetAll() { - return Call(":wails:ScreenGetAll"); - } - - // desktop/browser.js - var browser_exports = {}; - __export(browser_exports, { - BrowserOpenURL: () => BrowserOpenURL - }); - function BrowserOpenURL(url) { - window.WailsInvoke("BO:" + url); - } - - // desktop/clipboard.js - var clipboard_exports = {}; - __export(clipboard_exports, { - ClipboardGetText: () => ClipboardGetText, - ClipboardSetText: () => ClipboardSetText - }); - function ClipboardSetText(text) { - return Call(":wails:ClipboardSetText", [text]); - } - function ClipboardGetText() { - return Call(":wails:ClipboardGetText"); - } - - // desktop/draganddrop.js - var draganddrop_exports = {}; - __export(draganddrop_exports, { - CanResolveFilePaths: () => CanResolveFilePaths, - OnFileDrop: () => OnFileDrop, - OnFileDropOff: () => OnFileDropOff, - ResolveFilePaths: () => ResolveFilePaths - }); - var flags = { - registered: false, - defaultUseDropTarget: true, - useDropTarget: true, - nextDeactivate: null, - nextDeactivateTimeout: null - }; - var DROP_TARGET_ACTIVE = "wails-drop-target-active"; - function checkStyleDropTarget(style) { - const cssDropValue = style.getPropertyValue(window.wails.flags.cssDropProperty).trim(); - if (cssDropValue) { - if (cssDropValue === window.wails.flags.cssDropValue) { - return true; - } - return false; - } - return false; - } - function onDragOver(e) { - const isFileDrop = e.dataTransfer.types.includes("Files"); - if (!isFileDrop) { - return; - } - e.preventDefault(); - e.dataTransfer.dropEffect = "copy"; - if (!window.wails.flags.enableWailsDragAndDrop) { - return; - } - if (!flags.useDropTarget) { - return; - } - const element = e.target; - if (flags.nextDeactivate) - flags.nextDeactivate(); - if (!element || !checkStyleDropTarget(getComputedStyle(element))) { - return; - } - let currentElement = element; - while (currentElement) { - if (checkStyleDropTarget(getComputedStyle(currentElement))) { - currentElement.classList.add(DROP_TARGET_ACTIVE); - } - currentElement = currentElement.parentElement; - } - } - function onDragLeave(e) { - const isFileDrop = e.dataTransfer.types.includes("Files"); - if (!isFileDrop) { - return; - } - e.preventDefault(); - if (!window.wails.flags.enableWailsDragAndDrop) { - return; - } - if (!flags.useDropTarget) { - return; - } - if (!e.target || !checkStyleDropTarget(getComputedStyle(e.target))) { - return null; - } - if (flags.nextDeactivate) - flags.nextDeactivate(); - flags.nextDeactivate = () => { - Array.from(document.getElementsByClassName(DROP_TARGET_ACTIVE)).forEach((el) => el.classList.remove(DROP_TARGET_ACTIVE)); - flags.nextDeactivate = null; - if (flags.nextDeactivateTimeout) { - clearTimeout(flags.nextDeactivateTimeout); - flags.nextDeactivateTimeout = null; - } - }; - flags.nextDeactivateTimeout = setTimeout(() => { - if (flags.nextDeactivate) - flags.nextDeactivate(); - }, 50); - } - function onDrop(e) { - const isFileDrop = e.dataTransfer.types.includes("Files"); - if (!isFileDrop) { - return; - } - e.preventDefault(); - if (!window.wails.flags.enableWailsDragAndDrop) { - return; - } - if (CanResolveFilePaths()) { - let files = []; - if (e.dataTransfer.items) { - files = [...e.dataTransfer.items].map((item, i) => { - if (item.kind === "file") { - return item.getAsFile(); - } - }); - } else { - files = [...e.dataTransfer.files]; - } - window.runtime.ResolveFilePaths(e.x, e.y, files); - } - if (!flags.useDropTarget) { - return; - } - if (flags.nextDeactivate) - flags.nextDeactivate(); - Array.from(document.getElementsByClassName(DROP_TARGET_ACTIVE)).forEach((el) => el.classList.remove(DROP_TARGET_ACTIVE)); - } - function CanResolveFilePaths() { - return window.chrome?.webview?.postMessageWithAdditionalObjects != null; - } - function ResolveFilePaths(x, y, files) { - if (window.chrome?.webview?.postMessageWithAdditionalObjects) { - chrome.webview.postMessageWithAdditionalObjects(`file:drop:${x}:${y}`, files); - } - } - function OnFileDrop(callback, useDropTarget) { - if (typeof callback !== "function") { - console.error("DragAndDropCallback is not a function"); - return; - } - if (flags.registered) { - return; - } - flags.registered = true; - const uDTPT = typeof useDropTarget; - flags.useDropTarget = uDTPT === "undefined" || uDTPT !== "boolean" ? flags.defaultUseDropTarget : useDropTarget; - window.addEventListener("dragover", onDragOver); - window.addEventListener("dragleave", onDragLeave); - window.addEventListener("drop", onDrop); - let cb = callback; - if (flags.useDropTarget) { - cb = function(x, y, paths) { - const element = document.elementFromPoint(x, y); - if (!element || !checkStyleDropTarget(getComputedStyle(element))) { - return null; - } - callback(x, y, paths); - }; - } - EventsOn("wails:file-drop", cb); - } - function OnFileDropOff() { - window.removeEventListener("dragover", onDragOver); - window.removeEventListener("dragleave", onDragLeave); - window.removeEventListener("drop", onDrop); - EventsOff("wails:file-drop"); - flags.registered = false; - } - - // desktop/contextmenu.js - function processDefaultContextMenu(event) { - const element = event.target; - const computedStyle = window.getComputedStyle(element); - const defaultContextMenuAction = computedStyle.getPropertyValue("--default-contextmenu").trim(); - switch (defaultContextMenuAction) { - case "show": - return; - case "hide": - event.preventDefault(); - return; - default: - if (element.isContentEditable) { - return; - } - const selection = window.getSelection(); - const hasSelection = selection.toString().length > 0; - if (hasSelection) { - for (let i = 0; i < selection.rangeCount; i++) { - const range = selection.getRangeAt(i); - const rects = range.getClientRects(); - for (let j = 0; j < rects.length; j++) { - const rect = rects[j]; - if (document.elementFromPoint(rect.left, rect.top) === element) { - return; - } - } - } - } - if (element.tagName === "INPUT" || element.tagName === "TEXTAREA") { - if (hasSelection || !element.readOnly && !element.disabled) { - return; - } - } - event.preventDefault(); - } - } - - // desktop/main.js - function Quit() { - window.WailsInvoke("Q"); - } - function Show() { - window.WailsInvoke("S"); - } - function Hide() { - window.WailsInvoke("H"); - } - function Environment() { - return Call(":wails:Environment"); - } - window.runtime = { - ...log_exports, - ...window_exports, - ...browser_exports, - ...screen_exports, - ...clipboard_exports, - ...draganddrop_exports, - EventsOn, - EventsOnce, - EventsOnMultiple, - EventsEmit, - EventsOff, - EventsOffAll, - Environment, - Show, - Hide, - Quit - }; - window.wails = { - Callback, - EventsNotify, - SetBindings, - eventListeners, - callbacks, - flags: { - disableScrollbarDrag: false, - disableDefaultContextMenu: false, - enableResize: false, - defaultCursor: null, - borderThickness: 6, - shouldDrag: false, - deferDragToMouseMove: true, - cssDragProperty: "--wails-draggable", - cssDragValue: "drag", - cssDropProperty: "--wails-drop-target", - cssDropValue: "drop", - enableWailsDragAndDrop: false - } - }; - if (window.wailsbindings) { - window.wails.SetBindings(window.wailsbindings); - delete window.wails.SetBindings; - } - if (false) { - delete window.wailsbindings; - } - var dragTest = function(e) { - var val = window.getComputedStyle(e.target).getPropertyValue(window.wails.flags.cssDragProperty); - if (val) { - val = val.trim(); - } - if (val !== window.wails.flags.cssDragValue) { - return false; - } - if (e.buttons !== 1) { - return false; - } - if (e.detail !== 1) { - return false; - } - return true; - }; - window.wails.setCSSDragProperties = function(property, value) { - window.wails.flags.cssDragProperty = property; - window.wails.flags.cssDragValue = value; - }; - window.wails.setCSSDropProperties = function(property, value) { - window.wails.flags.cssDropProperty = property; - window.wails.flags.cssDropValue = value; - }; - window.addEventListener("mousedown", (e) => { - if (window.wails.flags.resizeEdge) { - window.WailsInvoke("resize:" + window.wails.flags.resizeEdge); - e.preventDefault(); - return; - } - if (dragTest(e)) { - if (window.wails.flags.disableScrollbarDrag) { - if (e.offsetX > e.target.clientWidth || e.offsetY > e.target.clientHeight) { - return; - } - } - if (window.wails.flags.deferDragToMouseMove) { - window.wails.flags.shouldDrag = true; - } else { - e.preventDefault(); - window.WailsInvoke("drag"); - } - return; - } else { - window.wails.flags.shouldDrag = false; - } - }); - window.addEventListener("mouseup", () => { - window.wails.flags.shouldDrag = false; - }); - function setResize(cursor) { - document.documentElement.style.cursor = cursor || window.wails.flags.defaultCursor; - window.wails.flags.resizeEdge = cursor; - } - window.addEventListener("mousemove", function(e) { - if (window.wails.flags.shouldDrag) { - window.wails.flags.shouldDrag = false; - let mousePressed = e.buttons !== void 0 ? e.buttons : e.which; - if (mousePressed > 0) { - window.WailsInvoke("drag"); - return; - } - } - if (!window.wails.flags.enableResize) { - return; - } - if (window.wails.flags.defaultCursor == null) { - window.wails.flags.defaultCursor = document.documentElement.style.cursor; - } - if (window.outerWidth - e.clientX < window.wails.flags.borderThickness && window.outerHeight - e.clientY < window.wails.flags.borderThickness) { - document.documentElement.style.cursor = "se-resize"; - } - let rightBorder = window.outerWidth - e.clientX < window.wails.flags.borderThickness; - let leftBorder = e.clientX < window.wails.flags.borderThickness; - let topBorder = e.clientY < window.wails.flags.borderThickness; - let bottomBorder = window.outerHeight - e.clientY < window.wails.flags.borderThickness; - if (!leftBorder && !rightBorder && !topBorder && !bottomBorder && window.wails.flags.resizeEdge !== void 0) { - setResize(); - } else if (rightBorder && bottomBorder) - setResize("se-resize"); - else if (leftBorder && bottomBorder) - setResize("sw-resize"); - else if (leftBorder && topBorder) - setResize("nw-resize"); - else if (topBorder && rightBorder) - setResize("ne-resize"); - else if (leftBorder) - setResize("w-resize"); - else if (topBorder) - setResize("n-resize"); - else if (bottomBorder) - setResize("s-resize"); - else if (rightBorder) - setResize("e-resize"); - }); - window.addEventListener("contextmenu", function(e) { - if (true) - return; - if (window.wails.flags.disableDefaultContextMenu) { - e.preventDefault(); - } else { - processDefaultContextMenu(e); - } - }); - window.WailsInvoke("runtime:ready"); -})(); -//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiZGVza3RvcC9sb2cuanMiLCAiZGVza3RvcC9ldmVudHMuanMiLCAiZGVza3RvcC9jYWxscy5qcyIsICJkZXNrdG9wL2JpbmRpbmdzLmpzIiwgImRlc2t0b3Avd2luZG93LmpzIiwgImRlc2t0b3Avc2NyZWVuLmpzIiwgImRlc2t0b3AvYnJvd3Nlci5qcyIsICJkZXNrdG9wL2NsaXBib2FyZC5qcyIsICJkZXNrdG9wL2RyYWdhbmRkcm9wLmpzIiwgImRlc2t0b3AvY29udGV4dG1lbnUuanMiLCAiZGVza3RvcC9tYWluLmpzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKlxyXG4gXyAgICAgICBfXyAgICAgIF8gX19cclxufCB8ICAgICAvIC9fX18gXyhfKSAvX19fX1xyXG58IHwgL3wgLyAvIF9fIGAvIC8gLyBfX18vXHJcbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxyXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cclxuVGhlIGVsZWN0cm9uIGFsdGVybmF0aXZlIGZvciBHb1xyXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XHJcbiovXHJcblxyXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA2ICovXHJcblxyXG4vKipcclxuICogU2VuZHMgYSBsb2cgbWVzc2FnZSB0byB0aGUgYmFja2VuZCB3aXRoIHRoZSBnaXZlbiBsZXZlbCArIG1lc3NhZ2VcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGxldmVsXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlXHJcbiAqL1xyXG5mdW5jdGlvbiBzZW5kTG9nTWVzc2FnZShsZXZlbCwgbWVzc2FnZSkge1xyXG5cclxuXHQvLyBMb2cgTWVzc2FnZSBmb3JtYXQ6XHJcblx0Ly8gbFt0eXBlXVttZXNzYWdlXVxyXG5cdHdpbmRvdy5XYWlsc0ludm9rZSgnTCcgKyBsZXZlbCArIG1lc3NhZ2UpO1xyXG59XHJcblxyXG4vKipcclxuICogTG9nIHRoZSBnaXZlbiB0cmFjZSBtZXNzYWdlIHdpdGggdGhlIGJhY2tlbmRcclxuICpcclxuICogQGV4cG9ydFxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIExvZ1RyYWNlKG1lc3NhZ2UpIHtcclxuXHRzZW5kTG9nTWVzc2FnZSgnVCcsIG1lc3NhZ2UpO1xyXG59XHJcblxyXG4vKipcclxuICogTG9nIHRoZSBnaXZlbiBtZXNzYWdlIHdpdGggdGhlIGJhY2tlbmRcclxuICpcclxuICogQGV4cG9ydFxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIExvZ1ByaW50KG1lc3NhZ2UpIHtcclxuXHRzZW5kTG9nTWVzc2FnZSgnUCcsIG1lc3NhZ2UpO1xyXG59XHJcblxyXG4vKipcclxuICogTG9nIHRoZSBnaXZlbiBkZWJ1ZyBtZXNzYWdlIHdpdGggdGhlIGJhY2tlbmRcclxuICpcclxuICogQGV4cG9ydFxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIExvZ0RlYnVnKG1lc3NhZ2UpIHtcclxuXHRzZW5kTG9nTWVzc2FnZSgnRCcsIG1lc3NhZ2UpO1xyXG59XHJcblxyXG4vKipcclxuICogTG9nIHRoZSBnaXZlbiBpbmZvIG1lc3NhZ2Ugd2l0aCB0aGUgYmFja2VuZFxyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gTG9nSW5mbyhtZXNzYWdlKSB7XHJcblx0c2VuZExvZ01lc3NhZ2UoJ0knLCBtZXNzYWdlKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIExvZyB0aGUgZ2l2ZW4gd2FybmluZyBtZXNzYWdlIHdpdGggdGhlIGJhY2tlbmRcclxuICpcclxuICogQGV4cG9ydFxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIExvZ1dhcm5pbmcobWVzc2FnZSkge1xyXG5cdHNlbmRMb2dNZXNzYWdlKCdXJywgbWVzc2FnZSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2cgdGhlIGdpdmVuIGVycm9yIG1lc3NhZ2Ugd2l0aCB0aGUgYmFja2VuZFxyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gTG9nRXJyb3IobWVzc2FnZSkge1xyXG5cdHNlbmRMb2dNZXNzYWdlKCdFJywgbWVzc2FnZSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2cgdGhlIGdpdmVuIGZhdGFsIG1lc3NhZ2Ugd2l0aCB0aGUgYmFja2VuZFxyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gTG9nRmF0YWwobWVzc2FnZSkge1xyXG5cdHNlbmRMb2dNZXNzYWdlKCdGJywgbWVzc2FnZSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBMb2cgbGV2ZWwgdG8gdGhlIGdpdmVuIGxvZyBsZXZlbFxyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBsb2dsZXZlbFxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIFNldExvZ0xldmVsKGxvZ2xldmVsKSB7XHJcblx0c2VuZExvZ01lc3NhZ2UoJ1MnLCBsb2dsZXZlbCk7XHJcbn1cclxuXHJcbi8vIExvZyBsZXZlbHNcclxuZXhwb3J0IGNvbnN0IExvZ0xldmVsID0ge1xyXG5cdFRSQUNFOiAxLFxyXG5cdERFQlVHOiAyLFxyXG5cdElORk86IDMsXHJcblx0V0FSTklORzogNCxcclxuXHRFUlJPUjogNSxcclxufTtcclxuIiwgIi8qXHJcbiBfICAgICAgIF9fICAgICAgXyBfX1xyXG58IHwgICAgIC8gL19fXyBfKF8pIC9fX19fXHJcbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cclxufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXHJcbnxfXy98X18vXFxfXyxfL18vXy9fX19fL1xyXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXHJcbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcclxuKi9cclxuLyoganNoaW50IGVzdmVyc2lvbjogNiAqL1xyXG5cclxuLy8gRGVmaW5lcyBhIHNpbmdsZSBsaXN0ZW5lciB3aXRoIGEgbWF4aW11bSBudW1iZXIgb2YgdGltZXMgdG8gY2FsbGJhY2tcclxuXHJcbi8qKlxyXG4gKiBUaGUgTGlzdGVuZXIgY2xhc3MgZGVmaW5lcyBhIGxpc3RlbmVyISA6LSlcclxuICpcclxuICogQGNsYXNzIExpc3RlbmVyXHJcbiAqL1xyXG5jbGFzcyBMaXN0ZW5lciB7XHJcbiAgICAvKipcclxuICAgICAqIENyZWF0ZXMgYW4gaW5zdGFuY2Ugb2YgTGlzdGVuZXIuXHJcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gZXZlbnROYW1lXHJcbiAgICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBjYWxsYmFja1xyXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IG1heENhbGxiYWNrc1xyXG4gICAgICogQG1lbWJlcm9mIExpc3RlbmVyXHJcbiAgICAgKi9cclxuICAgIGNvbnN0cnVjdG9yKGV2ZW50TmFtZSwgY2FsbGJhY2ssIG1heENhbGxiYWNrcykge1xyXG4gICAgICAgIHRoaXMuZXZlbnROYW1lID0gZXZlbnROYW1lO1xyXG4gICAgICAgIC8vIERlZmF1bHQgb2YgLTEgbWVhbnMgaW5maW5pdGVcclxuICAgICAgICB0aGlzLm1heENhbGxiYWNrcyA9IG1heENhbGxiYWNrcyB8fCAtMTtcclxuICAgICAgICAvLyBDYWxsYmFjayBpbnZva2VzIHRoZSBjYWxsYmFjayB3aXRoIHRoZSBnaXZlbiBkYXRhXHJcbiAgICAgICAgLy8gUmV0dXJucyB0cnVlIGlmIHRoaXMgbGlzdGVuZXIgc2hvdWxkIGJlIGRlc3Ryb3llZFxyXG4gICAgICAgIHRoaXMuQ2FsbGJhY2sgPSAoZGF0YSkgPT4ge1xyXG4gICAgICAgICAgICBjYWxsYmFjay5hcHBseShudWxsLCBkYXRhKTtcclxuICAgICAgICAgICAgLy8gSWYgbWF4Q2FsbGJhY2tzIGlzIGluZmluaXRlLCByZXR1cm4gZmFsc2UgKGRvIG5vdCBkZXN0cm95KVxyXG4gICAgICAgICAgICBpZiAodGhpcy5tYXhDYWxsYmFja3MgPT09IC0xKSB7XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgLy8gRGVjcmVtZW50IG1heENhbGxiYWNrcy4gUmV0dXJuIHRydWUgaWYgbm93IDAsIG90aGVyd2lzZSBmYWxzZVxyXG4gICAgICAgICAgICB0aGlzLm1heENhbGxiYWNrcyAtPSAxO1xyXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5tYXhDYWxsYmFja3MgPT09IDA7XHJcbiAgICAgICAgfTtcclxuICAgIH1cclxufVxyXG5cclxuZXhwb3J0IGNvbnN0IGV2ZW50TGlzdGVuZXJzID0ge307XHJcblxyXG4vKipcclxuICogUmVnaXN0ZXJzIGFuIGV2ZW50IGxpc3RlbmVyIHRoYXQgd2lsbCBiZSBpbnZva2VkIGBtYXhDYWxsYmFja3NgIHRpbWVzIGJlZm9yZSBiZWluZyBkZXN0cm95ZWRcclxuICpcclxuICogQGV4cG9ydFxyXG4gKiBAcGFyYW0ge3N0cmluZ30gZXZlbnROYW1lXHJcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGNhbGxiYWNrXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBtYXhDYWxsYmFja3NcclxuICogQHJldHVybnMge2Z1bmN0aW9ufSBBIGZ1bmN0aW9uIHRvIGNhbmNlbCB0aGUgbGlzdGVuZXJcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBFdmVudHNPbk11bHRpcGxlKGV2ZW50TmFtZSwgY2FsbGJhY2ssIG1heENhbGxiYWNrcykge1xyXG4gICAgZXZlbnRMaXN0ZW5lcnNbZXZlbnROYW1lXSA9IGV2ZW50TGlzdGVuZXJzW2V2ZW50TmFtZV0gfHwgW107XHJcbiAgICBjb25zdCB0aGlzTGlzdGVuZXIgPSBuZXcgTGlzdGVuZXIoZXZlbnROYW1lLCBjYWxsYmFjaywgbWF4Q2FsbGJhY2tzKTtcclxuICAgIGV2ZW50TGlzdGVuZXJzW2V2ZW50TmFtZV0ucHVzaCh0aGlzTGlzdGVuZXIpO1xyXG4gICAgcmV0dXJuICgpID0+IGxpc3RlbmVyT2ZmKHRoaXNMaXN0ZW5lcik7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZWdpc3RlcnMgYW4gZXZlbnQgbGlzdGVuZXIgdGhhdCB3aWxsIGJlIGludm9rZWQgZXZlcnkgdGltZSB0aGUgZXZlbnQgaXMgZW1pdHRlZFxyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBldmVudE5hbWVcclxuICogQHBhcmFtIHtmdW5jdGlvbn0gY2FsbGJhY2tcclxuICogQHJldHVybnMge2Z1bmN0aW9ufSBBIGZ1bmN0aW9uIHRvIGNhbmNlbCB0aGUgbGlzdGVuZXJcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBFdmVudHNPbihldmVudE5hbWUsIGNhbGxiYWNrKSB7XHJcbiAgICByZXR1cm4gRXZlbnRzT25NdWx0aXBsZShldmVudE5hbWUsIGNhbGxiYWNrLCAtMSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZWdpc3RlcnMgYW4gZXZlbnQgbGlzdGVuZXIgdGhhdCB3aWxsIGJlIGludm9rZWQgb25jZSB0aGVuIGRlc3Ryb3llZFxyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBldmVudE5hbWVcclxuICogQHBhcmFtIHtmdW5jdGlvbn0gY2FsbGJhY2tcclxuICogQHJldHVybnMge2Z1bmN0aW9ufSBBIGZ1bmN0aW9uIHRvIGNhbmNlbCB0aGUgbGlzdGVuZXJcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBFdmVudHNPbmNlKGV2ZW50TmFtZSwgY2FsbGJhY2spIHtcclxuICAgIHJldHVybiBFdmVudHNPbk11bHRpcGxlKGV2ZW50TmFtZSwgY2FsbGJhY2ssIDEpO1xyXG59XHJcblxyXG5mdW5jdGlvbiBub3RpZnlMaXN0ZW5lcnMoZXZlbnREYXRhKSB7XHJcblxyXG4gICAgLy8gR2V0IHRoZSBldmVudCBuYW1lXHJcbiAgICBsZXQgZXZlbnROYW1lID0gZXZlbnREYXRhLm5hbWU7XHJcblxyXG4gICAgLy8gS2VlcCBhIGxpc3Qgb2YgbGlzdGVuZXIgaW5kZXhlcyB0byBkZXN0cm95XHJcbiAgICBjb25zdCBuZXdFdmVudExpc3RlbmVyTGlzdCA9IGV2ZW50TGlzdGVuZXJzW2V2ZW50TmFtZV0/LnNsaWNlKCkgfHwgW107XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgd2UgaGF2ZSBhbnkgbGlzdGVuZXJzIGZvciB0aGlzIGV2ZW50XHJcbiAgICBpZiAobmV3RXZlbnRMaXN0ZW5lckxpc3QubGVuZ3RoKSB7XHJcblxyXG4gICAgICAgIC8vIEl0ZXJhdGUgbGlzdGVuZXJzXHJcbiAgICAgICAgZm9yIChsZXQgY291bnQgPSBuZXdFdmVudExpc3RlbmVyTGlzdC5sZW5ndGggLSAxOyBjb3VudCA+PSAwOyBjb3VudCAtPSAxKSB7XHJcblxyXG4gICAgICAgICAgICAvLyBHZXQgbmV4dCBsaXN0ZW5lclxyXG4gICAgICAgICAgICBjb25zdCBsaXN0ZW5lciA9IG5ld0V2ZW50TGlzdGVuZXJMaXN0W2NvdW50XTtcclxuXHJcbiAgICAgICAgICAgIGxldCBkYXRhID0gZXZlbnREYXRhLmRhdGE7XHJcblxyXG4gICAgICAgICAgICAvLyBEbyB0aGUgY2FsbGJhY2tcclxuICAgICAgICAgICAgY29uc3QgZGVzdHJveSA9IGxpc3RlbmVyLkNhbGxiYWNrKGRhdGEpO1xyXG4gICAgICAgICAgICBpZiAoZGVzdHJveSkge1xyXG4gICAgICAgICAgICAgICAgLy8gaWYgdGhlIGxpc3RlbmVyIGluZGljYXRlZCB0byBkZXN0cm95IGl0c2VsZiwgYWRkIGl0IHRvIHRoZSBkZXN0cm95IGxpc3RcclxuICAgICAgICAgICAgICAgIG5ld0V2ZW50TGlzdGVuZXJMaXN0LnNwbGljZShjb3VudCwgMSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFVwZGF0ZSBjYWxsYmFja3Mgd2l0aCBuZXcgbGlzdCBvZiBsaXN0ZW5lcnNcclxuICAgICAgICBpZiAobmV3RXZlbnRMaXN0ZW5lckxpc3QubGVuZ3RoID09PSAwKSB7XHJcbiAgICAgICAgICAgIHJlbW92ZUxpc3RlbmVyKGV2ZW50TmFtZSk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgZXZlbnRMaXN0ZW5lcnNbZXZlbnROYW1lXSA9IG5ld0V2ZW50TGlzdGVuZXJMaXN0O1xyXG4gICAgICAgIH1cclxuICAgIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIE5vdGlmeSBpbmZvcm1zIGZyb250ZW5kIGxpc3RlbmVycyB0aGF0IGFuIGV2ZW50IHdhcyBlbWl0dGVkIHdpdGggdGhlIGdpdmVuIGRhdGFcclxuICpcclxuICogQGV4cG9ydFxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbm90aWZ5TWVzc2FnZSAtIGVuY29kZWQgbm90aWZpY2F0aW9uIG1lc3NhZ2VcclxuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gRXZlbnRzTm90aWZ5KG5vdGlmeU1lc3NhZ2UpIHtcclxuICAgIC8vIFBhcnNlIHRoZSBtZXNzYWdlXHJcbiAgICBsZXQgbWVzc2FnZTtcclxuICAgIHRyeSB7XHJcbiAgICAgICAgbWVzc2FnZSA9IEpTT04ucGFyc2Uobm90aWZ5TWVzc2FnZSk7XHJcbiAgICB9IGNhdGNoIChlKSB7XHJcbiAgICAgICAgY29uc3QgZXJyb3IgPSAnSW52YWxpZCBKU09OIHBhc3NlZCB0byBOb3RpZnk6ICcgKyBub3RpZnlNZXNzYWdlO1xyXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihlcnJvcik7XHJcbiAgICB9XHJcbiAgICBub3RpZnlMaXN0ZW5lcnMobWVzc2FnZSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFbWl0IGFuIGV2ZW50IHdpdGggdGhlIGdpdmVuIG5hbWUgYW5kIGRhdGFcclxuICpcclxuICogQGV4cG9ydFxyXG4gKiBAcGFyYW0ge3N0cmluZ30gZXZlbnROYW1lXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gRXZlbnRzRW1pdChldmVudE5hbWUpIHtcclxuXHJcbiAgICBjb25zdCBwYXlsb2FkID0ge1xyXG4gICAgICAgIG5hbWU6IGV2ZW50TmFtZSxcclxuICAgICAgICBkYXRhOiBbXS5zbGljZS5hcHBseShhcmd1bWVudHMpLnNsaWNlKDEpLFxyXG4gICAgfTtcclxuXHJcbiAgICAvLyBOb3RpZnkgSlMgbGlzdGVuZXJzXHJcbiAgICBub3RpZnlMaXN0ZW5lcnMocGF5bG9hZCk7XHJcblxyXG4gICAgLy8gTm90aWZ5IEdvIGxpc3RlbmVyc1xyXG4gICAgd2luZG93LldhaWxzSW52b2tlKCdFRScgKyBKU09OLnN0cmluZ2lmeShwYXlsb2FkKSk7XHJcbn1cclxuXHJcbmZ1bmN0aW9uIHJlbW92ZUxpc3RlbmVyKGV2ZW50TmFtZSkge1xyXG4gICAgLy8gUmVtb3ZlIGxvY2FsIGxpc3RlbmVyc1xyXG4gICAgZGVsZXRlIGV2ZW50TGlzdGVuZXJzW2V2ZW50TmFtZV07XHJcblxyXG4gICAgLy8gTm90aWZ5IEdvIGxpc3RlbmVyc1xyXG4gICAgd2luZG93LldhaWxzSW52b2tlKCdFWCcgKyBldmVudE5hbWUpO1xyXG59XHJcblxyXG4vKipcclxuICogT2ZmIHVucmVnaXN0ZXJzIGEgbGlzdGVuZXIgcHJldmlvdXNseSByZWdpc3RlcmVkIHdpdGggT24sXHJcbiAqIG9wdGlvbmFsbHkgbXVsdGlwbGUgbGlzdGVuZXJlcyBjYW4gYmUgdW5yZWdpc3RlcmVkIHZpYSBgYWRkaXRpb25hbEV2ZW50TmFtZXNgXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBldmVudE5hbWVcclxuICogQHBhcmFtICB7Li4uc3RyaW5nfSBhZGRpdGlvbmFsRXZlbnROYW1lc1xyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIEV2ZW50c09mZihldmVudE5hbWUsIC4uLmFkZGl0aW9uYWxFdmVudE5hbWVzKSB7XHJcbiAgICByZW1vdmVMaXN0ZW5lcihldmVudE5hbWUpXHJcblxyXG4gICAgaWYgKGFkZGl0aW9uYWxFdmVudE5hbWVzLmxlbmd0aCA+IDApIHtcclxuICAgICAgICBhZGRpdGlvbmFsRXZlbnROYW1lcy5mb3JFYWNoKGV2ZW50TmFtZSA9PiB7XHJcbiAgICAgICAgICAgIHJlbW92ZUxpc3RlbmVyKGV2ZW50TmFtZSlcclxuICAgICAgICB9KVxyXG4gICAgfVxyXG59XHJcblxyXG4vKipcclxuICogT2ZmIHVucmVnaXN0ZXJzIGFsbCBldmVudCBsaXN0ZW5lcnMgcHJldmlvdXNseSByZWdpc3RlcmVkIHdpdGggT25cclxuICovXHJcbiBleHBvcnQgZnVuY3Rpb24gRXZlbnRzT2ZmQWxsKCkge1xyXG4gICAgY29uc3QgZXZlbnROYW1lcyA9IE9iamVjdC5rZXlzKGV2ZW50TGlzdGVuZXJzKTtcclxuICAgIGV2ZW50TmFtZXMuZm9yRWFjaChldmVudE5hbWUgPT4ge1xyXG4gICAgICAgIHJlbW92ZUxpc3RlbmVyKGV2ZW50TmFtZSlcclxuICAgIH0pXHJcbn1cclxuXHJcbi8qKlxyXG4gKiBsaXN0ZW5lck9mZiB1bnJlZ2lzdGVycyBhIGxpc3RlbmVyIHByZXZpb3VzbHkgcmVnaXN0ZXJlZCB3aXRoIEV2ZW50c09uXHJcbiAqXHJcbiAqIEBwYXJhbSB7TGlzdGVuZXJ9IGxpc3RlbmVyXHJcbiAqL1xyXG4gZnVuY3Rpb24gbGlzdGVuZXJPZmYobGlzdGVuZXIpIHtcclxuICAgIGNvbnN0IGV2ZW50TmFtZSA9IGxpc3RlbmVyLmV2ZW50TmFtZTtcclxuICAgIGlmIChldmVudExpc3RlbmVyc1tldmVudE5hbWVdID09PSB1bmRlZmluZWQpIHJldHVybjtcclxuXHJcbiAgICAvLyBSZW1vdmUgbG9jYWwgbGlzdGVuZXJcclxuICAgIGV2ZW50TGlzdGVuZXJzW2V2ZW50TmFtZV0gPSBldmVudExpc3RlbmVyc1tldmVudE5hbWVdLmZpbHRlcihsID0+IGwgIT09IGxpc3RlbmVyKTtcclxuXHJcbiAgICAvLyBDbGVhbiB1cCBpZiB0aGVyZSBhcmUgbm8gZXZlbnQgbGlzdGVuZXJzIGxlZnRcclxuICAgIGlmIChldmVudExpc3RlbmVyc1tldmVudE5hbWVdLmxlbmd0aCA9PT0gMCkge1xyXG4gICAgICAgIHJlbW92ZUxpc3RlbmVyKGV2ZW50TmFtZSk7XHJcbiAgICB9XHJcbn1cclxuIiwgIi8qXHJcbiBfICAgICAgIF9fICAgICAgXyBfX1xyXG58IHwgICAgIC8gL19fXyBfKF8pIC9fX19fXHJcbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cclxufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXHJcbnxfXy98X18vXFxfXyxfL18vXy9fX19fL1xyXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXHJcbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcclxuKi9cclxuLyoganNoaW50IGVzdmVyc2lvbjogNiAqL1xyXG5cclxuZXhwb3J0IGNvbnN0IGNhbGxiYWNrcyA9IHt9O1xyXG5cclxuLyoqXHJcbiAqIFJldHVybnMgYSBudW1iZXIgZnJvbSB0aGUgbmF0aXZlIGJyb3dzZXIgcmFuZG9tIGZ1bmN0aW9uXHJcbiAqXHJcbiAqIEByZXR1cm5zIG51bWJlclxyXG4gKi9cclxuZnVuY3Rpb24gY3J5cHRvUmFuZG9tKCkge1xyXG5cdHZhciBhcnJheSA9IG5ldyBVaW50MzJBcnJheSgxKTtcclxuXHRyZXR1cm4gd2luZG93LmNyeXB0by5nZXRSYW5kb21WYWx1ZXMoYXJyYXkpWzBdO1xyXG59XHJcblxyXG4vKipcclxuICogUmV0dXJucyBhIG51bWJlciB1c2luZyBkYSBvbGQtc2tvb2wgTWF0aC5SYW5kb21cclxuICogSSBsaWtlcyB0byBjYWxsIGl0IExPTFJhbmRvbVxyXG4gKlxyXG4gKiBAcmV0dXJucyBudW1iZXJcclxuICovXHJcbmZ1bmN0aW9uIGJhc2ljUmFuZG9tKCkge1xyXG5cdHJldHVybiBNYXRoLnJhbmRvbSgpICogOTAwNzE5OTI1NDc0MDk5MTtcclxufVxyXG5cclxuLy8gUGljayBhIHJhbmRvbSBudW1iZXIgZnVuY3Rpb24gYmFzZWQgb24gYnJvd3NlciBjYXBhYmlsaXR5XHJcbnZhciByYW5kb21GdW5jO1xyXG5pZiAod2luZG93LmNyeXB0bykge1xyXG5cdHJhbmRvbUZ1bmMgPSBjcnlwdG9SYW5kb207XHJcbn0gZWxzZSB7XHJcblx0cmFuZG9tRnVuYyA9IGJhc2ljUmFuZG9tO1xyXG59XHJcblxyXG5cclxuLyoqXHJcbiAqIENhbGwgc2VuZHMgYSBtZXNzYWdlIHRvIHRoZSBiYWNrZW5kIHRvIGNhbGwgdGhlIGJpbmRpbmcgd2l0aCB0aGVcclxuICogZ2l2ZW4gZGF0YS4gQSBwcm9taXNlIGlzIHJldHVybmVkIGFuZCB3aWxsIGJlIGNvbXBsZXRlZCB3aGVuIHRoZVxyXG4gKiBiYWNrZW5kIHJlc3BvbmRzLiBUaGlzIHdpbGwgYmUgcmVzb2x2ZWQgd2hlbiB0aGUgY2FsbCB3YXMgc3VjY2Vzc2Z1bFxyXG4gKiBvciByZWplY3RlZCBpZiBhbiBlcnJvciBpcyBwYXNzZWQgYmFjay5cclxuICogVGhlcmUgaXMgYSB0aW1lb3V0IG1lY2hhbmlzbS4gSWYgdGhlIGNhbGwgZG9lc24ndCByZXNwb25kIGluIHRoZSBnaXZlblxyXG4gKiB0aW1lIChpbiBtaWxsaXNlY29uZHMpIHRoZW4gdGhlIHByb21pc2UgaXMgcmVqZWN0ZWQuXHJcbiAqXHJcbiAqIEBleHBvcnRcclxuICogQHBhcmFtIHtzdHJpbmd9IG5hbWVcclxuICogQHBhcmFtIHthbnk9fSBhcmdzXHJcbiAqIEBwYXJhbSB7bnVtYmVyPX0gdGltZW91dFxyXG4gKiBAcmV0dXJuc1xyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIENhbGwobmFtZSwgYXJncywgdGltZW91dCkge1xyXG5cclxuXHQvLyBUaW1lb3V0IGluZmluaXRlIGJ5IGRlZmF1bHRcclxuXHRpZiAodGltZW91dCA9PSBudWxsKSB7XHJcblx0XHR0aW1lb3V0ID0gMDtcclxuXHR9XHJcblxyXG5cdC8vIENyZWF0ZSBhIHByb21pc2VcclxuXHRyZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24gKHJlc29sdmUsIHJlamVjdCkge1xyXG5cclxuXHRcdC8vIENyZWF0ZSBhIHVuaXF1ZSBjYWxsYmFja0lEXHJcblx0XHR2YXIgY2FsbGJhY2tJRDtcclxuXHRcdGRvIHtcclxuXHRcdFx0Y2FsbGJhY2tJRCA9IG5hbWUgKyAnLScgKyByYW5kb21GdW5jKCk7XHJcblx0XHR9IHdoaWxlIChjYWxsYmFja3NbY2FsbGJhY2tJRF0pO1xyXG5cclxuXHRcdHZhciB0aW1lb3V0SGFuZGxlO1xyXG5cdFx0Ly8gU2V0IHRpbWVvdXRcclxuXHRcdGlmICh0aW1lb3V0ID4gMCkge1xyXG5cdFx0XHR0aW1lb3V0SGFuZGxlID0gc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XHJcblx0XHRcdFx0cmVqZWN0KEVycm9yKCdDYWxsIHRvICcgKyBuYW1lICsgJyB0aW1lZCBvdXQuIFJlcXVlc3QgSUQ6ICcgKyBjYWxsYmFja0lEKSk7XHJcblx0XHRcdH0sIHRpbWVvdXQpO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8vIFN0b3JlIGNhbGxiYWNrXHJcblx0XHRjYWxsYmFja3NbY2FsbGJhY2tJRF0gPSB7XHJcblx0XHRcdHRpbWVvdXRIYW5kbGU6IHRpbWVvdXRIYW5kbGUsXHJcblx0XHRcdHJlamVjdDogcmVqZWN0LFxyXG5cdFx0XHRyZXNvbHZlOiByZXNvbHZlXHJcblx0XHR9O1xyXG5cclxuXHRcdHRyeSB7XHJcblx0XHRcdGNvbnN0IHBheWxvYWQgPSB7XHJcblx0XHRcdFx0bmFtZSxcclxuXHRcdFx0XHRhcmdzLFxyXG5cdFx0XHRcdGNhbGxiYWNrSUQsXHJcblx0XHRcdH07XHJcblxyXG4gICAgICAgICAgICAvLyBNYWtlIHRoZSBjYWxsXHJcbiAgICAgICAgICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnQycgKyBKU09OLnN0cmluZ2lmeShwYXlsb2FkKSk7XHJcbiAgICAgICAgfSBjYXRjaCAoZSkge1xyXG4gICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmVcclxuICAgICAgICAgICAgY29uc29sZS5lcnJvcihlKTtcclxuICAgICAgICB9XHJcbiAgICB9KTtcclxufVxyXG5cclxud2luZG93Lk9iZnVzY2F0ZWRDYWxsID0gKGlkLCBhcmdzLCB0aW1lb3V0KSA9PiB7XHJcblxyXG4gICAgLy8gVGltZW91dCBpbmZpbml0ZSBieSBkZWZhdWx0XHJcbiAgICBpZiAodGltZW91dCA9PSBudWxsKSB7XHJcbiAgICAgICAgdGltZW91dCA9IDA7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ3JlYXRlIGEgcHJvbWlzZVxyXG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHtcclxuXHJcbiAgICAgICAgLy8gQ3JlYXRlIGEgdW5pcXVlIGNhbGxiYWNrSURcclxuICAgICAgICB2YXIgY2FsbGJhY2tJRDtcclxuICAgICAgICBkbyB7XHJcbiAgICAgICAgICAgIGNhbGxiYWNrSUQgPSBpZCArICctJyArIHJhbmRvbUZ1bmMoKTtcclxuICAgICAgICB9IHdoaWxlIChjYWxsYmFja3NbY2FsbGJhY2tJRF0pO1xyXG5cclxuICAgICAgICB2YXIgdGltZW91dEhhbmRsZTtcclxuICAgICAgICAvLyBTZXQgdGltZW91dFxyXG4gICAgICAgIGlmICh0aW1lb3V0ID4gMCkge1xyXG4gICAgICAgICAgICB0aW1lb3V0SGFuZGxlID0gc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgICAgICByZWplY3QoRXJyb3IoJ0NhbGwgdG8gbWV0aG9kICcgKyBpZCArICcgdGltZWQgb3V0LiBSZXF1ZXN0IElEOiAnICsgY2FsbGJhY2tJRCkpO1xyXG4gICAgICAgICAgICB9LCB0aW1lb3V0KTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFN0b3JlIGNhbGxiYWNrXHJcbiAgICAgICAgY2FsbGJhY2tzW2NhbGxiYWNrSURdID0ge1xyXG4gICAgICAgICAgICB0aW1lb3V0SGFuZGxlOiB0aW1lb3V0SGFuZGxlLFxyXG4gICAgICAgICAgICByZWplY3Q6IHJlamVjdCxcclxuICAgICAgICAgICAgcmVzb2x2ZTogcmVzb2x2ZVxyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIGNvbnN0IHBheWxvYWQgPSB7XHJcblx0XHRcdFx0aWQsXHJcblx0XHRcdFx0YXJncyxcclxuXHRcdFx0XHRjYWxsYmFja0lELFxyXG5cdFx0XHR9O1xyXG5cclxuICAgICAgICAgICAgLy8gTWFrZSB0aGUgY2FsbFxyXG4gICAgICAgICAgICB3aW5kb3cuV2FpbHNJbnZva2UoJ2MnICsgSlNPTi5zdHJpbmdpZnkocGF5bG9hZCkpO1xyXG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcclxuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lXHJcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZSk7XHJcbiAgICAgICAgfVxyXG4gICAgfSk7XHJcbn07XHJcblxyXG5cclxuLyoqXHJcbiAqIENhbGxlZCBieSB0aGUgYmFja2VuZCB0byByZXR1cm4gZGF0YSB0byBhIHByZXZpb3VzbHkgY2FsbGVkXHJcbiAqIGJpbmRpbmcgaW52b2NhdGlvblxyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpbmNvbWluZ01lc3NhZ2VcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBDYWxsYmFjayhpbmNvbWluZ01lc3NhZ2UpIHtcclxuXHQvLyBQYXJzZSB0aGUgbWVzc2FnZVxyXG5cdGxldCBtZXNzYWdlO1xyXG5cdHRyeSB7XHJcblx0XHRtZXNzYWdlID0gSlNPTi5wYXJzZShpbmNvbWluZ01lc3NhZ2UpO1xyXG5cdH0gY2F0Y2ggKGUpIHtcclxuXHRcdGNvbnN0IGVycm9yID0gYEludmFsaWQgSlNPTiBwYXNzZWQgdG8gY2FsbGJhY2s6ICR7ZS5tZXNzYWdlfS4gTWVzc2FnZTogJHtpbmNvbWluZ01lc3NhZ2V9YDtcclxuXHRcdHJ1bnRpbWUuTG9nRGVidWcoZXJyb3IpO1xyXG5cdFx0dGhyb3cgbmV3IEVycm9yKGVycm9yKTtcclxuXHR9XHJcblx0bGV0IGNhbGxiYWNrSUQgPSBtZXNzYWdlLmNhbGxiYWNraWQ7XHJcblx0bGV0IGNhbGxiYWNrRGF0YSA9IGNhbGxiYWNrc1tjYWxsYmFja0lEXTtcclxuXHRpZiAoIWNhbGxiYWNrRGF0YSkge1xyXG5cdFx0Y29uc3QgZXJyb3IgPSBgQ2FsbGJhY2sgJyR7Y2FsbGJhY2tJRH0nIG5vdCByZWdpc3RlcmVkISEhYDtcclxuXHRcdGNvbnNvbGUuZXJyb3IoZXJyb3IpOyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lXHJcblx0XHR0aHJvdyBuZXcgRXJyb3IoZXJyb3IpO1xyXG5cdH1cclxuXHRjbGVhclRpbWVvdXQoY2FsbGJhY2tEYXRhLnRpbWVvdXRIYW5kbGUpO1xyXG5cclxuXHRkZWxldGUgY2FsbGJhY2tzW2NhbGxiYWNrSURdO1xyXG5cclxuXHRpZiAobWVzc2FnZS5lcnJvcikge1xyXG5cdFx0Y2FsbGJhY2tEYXRhLnJlamVjdChtZXNzYWdlLmVycm9yKTtcclxuXHR9IGVsc2Uge1xyXG5cdFx0Y2FsbGJhY2tEYXRhLnJlc29sdmUobWVzc2FnZS5yZXN1bHQpO1xyXG5cdH1cclxufVxyXG4iLCAiLypcclxuIF8gICAgICAgX18gICAgICBfIF9fICAgIFxyXG58IHwgICAgIC8gL19fXyBfKF8pIC9fX19fXHJcbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cclxufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApIFxyXG58X18vfF9fL1xcX18sXy9fL18vX19fXy8gIFxyXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXHJcbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcclxuKi9cclxuLyoganNoaW50IGVzdmVyc2lvbjogNiAqL1xyXG5cclxuaW1wb3J0IHtDYWxsfSBmcm9tICcuL2NhbGxzJztcclxuXHJcbi8vIFRoaXMgaXMgd2hlcmUgd2UgYmluZCBnbyBtZXRob2Qgd3JhcHBlcnNcclxud2luZG93LmdvID0ge307XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gU2V0QmluZGluZ3MoYmluZGluZ3NNYXApIHtcclxuXHR0cnkge1xyXG5cdFx0YmluZGluZ3NNYXAgPSBKU09OLnBhcnNlKGJpbmRpbmdzTWFwKTtcclxuXHR9IGNhdGNoIChlKSB7XHJcblx0XHRjb25zb2xlLmVycm9yKGUpO1xyXG5cdH1cclxuXHJcblx0Ly8gSW5pdGlhbGlzZSB0aGUgYmluZGluZ3MgbWFwXHJcblx0d2luZG93LmdvID0gd2luZG93LmdvIHx8IHt9O1xyXG5cclxuXHQvLyBJdGVyYXRlIHBhY2thZ2UgbmFtZXNcclxuXHRPYmplY3Qua2V5cyhiaW5kaW5nc01hcCkuZm9yRWFjaCgocGFja2FnZU5hbWUpID0+IHtcclxuXHJcblx0XHQvLyBDcmVhdGUgaW5uZXIgbWFwIGlmIGl0IGRvZXNuJ3QgZXhpc3RcclxuXHRcdHdpbmRvdy5nb1twYWNrYWdlTmFtZV0gPSB3aW5kb3cuZ29bcGFja2FnZU5hbWVdIHx8IHt9O1xyXG5cclxuXHRcdC8vIEl0ZXJhdGUgc3RydWN0IG5hbWVzXHJcblx0XHRPYmplY3Qua2V5cyhiaW5kaW5nc01hcFtwYWNrYWdlTmFtZV0pLmZvckVhY2goKHN0cnVjdE5hbWUpID0+IHtcclxuXHJcblx0XHRcdC8vIENyZWF0ZSBpbm5lciBtYXAgaWYgaXQgZG9lc24ndCBleGlzdFxyXG5cdFx0XHR3aW5kb3cuZ29bcGFja2FnZU5hbWVdW3N0cnVjdE5hbWVdID0gd2luZG93LmdvW3BhY2thZ2VOYW1lXVtzdHJ1Y3ROYW1lXSB8fCB7fTtcclxuXHJcblx0XHRcdE9iamVjdC5rZXlzKGJpbmRpbmdzTWFwW3BhY2thZ2VOYW1lXVtzdHJ1Y3ROYW1lXSkuZm9yRWFjaCgobWV0aG9kTmFtZSkgPT4ge1xyXG5cclxuXHRcdFx0XHR3aW5kb3cuZ29bcGFja2FnZU5hbWVdW3N0cnVjdE5hbWVdW21ldGhvZE5hbWVdID0gZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdFx0XHRcdC8vIE5vIHRpbWVvdXQgYnkgZGVmYXVsdFxyXG5cdFx0XHRcdFx0bGV0IHRpbWVvdXQgPSAwO1xyXG5cclxuXHRcdFx0XHRcdC8vIEFjdHVhbCBmdW5jdGlvblxyXG5cdFx0XHRcdFx0ZnVuY3Rpb24gZHluYW1pYygpIHtcclxuXHRcdFx0XHRcdFx0Y29uc3QgYXJncyA9IFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzKTtcclxuXHRcdFx0XHRcdFx0cmV0dXJuIENhbGwoW3BhY2thZ2VOYW1lLCBzdHJ1Y3ROYW1lLCBtZXRob2ROYW1lXS5qb2luKCcuJyksIGFyZ3MsIHRpbWVvdXQpO1xyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdC8vIEFsbG93IHNldHRpbmcgdGltZW91dCB0byBmdW5jdGlvblxyXG5cdFx0XHRcdFx0ZHluYW1pYy5zZXRUaW1lb3V0ID0gZnVuY3Rpb24gKG5ld1RpbWVvdXQpIHtcclxuXHRcdFx0XHRcdFx0dGltZW91dCA9IG5ld1RpbWVvdXQ7XHJcblx0XHRcdFx0XHR9O1xyXG5cclxuXHRcdFx0XHRcdC8vIEFsbG93IGdldHRpbmcgdGltZW91dCB0byBmdW5jdGlvblxyXG5cdFx0XHRcdFx0ZHluYW1pYy5nZXRUaW1lb3V0ID0gZnVuY3Rpb24gKCkge1xyXG5cdFx0XHRcdFx0XHRyZXR1cm4gdGltZW91dDtcclxuXHRcdFx0XHRcdH07XHJcblxyXG5cdFx0XHRcdFx0cmV0dXJuIGR5bmFtaWM7XHJcblx0XHRcdFx0fSgpO1xyXG5cdFx0XHR9KTtcclxuXHRcdH0pO1xyXG5cdH0pO1xyXG59XHJcbiIsICIvKlxyXG4gX1x0ICAgX19cdCAgXyBfX1xyXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xyXG58IHwgL3wgLyAvIF9fIGAvIC8gLyBfX18vXHJcbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxyXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cclxuVGhlIGVsZWN0cm9uIGFsdGVybmF0aXZlIGZvciBHb1xyXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XHJcbiovXHJcblxyXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA5ICovXHJcblxyXG5cclxuaW1wb3J0IHtDYWxsfSBmcm9tIFwiLi9jYWxsc1wiO1xyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd1JlbG9hZCgpIHtcclxuICAgIHdpbmRvdy5sb2NhdGlvbi5yZWxvYWQoKTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd1JlbG9hZEFwcCgpIHtcclxuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV1InKTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd1NldFN5c3RlbURlZmF1bHRUaGVtZSgpIHtcclxuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV0FTRFQnKTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd1NldExpZ2h0VGhlbWUoKSB7XHJcbiAgICB3aW5kb3cuV2FpbHNJbnZva2UoJ1dBTFQnKTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd1NldERhcmtUaGVtZSgpIHtcclxuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV0FEVCcpO1xyXG59XHJcblxyXG4vKipcclxuICogUGxhY2UgdGhlIHdpbmRvdyBpbiB0aGUgY2VudGVyIG9mIHRoZSBzY3JlZW5cclxuICpcclxuICogQGV4cG9ydFxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd0NlbnRlcigpIHtcclxuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV2MnKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIHdpbmRvdyB0aXRsZVxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdGl0bGVcclxuICogQGV4cG9ydFxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd1NldFRpdGxlKHRpdGxlKSB7XHJcbiAgICB3aW5kb3cuV2FpbHNJbnZva2UoJ1dUJyArIHRpdGxlKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIE1ha2VzIHRoZSB3aW5kb3cgZ28gZnVsbHNjcmVlblxyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gV2luZG93RnVsbHNjcmVlbigpIHtcclxuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV0YnKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJldmVydHMgdGhlIHdpbmRvdyBmcm9tIGZ1bGxzY3JlZW5cclxuICpcclxuICogQGV4cG9ydFxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd1VuZnVsbHNjcmVlbigpIHtcclxuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV2YnKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHVybnMgdGhlIHN0YXRlIG9mIHRoZSB3aW5kb3csIGkuZS4gd2hldGhlciB0aGUgd2luZG93IGlzIGluIGZ1bGwgc2NyZWVuIG1vZGUgb3Igbm90LlxyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEByZXR1cm4ge1Byb21pc2U8Ym9vbGVhbj59IFRoZSBzdGF0ZSBvZiB0aGUgd2luZG93XHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gV2luZG93SXNGdWxsc2NyZWVuKCkge1xyXG4gICAgcmV0dXJuIENhbGwoXCI6d2FpbHM6V2luZG93SXNGdWxsc2NyZWVuXCIpO1xyXG59XHJcblxyXG4vKipcclxuICogU2V0IHRoZSBTaXplIG9mIHRoZSB3aW5kb3dcclxuICpcclxuICogQGV4cG9ydFxyXG4gKiBAcGFyYW0ge251bWJlcn0gd2lkdGhcclxuICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodFxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd1NldFNpemUod2lkdGgsIGhlaWdodCkge1xyXG4gICAgd2luZG93LldhaWxzSW52b2tlKCdXczonICsgd2lkdGggKyAnOicgKyBoZWlnaHQpO1xyXG59XHJcblxyXG4vKipcclxuICogR2V0IHRoZSBTaXplIG9mIHRoZSB3aW5kb3dcclxuICpcclxuICogQGV4cG9ydFxyXG4gKiBAcmV0dXJuIHtQcm9taXNlPHt3OiBudW1iZXIsIGg6IG51bWJlcn0+fSBUaGUgc2l6ZSBvZiB0aGUgd2luZG93XHJcblxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd0dldFNpemUoKSB7XHJcbiAgICByZXR1cm4gQ2FsbChcIjp3YWlsczpXaW5kb3dHZXRTaXplXCIpO1xyXG59XHJcblxyXG4vKipcclxuICogU2V0IHRoZSBtYXhpbXVtIHNpemUgb2YgdGhlIHdpbmRvd1xyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aFxyXG4gKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0XHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gV2luZG93U2V0TWF4U2l6ZSh3aWR0aCwgaGVpZ2h0KSB7XHJcbiAgICB3aW5kb3cuV2FpbHNJbnZva2UoJ1daOicgKyB3aWR0aCArICc6JyArIGhlaWdodCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXQgdGhlIG1pbmltdW0gc2l6ZSBvZiB0aGUgd2luZG93XHJcbiAqXHJcbiAqIEBleHBvcnRcclxuICogQHBhcmFtIHtudW1iZXJ9IHdpZHRoXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHRcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBXaW5kb3dTZXRNaW5TaXplKHdpZHRoLCBoZWlnaHQpIHtcclxuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV3o6JyArIHdpZHRoICsgJzonICsgaGVpZ2h0KTtcclxufVxyXG5cclxuXHJcblxyXG4vKipcclxuICogU2V0IHRoZSB3aW5kb3cgQWx3YXlzT25Ub3Agb3Igbm90IG9uIHRvcFxyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gV2luZG93U2V0QWx3YXlzT25Ub3AoYikge1xyXG5cclxuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV0FUUDonICsgKGIgPyAnMScgOiAnMCcpKTtcclxufVxyXG5cclxuXHJcblxyXG5cclxuLyoqXHJcbiAqIFNldCB0aGUgUG9zaXRpb24gb2YgdGhlIHdpbmRvd1xyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB4XHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB5XHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gV2luZG93U2V0UG9zaXRpb24oeCwgeSkge1xyXG4gICAgd2luZG93LldhaWxzSW52b2tlKCdXcDonICsgeCArICc6JyArIHkpO1xyXG59XHJcblxyXG4vKipcclxuICogR2V0IHRoZSBQb3NpdGlvbiBvZiB0aGUgd2luZG93XHJcbiAqXHJcbiAqIEBleHBvcnRcclxuICogQHJldHVybiB7UHJvbWlzZTx7eDogbnVtYmVyLCB5OiBudW1iZXJ9Pn0gVGhlIHBvc2l0aW9uIG9mIHRoZSB3aW5kb3dcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBXaW5kb3dHZXRQb3NpdGlvbigpIHtcclxuICAgIHJldHVybiBDYWxsKFwiOndhaWxzOldpbmRvd0dldFBvc1wiKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEhpZGUgdGhlIFdpbmRvd1xyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gV2luZG93SGlkZSgpIHtcclxuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV0gnKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNob3cgdGhlIFdpbmRvd1xyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gV2luZG93U2hvdygpIHtcclxuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV1MnKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIE1heGltaXNlIHRoZSBXaW5kb3dcclxuICpcclxuICogQGV4cG9ydFxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd01heGltaXNlKCkge1xyXG4gICAgd2luZG93LldhaWxzSW52b2tlKCdXTScpO1xyXG59XHJcblxyXG4vKipcclxuICogVG9nZ2xlIHRoZSBNYXhpbWlzZSBvZiB0aGUgV2luZG93XHJcbiAqXHJcbiAqIEBleHBvcnRcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBXaW5kb3dUb2dnbGVNYXhpbWlzZSgpIHtcclxuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV3QnKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFVubWF4aW1pc2UgdGhlIFdpbmRvd1xyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gV2luZG93VW5tYXhpbWlzZSgpIHtcclxuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV1UnKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHVybnMgdGhlIHN0YXRlIG9mIHRoZSB3aW5kb3csIGkuZS4gd2hldGhlciB0aGUgd2luZG93IGlzIG1heGltaXNlZCBvciBub3QuXHJcbiAqXHJcbiAqIEBleHBvcnRcclxuICogQHJldHVybiB7UHJvbWlzZTxib29sZWFuPn0gVGhlIHN0YXRlIG9mIHRoZSB3aW5kb3dcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBXaW5kb3dJc01heGltaXNlZCgpIHtcclxuICAgIHJldHVybiBDYWxsKFwiOndhaWxzOldpbmRvd0lzTWF4aW1pc2VkXCIpO1xyXG59XHJcblxyXG4vKipcclxuICogTWluaW1pc2UgdGhlIFdpbmRvd1xyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gV2luZG93TWluaW1pc2UoKSB7XHJcbiAgICB3aW5kb3cuV2FpbHNJbnZva2UoJ1dtJyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBVbm1pbmltaXNlIHRoZSBXaW5kb3dcclxuICpcclxuICogQGV4cG9ydFxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd1VubWluaW1pc2UoKSB7XHJcbiAgICB3aW5kb3cuV2FpbHNJbnZva2UoJ1d1Jyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXR1cm5zIHRoZSBzdGF0ZSBvZiB0aGUgd2luZG93LCBpLmUuIHdoZXRoZXIgdGhlIHdpbmRvdyBpcyBtaW5pbWlzZWQgb3Igbm90LlxyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEByZXR1cm4ge1Byb21pc2U8Ym9vbGVhbj59IFRoZSBzdGF0ZSBvZiB0aGUgd2luZG93XHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gV2luZG93SXNNaW5pbWlzZWQoKSB7XHJcbiAgICByZXR1cm4gQ2FsbChcIjp3YWlsczpXaW5kb3dJc01pbmltaXNlZFwiKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHVybnMgdGhlIHN0YXRlIG9mIHRoZSB3aW5kb3csIGkuZS4gd2hldGhlciB0aGUgd2luZG93IGlzIG5vcm1hbCBvciBub3QuXHJcbiAqXHJcbiAqIEBleHBvcnRcclxuICogQHJldHVybiB7UHJvbWlzZTxib29sZWFuPn0gVGhlIHN0YXRlIG9mIHRoZSB3aW5kb3dcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBXaW5kb3dJc05vcm1hbCgpIHtcclxuICAgIHJldHVybiBDYWxsKFwiOndhaWxzOldpbmRvd0lzTm9ybWFsXCIpO1xyXG59XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgYmFja2dyb3VuZCBjb2xvdXIgb2YgdGhlIHdpbmRvd1xyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBSIFJlZFxyXG4gKiBAcGFyYW0ge251bWJlcn0gRyBHcmVlblxyXG4gKiBAcGFyYW0ge251bWJlcn0gQiBCbHVlXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBBIEFscGhhXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gV2luZG93U2V0QmFja2dyb3VuZENvbG91cihSLCBHLCBCLCBBKSB7XHJcbiAgICBsZXQgcmdiYSA9IEpTT04uc3RyaW5naWZ5KHtyOiBSIHx8IDAsIGc6IEcgfHwgMCwgYjogQiB8fCAwLCBhOiBBIHx8IDI1NX0pO1xyXG4gICAgd2luZG93LldhaWxzSW52b2tlKCdXcjonICsgcmdiYSk7XHJcbn1cclxuXHJcbiIsICIvKlxyXG4gX1x0ICAgX19cdCAgXyBfX1xyXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xyXG58IHwgL3wgLyAvIF9fIGAvIC8gLyBfX18vXHJcbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxyXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cclxuVGhlIGVsZWN0cm9uIGFsdGVybmF0aXZlIGZvciBHb1xyXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XHJcbiovXHJcblxyXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA5ICovXHJcblxyXG5cclxuaW1wb3J0IHtDYWxsfSBmcm9tIFwiLi9jYWxsc1wiO1xyXG5cclxuXHJcbi8qKlxyXG4gKiBHZXRzIHRoZSBhbGwgc2NyZWVucy4gQ2FsbCB0aGlzIGFuZXcgZWFjaCB0aW1lIHlvdSB3YW50IHRvIHJlZnJlc2ggZGF0YSBmcm9tIHRoZSB1bmRlcmx5aW5nIHdpbmRvd2luZyBzeXN0ZW0uXHJcbiAqIEBleHBvcnRcclxuICogQHR5cGVkZWYge2ltcG9ydCgnLi4vd3JhcHBlci9ydW50aW1lJykuU2NyZWVufSBTY3JlZW5cclxuICogQHJldHVybiB7UHJvbWlzZTx7U2NyZWVuW119Pn0gVGhlIHNjcmVlbnNcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBTY3JlZW5HZXRBbGwoKSB7XHJcbiAgICByZXR1cm4gQ2FsbChcIjp3YWlsczpTY3JlZW5HZXRBbGxcIik7XHJcbn1cclxuIiwgIi8qKlxyXG4gKiBAZGVzY3JpcHRpb246IFVzZSB0aGUgc3lzdGVtIGRlZmF1bHQgYnJvd3NlciB0byBvcGVuIHRoZSB1cmxcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCBcclxuICogQHJldHVybiB7dm9pZH1cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBCcm93c2VyT3BlblVSTCh1cmwpIHtcclxuICB3aW5kb3cuV2FpbHNJbnZva2UoJ0JPOicgKyB1cmwpO1xyXG59IiwgIi8qXHJcbiBfXHQgICBfX1x0ICBfIF9fXHJcbnwgfFx0IC8gL19fXyBfKF8pIC9fX19fXHJcbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cclxufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXHJcbnxfXy98X18vXFxfXyxfL18vXy9fX19fL1xyXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXHJcbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcclxuKi9cclxuXHJcbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cclxuXHJcbmltcG9ydCB7Q2FsbH0gZnJvbSBcIi4vY2FsbHNcIjtcclxuXHJcbi8qKlxyXG4gKiBTZXQgdGhlIFNpemUgb2YgdGhlIHdpbmRvd1xyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0XHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gQ2xpcGJvYXJkU2V0VGV4dCh0ZXh0KSB7XHJcbiAgICByZXR1cm4gQ2FsbChcIjp3YWlsczpDbGlwYm9hcmRTZXRUZXh0XCIsIFt0ZXh0XSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBHZXQgdGhlIHRleHQgY29udGVudCBvZiB0aGUgY2xpcGJvYXJkXHJcbiAqXHJcbiAqIEBleHBvcnRcclxuICogQHJldHVybiB7UHJvbWlzZTx7c3RyaW5nfT59IFRleHQgY29udGVudCBvZiB0aGUgY2xpcGJvYXJkXHJcblxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIENsaXBib2FyZEdldFRleHQoKSB7XHJcbiAgICByZXR1cm4gQ2FsbChcIjp3YWlsczpDbGlwYm9hcmRHZXRUZXh0XCIpO1xyXG59IiwgIi8qXHJcbiBfXHQgICBfX1x0ICBfIF9fXHJcbnwgfFx0IC8gL19fXyBfKF8pIC9fX19fXHJcbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cclxufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXHJcbnxfXy98X18vXFxfXyxfL18vXy9fX19fL1xyXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXHJcbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcclxuKi9cclxuXHJcbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cclxuXHJcbmltcG9ydCB7RXZlbnRzT24sIEV2ZW50c09mZn0gZnJvbSBcIi4vZXZlbnRzXCI7XHJcblxyXG5jb25zdCBmbGFncyA9IHtcclxuICAgIHJlZ2lzdGVyZWQ6IGZhbHNlLFxyXG4gICAgZGVmYXVsdFVzZURyb3BUYXJnZXQ6IHRydWUsXHJcbiAgICB1c2VEcm9wVGFyZ2V0OiB0cnVlLFxyXG4gICAgbmV4dERlYWN0aXZhdGU6IG51bGwsXHJcbiAgICBuZXh0RGVhY3RpdmF0ZVRpbWVvdXQ6IG51bGwsXHJcbn07XHJcblxyXG5jb25zdCBEUk9QX1RBUkdFVF9BQ1RJVkUgPSBcIndhaWxzLWRyb3AtdGFyZ2V0LWFjdGl2ZVwiO1xyXG5cclxuLyoqXHJcbiAqIGNoZWNrU3R5bGVEcm9wVGFyZ2V0IGNoZWNrcyBpZiB0aGUgc3R5bGUgaGFzIHRoZSBkcm9wIHRhcmdldCBhdHRyaWJ1dGVcclxuICogXHJcbiAqIEBwYXJhbSB7Q1NTU3R5bGVEZWNsYXJhdGlvbn0gc3R5bGUgXHJcbiAqIEByZXR1cm5zIFxyXG4gKi9cclxuZnVuY3Rpb24gY2hlY2tTdHlsZURyb3BUYXJnZXQoc3R5bGUpIHtcclxuICAgIGNvbnN0IGNzc0Ryb3BWYWx1ZSA9IHN0eWxlLmdldFByb3BlcnR5VmFsdWUod2luZG93LndhaWxzLmZsYWdzLmNzc0Ryb3BQcm9wZXJ0eSkudHJpbSgpO1xyXG4gICAgaWYgKGNzc0Ryb3BWYWx1ZSkge1xyXG4gICAgICAgIGlmIChjc3NEcm9wVmFsdWUgPT09IHdpbmRvdy53YWlscy5mbGFncy5jc3NEcm9wVmFsdWUpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIC8vIGlmIHRoZSBlbGVtZW50IGhhcyB0aGUgZHJvcCB0YXJnZXQgYXR0cmlidXRlLCBidXQgXHJcbiAgICAgICAgLy8gdGhlIHZhbHVlIGlzIG5vdCBjb3JyZWN0LCB0ZXJtaW5hdGUgZmluZGluZyBwcm9jZXNzLlxyXG4gICAgICAgIC8vIFRoaXMgY2FuIGJlIHVzZWZ1bCB0byBibG9jayBzb21lIGNoaWxkIGVsZW1lbnRzIGZyb20gYmVpbmcgZHJvcCB0YXJnZXRzLlxyXG4gICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuICAgIHJldHVybiBmYWxzZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIG9uRHJhZ092ZXIgaXMgY2FsbGVkIHdoZW4gdGhlIGRyYWdvdmVyIGV2ZW50IGlzIGVtaXR0ZWQuXHJcbiAqIEBwYXJhbSB7RHJhZ0V2ZW50fSBlXHJcbiAqIEByZXR1cm5zXHJcbiAqL1xyXG5mdW5jdGlvbiBvbkRyYWdPdmVyKGUpIHtcclxuICAgIC8vIENoZWNrIGlmIHRoaXMgaXMgYW4gZXh0ZXJuYWwgZmlsZSBkcm9wIG9yIGludGVybmFsIEhUTUwgZHJhZ1xyXG4gICAgLy8gRXh0ZXJuYWwgZmlsZSBkcm9wcyB3aWxsIGhhdmUgXCJGaWxlc1wiIGluIHRoZSB0eXBlcyBhcnJheVxyXG4gICAgLy8gSW50ZXJuYWwgSFRNTCBkcmFncyB0eXBpY2FsbHkgaGF2ZSBcInRleHQvcGxhaW5cIiwgXCJ0ZXh0L2h0bWxcIiBvciBjdXN0b20gdHlwZXNcclxuICAgIGNvbnN0IGlzRmlsZURyb3AgPSBlLmRhdGFUcmFuc2Zlci50eXBlcy5pbmNsdWRlcyhcIkZpbGVzXCIpO1xyXG5cclxuICAgIC8vIE9ubHkgaGFuZGxlIGV4dGVybmFsIGZpbGUgZHJvcHMsIGxldCBpbnRlcm5hbCBIVE1MNSBkcmFnLWFuZC1kcm9wIHdvcmsgbm9ybWFsbHlcclxuICAgIGlmICghaXNGaWxlRHJvcCkge1xyXG4gICAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICAvLyBBTFdBWVMgcHJldmVudCBkZWZhdWx0IGZvciBmaWxlIGRyb3BzIHRvIHN0b3AgYnJvd3NlciBuYXZpZ2F0aW9uXHJcbiAgICBlLnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICBlLmRhdGFUcmFuc2Zlci5kcm9wRWZmZWN0ID0gJ2NvcHknO1xyXG5cclxuICAgIGlmICghd2luZG93LndhaWxzLmZsYWdzLmVuYWJsZVdhaWxzRHJhZ0FuZERyb3ApIHtcclxuICAgICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFmbGFncy51c2VEcm9wVGFyZ2V0KSB7XHJcbiAgICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IGVsZW1lbnQgPSBlLnRhcmdldDtcclxuXHJcbiAgICAvLyBUcmlnZ2VyIGRlYm91bmNlIGZ1bmN0aW9uIHRvIGRlYWN0aXZhdGUgZHJvcCB0YXJnZXRzXHJcbiAgICBpZihmbGFncy5uZXh0RGVhY3RpdmF0ZSkgZmxhZ3MubmV4dERlYWN0aXZhdGUoKTtcclxuXHJcbiAgICAvLyBpZiB0aGUgZWxlbWVudCBpcyBudWxsIG9yIGVsZW1lbnQgaXMgbm90IGNoaWxkIG9mIGRyb3AgdGFyZ2V0IGVsZW1lbnRcclxuICAgIGlmICghZWxlbWVudCB8fCAhY2hlY2tTdHlsZURyb3BUYXJnZXQoZ2V0Q29tcHV0ZWRTdHlsZShlbGVtZW50KSkpIHtcclxuICAgICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgbGV0IGN1cnJlbnRFbGVtZW50ID0gZWxlbWVudDtcclxuICAgIHdoaWxlIChjdXJyZW50RWxlbWVudCkge1xyXG4gICAgICAgIC8vIGNoZWNrIGlmIGN1cnJlbnRFbGVtZW50IGlzIGRyb3AgdGFyZ2V0IGVsZW1lbnRcclxuICAgICAgICBpZiAoY2hlY2tTdHlsZURyb3BUYXJnZXQoZ2V0Q29tcHV0ZWRTdHlsZShjdXJyZW50RWxlbWVudCkpKSB7XHJcbiAgICAgICAgICAgIGN1cnJlbnRFbGVtZW50LmNsYXNzTGlzdC5hZGQoRFJPUF9UQVJHRVRfQUNUSVZFKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgY3VycmVudEVsZW1lbnQgPSBjdXJyZW50RWxlbWVudC5wYXJlbnRFbGVtZW50O1xyXG4gICAgfVxyXG59XHJcblxyXG4vKipcclxuICogb25EcmFnTGVhdmUgaXMgY2FsbGVkIHdoZW4gdGhlIGRyYWdsZWF2ZSBldmVudCBpcyBlbWl0dGVkLlxyXG4gKiBAcGFyYW0ge0RyYWdFdmVudH0gZVxyXG4gKiBAcmV0dXJuc1xyXG4gKi9cclxuZnVuY3Rpb24gb25EcmFnTGVhdmUoZSkge1xyXG4gICAgLy8gQ2hlY2sgaWYgdGhpcyBpcyBhbiBleHRlcm5hbCBmaWxlIGRyb3Agb3IgaW50ZXJuYWwgSFRNTCBkcmFnXHJcbiAgICBjb25zdCBpc0ZpbGVEcm9wID0gZS5kYXRhVHJhbnNmZXIudHlwZXMuaW5jbHVkZXMoXCJGaWxlc1wiKTtcclxuXHJcbiAgICAvLyBPbmx5IGhhbmRsZSBleHRlcm5hbCBmaWxlIGRyb3BzLCBsZXQgaW50ZXJuYWwgSFRNTDUgZHJhZy1hbmQtZHJvcCB3b3JrIG5vcm1hbGx5XHJcbiAgICBpZiAoIWlzRmlsZURyb3ApIHtcclxuICAgICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQUxXQVlTIHByZXZlbnQgZGVmYXVsdCBmb3IgZmlsZSBkcm9wcyB0byBzdG9wIGJyb3dzZXIgbmF2aWdhdGlvblxyXG4gICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xyXG5cclxuICAgIGlmICghd2luZG93LndhaWxzLmZsYWdzLmVuYWJsZVdhaWxzRHJhZ0FuZERyb3ApIHtcclxuICAgICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFmbGFncy51c2VEcm9wVGFyZ2V0KSB7XHJcbiAgICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEZpbmQgdGhlIGNsb3NlIGRyb3AgdGFyZ2V0IGVsZW1lbnRcclxuICAgIGlmICghZS50YXJnZXQgfHwgIWNoZWNrU3R5bGVEcm9wVGFyZ2V0KGdldENvbXB1dGVkU3R5bGUoZS50YXJnZXQpKSkge1xyXG4gICAgICAgIHJldHVybiBudWxsO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFRyaWdnZXIgZGVib3VuY2UgZnVuY3Rpb24gdG8gZGVhY3RpdmF0ZSBkcm9wIHRhcmdldHNcclxuICAgIGlmKGZsYWdzLm5leHREZWFjdGl2YXRlKSBmbGFncy5uZXh0RGVhY3RpdmF0ZSgpO1xyXG4gICAgXHJcbiAgICAvLyBVc2UgZGVib3VuY2UgdGVjaG5pcXVlIHRvIHRhY2xlIGRyYWdsZWF2ZSBldmVudHMgb24gb3ZlcmxhcHBpbmcgZWxlbWVudHMgYW5kIGRyb3AgdGFyZ2V0IGVsZW1lbnRzXHJcbiAgICBmbGFncy5uZXh0RGVhY3RpdmF0ZSA9ICgpID0+IHtcclxuICAgICAgICAvLyBEZWFjdGl2YXRlIGFsbCBkcm9wIHRhcmdldHMsIG5ldyBkcm9wIHRhcmdldCB3aWxsIGJlIGFjdGl2YXRlZCBvbiBuZXh0IGRyYWdvdmVyIGV2ZW50XHJcbiAgICAgICAgQXJyYXkuZnJvbShkb2N1bWVudC5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lKERST1BfVEFSR0VUX0FDVElWRSkpLmZvckVhY2goZWwgPT4gZWwuY2xhc3NMaXN0LnJlbW92ZShEUk9QX1RBUkdFVF9BQ1RJVkUpKTtcclxuICAgICAgICAvLyBSZXNldCBuZXh0RGVhY3RpdmF0ZVxyXG4gICAgICAgIGZsYWdzLm5leHREZWFjdGl2YXRlID0gbnVsbDtcclxuICAgICAgICAvLyBDbGVhciB0aW1lb3V0XHJcbiAgICAgICAgaWYgKGZsYWdzLm5leHREZWFjdGl2YXRlVGltZW91dCkge1xyXG4gICAgICAgICAgICBjbGVhclRpbWVvdXQoZmxhZ3MubmV4dERlYWN0aXZhdGVUaW1lb3V0KTtcclxuICAgICAgICAgICAgZmxhZ3MubmV4dERlYWN0aXZhdGVUaW1lb3V0ID0gbnVsbDtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2V0IHRpbWVvdXQgdG8gZGVhY3RpdmF0ZSBkcm9wIHRhcmdldHMgaWYgbm90IHRyaWdnZXJlZCBieSBuZXh0IGRyYWcgZXZlbnRcclxuICAgIGZsYWdzLm5leHREZWFjdGl2YXRlVGltZW91dCA9IHNldFRpbWVvdXQoKCkgPT4ge1xyXG4gICAgICAgIGlmKGZsYWdzLm5leHREZWFjdGl2YXRlKSBmbGFncy5uZXh0RGVhY3RpdmF0ZSgpO1xyXG4gICAgfSwgNTApO1xyXG59XHJcblxyXG4vKipcclxuICogb25Ecm9wIGlzIGNhbGxlZCB3aGVuIHRoZSBkcm9wIGV2ZW50IGlzIGVtaXR0ZWQuXHJcbiAqIEBwYXJhbSB7RHJhZ0V2ZW50fSBlXHJcbiAqIEByZXR1cm5zXHJcbiAqL1xyXG5mdW5jdGlvbiBvbkRyb3AoZSkge1xyXG4gICAgLy8gQ2hlY2sgaWYgdGhpcyBpcyBhbiBleHRlcm5hbCBmaWxlIGRyb3Agb3IgaW50ZXJuYWwgSFRNTCBkcmFnXHJcbiAgICBjb25zdCBpc0ZpbGVEcm9wID0gZS5kYXRhVHJhbnNmZXIudHlwZXMuaW5jbHVkZXMoXCJGaWxlc1wiKTtcclxuXHJcbiAgICAvLyBPbmx5IGhhbmRsZSBleHRlcm5hbCBmaWxlIGRyb3BzLCBsZXQgaW50ZXJuYWwgSFRNTDUgZHJhZy1hbmQtZHJvcCB3b3JrIG5vcm1hbGx5XHJcbiAgICBpZiAoIWlzRmlsZURyb3ApIHtcclxuICAgICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQUxXQVlTIHByZXZlbnQgZGVmYXVsdCBmb3IgZmlsZSBkcm9wcyB0byBzdG9wIGJyb3dzZXIgbmF2aWdhdGlvblxyXG4gICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xyXG5cclxuICAgIGlmICghd2luZG93LndhaWxzLmZsYWdzLmVuYWJsZVdhaWxzRHJhZ0FuZERyb3ApIHtcclxuICAgICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKENhblJlc29sdmVGaWxlUGF0aHMoKSkge1xyXG4gICAgICAgIC8vIHByb2Nlc3MgZmlsZXNcclxuICAgICAgICBsZXQgZmlsZXMgPSBbXTtcclxuICAgICAgICBpZiAoZS5kYXRhVHJhbnNmZXIuaXRlbXMpIHtcclxuICAgICAgICAgICAgZmlsZXMgPSBbLi4uZS5kYXRhVHJhbnNmZXIuaXRlbXNdLm1hcCgoaXRlbSwgaSkgPT4ge1xyXG4gICAgICAgICAgICAgICAgaWYgKGl0ZW0ua2luZCA9PT0gJ2ZpbGUnKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGl0ZW0uZ2V0QXNGaWxlKCk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH0pO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIGZpbGVzID0gWy4uLmUuZGF0YVRyYW5zZmVyLmZpbGVzXTtcclxuICAgICAgICB9XHJcbiAgICAgICAgd2luZG93LnJ1bnRpbWUuUmVzb2x2ZUZpbGVQYXRocyhlLngsIGUueSwgZmlsZXMpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICghZmxhZ3MudXNlRHJvcFRhcmdldCkge1xyXG4gICAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICAvLyBUcmlnZ2VyIGRlYm91bmNlIGZ1bmN0aW9uIHRvIGRlYWN0aXZhdGUgZHJvcCB0YXJnZXRzXHJcbiAgICBpZihmbGFncy5uZXh0RGVhY3RpdmF0ZSkgZmxhZ3MubmV4dERlYWN0aXZhdGUoKTtcclxuXHJcbiAgICAvLyBEZWFjdGl2YXRlIGFsbCBkcm9wIHRhcmdldHNcclxuICAgIEFycmF5LmZyb20oZG9jdW1lbnQuZ2V0RWxlbWVudHNCeUNsYXNzTmFtZShEUk9QX1RBUkdFVF9BQ1RJVkUpKS5mb3JFYWNoKGVsID0+IGVsLmNsYXNzTGlzdC5yZW1vdmUoRFJPUF9UQVJHRVRfQUNUSVZFKSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBwb3N0TWVzc2FnZVdpdGhBZGRpdGlvbmFsT2JqZWN0cyBjaGVja3MgdGhlIGJyb3dzZXIncyBjYXBhYmlsaXR5IG9mIHNlbmRpbmcgcG9zdE1lc3NhZ2VXaXRoQWRkaXRpb25hbE9iamVjdHNcclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59XHJcbiAqIEBjb25zdHJ1Y3RvclxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIENhblJlc29sdmVGaWxlUGF0aHMoKSB7XHJcbiAgICByZXR1cm4gd2luZG93LmNocm9tZT8ud2Vidmlldz8ucG9zdE1lc3NhZ2VXaXRoQWRkaXRpb25hbE9iamVjdHMgIT0gbnVsbDtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJlc29sdmVGaWxlUGF0aHMgc2VuZHMgZHJvcCBldmVudHMgdG8gdGhlIEdPIHNpZGUgdG8gcmVzb2x2ZSBmaWxlIHBhdGhzIG9uIHdpbmRvd3MuXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB4XHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB5XHJcbiAqIEBwYXJhbSB7YW55W119IGZpbGVzXHJcbiAqIEBjb25zdHJ1Y3RvclxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIFJlc29sdmVGaWxlUGF0aHMoeCwgeSwgZmlsZXMpIHtcclxuICAgIC8vIE9ubHkgZm9yIHdpbmRvd3Mgd2VidmlldzIgPj0gMS4wLjE3NzQuMzBcclxuICAgIC8vIGh0dHBzOi8vbGVhcm4ubWljcm9zb2Z0LmNvbS9lbi11cy9taWNyb3NvZnQtZWRnZS93ZWJ2aWV3Mi9yZWZlcmVuY2Uvd2luMzIvaWNvcmV3ZWJ2aWV3MndlYm1lc3NhZ2VyZWNlaXZlZGV2ZW50YXJnczI/dmlldz13ZWJ2aWV3Mi0xLjAuMTgyMy4zMiNhcHBsaWVzLXRvXHJcbiAgICBpZiAod2luZG93LmNocm9tZT8ud2Vidmlldz8ucG9zdE1lc3NhZ2VXaXRoQWRkaXRpb25hbE9iamVjdHMpIHtcclxuICAgICAgICBjaHJvbWUud2Vidmlldy5wb3N0TWVzc2FnZVdpdGhBZGRpdGlvbmFsT2JqZWN0cyhgZmlsZTpkcm9wOiR7eH06JHt5fWAsIGZpbGVzKTtcclxuICAgIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIENhbGxiYWNrIGZvciBPbkZpbGVEcm9wIHJldHVybnMgYSBzbGljZSBvZiBmaWxlIHBhdGggc3RyaW5ncyB3aGVuIGEgZHJvcCBpcyBmaW5pc2hlZC5cclxuICpcclxuICogQGV4cG9ydFxyXG4gKiBAY2FsbGJhY2sgT25GaWxlRHJvcENhbGxiYWNrXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB4IC0geCBjb29yZGluYXRlIG9mIHRoZSBkcm9wXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB5IC0geSBjb29yZGluYXRlIG9mIHRoZSBkcm9wXHJcbiAqIEBwYXJhbSB7c3RyaW5nW119IHBhdGhzIC0gQSBsaXN0IG9mIGZpbGUgcGF0aHMuXHJcbiAqL1xyXG5cclxuLyoqXHJcbiAqIE9uRmlsZURyb3AgbGlzdGVucyB0byBkcmFnIGFuZCBkcm9wIGV2ZW50cyBhbmQgY2FsbHMgdGhlIGNhbGxiYWNrIHdpdGggdGhlIGNvb3JkaW5hdGVzIG9mIHRoZSBkcm9wIGFuZCBhbiBhcnJheSBvZiBwYXRoIHN0cmluZ3MuXHJcbiAqXHJcbiAqIEBleHBvcnRcclxuICogQHBhcmFtIHtPbkZpbGVEcm9wQ2FsbGJhY2t9IGNhbGxiYWNrIC0gQ2FsbGJhY2sgZm9yIE9uRmlsZURyb3AgcmV0dXJucyBhIHNsaWNlIG9mIGZpbGUgcGF0aCBzdHJpbmdzIHdoZW4gYSBkcm9wIGlzIGZpbmlzaGVkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFt1c2VEcm9wVGFyZ2V0PXRydWVdIC0gT25seSBjYWxsIHRoZSBjYWxsYmFjayB3aGVuIHRoZSBkcm9wIGZpbmlzaGVkIG9uIGFuIGVsZW1lbnQgdGhhdCBoYXMgdGhlIGRyb3AgdGFyZ2V0IHN0eWxlLiAoLS13YWlscy1kcm9wLXRhcmdldClcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBPbkZpbGVEcm9wKGNhbGxiYWNrLCB1c2VEcm9wVGFyZ2V0KSB7XHJcbiAgICBpZiAodHlwZW9mIGNhbGxiYWNrICE9PSBcImZ1bmN0aW9uXCIpIHtcclxuICAgICAgICBjb25zb2xlLmVycm9yKFwiRHJhZ0FuZERyb3BDYWxsYmFjayBpcyBub3QgYSBmdW5jdGlvblwiKTtcclxuICAgICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKGZsYWdzLnJlZ2lzdGVyZWQpIHtcclxuICAgICAgICByZXR1cm47XHJcbiAgICB9XHJcbiAgICBmbGFncy5yZWdpc3RlcmVkID0gdHJ1ZTtcclxuXHJcbiAgICBjb25zdCB1RFRQVCA9IHR5cGVvZiB1c2VEcm9wVGFyZ2V0O1xyXG4gICAgZmxhZ3MudXNlRHJvcFRhcmdldCA9IHVEVFBUID09PSBcInVuZGVmaW5lZFwiIHx8IHVEVFBUICE9PSBcImJvb2xlYW5cIiA/IGZsYWdzLmRlZmF1bHRVc2VEcm9wVGFyZ2V0IDogdXNlRHJvcFRhcmdldDtcclxuICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdkcmFnb3ZlcicsIG9uRHJhZ092ZXIpO1xyXG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ2RyYWdsZWF2ZScsIG9uRHJhZ0xlYXZlKTtcclxuICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdkcm9wJywgb25Ecm9wKTtcclxuXHJcbiAgICBsZXQgY2IgPSBjYWxsYmFjaztcclxuICAgIGlmIChmbGFncy51c2VEcm9wVGFyZ2V0KSB7XHJcbiAgICAgICAgY2IgPSBmdW5jdGlvbiAoeCwgeSwgcGF0aHMpIHtcclxuICAgICAgICAgICAgY29uc3QgZWxlbWVudCA9IGRvY3VtZW50LmVsZW1lbnRGcm9tUG9pbnQoeCwgeSlcclxuICAgICAgICAgICAgLy8gaWYgdGhlIGVsZW1lbnQgaXMgbnVsbCBvciBlbGVtZW50IGlzIG5vdCBjaGlsZCBvZiBkcm9wIHRhcmdldCBlbGVtZW50LCByZXR1cm4gbnVsbFxyXG4gICAgICAgICAgICBpZiAoIWVsZW1lbnQgfHwgIWNoZWNrU3R5bGVEcm9wVGFyZ2V0KGdldENvbXB1dGVkU3R5bGUoZWxlbWVudCkpKSB7XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gbnVsbDtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICBjYWxsYmFjayh4LCB5LCBwYXRocyk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIEV2ZW50c09uKFwid2FpbHM6ZmlsZS1kcm9wXCIsIGNiKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIE9uRmlsZURyb3BPZmYgcmVtb3ZlcyB0aGUgZHJhZyBhbmQgZHJvcCBsaXN0ZW5lcnMgYW5kIGhhbmRsZXJzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIE9uRmlsZURyb3BPZmYoKSB7XHJcbiAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcignZHJhZ292ZXInLCBvbkRyYWdPdmVyKTtcclxuICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKCdkcmFnbGVhdmUnLCBvbkRyYWdMZWF2ZSk7XHJcbiAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcignZHJvcCcsIG9uRHJvcCk7XHJcbiAgICBFdmVudHNPZmYoXCJ3YWlsczpmaWxlLWRyb3BcIik7XHJcbiAgICBmbGFncy5yZWdpc3RlcmVkID0gZmFsc2U7XHJcbn1cclxuIiwgIi8qXHJcbi0tZGVmYXVsdC1jb250ZXh0bWVudTogYXV0bzsgKGRlZmF1bHQpIHdpbGwgc2hvdyB0aGUgZGVmYXVsdCBjb250ZXh0IG1lbnUgaWYgY29udGVudEVkaXRhYmxlIGlzIHRydWUgT1IgdGV4dCBoYXMgYmVlbiBzZWxlY3RlZCBPUiBlbGVtZW50IGlzIGlucHV0IG9yIHRleHRhcmVhXHJcbi0tZGVmYXVsdC1jb250ZXh0bWVudTogc2hvdzsgd2lsbCBhbHdheXMgc2hvdyB0aGUgZGVmYXVsdCBjb250ZXh0IG1lbnVcclxuLS1kZWZhdWx0LWNvbnRleHRtZW51OiBoaWRlOyB3aWxsIGFsd2F5cyBoaWRlIHRoZSBkZWZhdWx0IGNvbnRleHQgbWVudVxyXG5cclxuVGhpcyBydWxlIGlzIGluaGVyaXRlZCBsaWtlIG5vcm1hbCBDU1MgcnVsZXMsIHNvIG5lc3Rpbmcgd29ya3MgYXMgZXhwZWN0ZWRcclxuKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHByb2Nlc3NEZWZhdWx0Q29udGV4dE1lbnUoZXZlbnQpIHtcclxuICAgIC8vIFByb2Nlc3MgZGVmYXVsdCBjb250ZXh0IG1lbnVcclxuICAgIGNvbnN0IGVsZW1lbnQgPSBldmVudC50YXJnZXQ7XHJcbiAgICBjb25zdCBjb21wdXRlZFN0eWxlID0gd2luZG93LmdldENvbXB1dGVkU3R5bGUoZWxlbWVudCk7XHJcbiAgICBjb25zdCBkZWZhdWx0Q29udGV4dE1lbnVBY3Rpb24gPSBjb21wdXRlZFN0eWxlLmdldFByb3BlcnR5VmFsdWUoXCItLWRlZmF1bHQtY29udGV4dG1lbnVcIikudHJpbSgpO1xyXG4gICAgc3dpdGNoIChkZWZhdWx0Q29udGV4dE1lbnVBY3Rpb24pIHtcclxuICAgICAgICBjYXNlIFwic2hvd1wiOlxyXG4gICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgY2FzZSBcImhpZGVcIjpcclxuICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcclxuICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgIGRlZmF1bHQ6XHJcbiAgICAgICAgICAgIC8vIENoZWNrIGlmIGNvbnRlbnRFZGl0YWJsZSBpcyB0cnVlXHJcbiAgICAgICAgICAgIGlmIChlbGVtZW50LmlzQ29udGVudEVkaXRhYmxlKSB7XHJcbiAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIENoZWNrIGlmIHRleHQgaGFzIGJlZW4gc2VsZWN0ZWQgYW5kIGFjdGlvbiBpcyBvbiB0aGUgc2VsZWN0ZWQgZWxlbWVudHNcclxuICAgICAgICAgICAgY29uc3Qgc2VsZWN0aW9uID0gd2luZG93LmdldFNlbGVjdGlvbigpO1xyXG4gICAgICAgICAgICBjb25zdCBoYXNTZWxlY3Rpb24gPSAoc2VsZWN0aW9uLnRvU3RyaW5nKCkubGVuZ3RoID4gMClcclxuICAgICAgICAgICAgaWYgKGhhc1NlbGVjdGlvbikge1xyXG4gICAgICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzZWxlY3Rpb24ucmFuZ2VDb3VudDsgaSsrKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgcmFuZ2UgPSBzZWxlY3Rpb24uZ2V0UmFuZ2VBdChpKTtcclxuICAgICAgICAgICAgICAgICAgICBjb25zdCByZWN0cyA9IHJhbmdlLmdldENsaWVudFJlY3RzKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCByZWN0cy5sZW5ndGg7IGorKykge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCByZWN0ID0gcmVjdHNbal07XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChkb2N1bWVudC5lbGVtZW50RnJvbVBvaW50KHJlY3QubGVmdCwgcmVjdC50b3ApID09PSBlbGVtZW50KSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgLy8gQ2hlY2sgaWYgdGFnbmFtZSBpcyBpbnB1dCBvciB0ZXh0YXJlYVxyXG4gICAgICAgICAgICBpZiAoZWxlbWVudC50YWdOYW1lID09PSBcIklOUFVUXCIgfHwgZWxlbWVudC50YWdOYW1lID09PSBcIlRFWFRBUkVBXCIpIHtcclxuICAgICAgICAgICAgICAgIGlmIChoYXNTZWxlY3Rpb24gfHwgKCFlbGVtZW50LnJlYWRPbmx5ICYmICFlbGVtZW50LmRpc2FibGVkKSkge1xyXG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gaGlkZSBkZWZhdWx0IGNvbnRleHQgbWVudVxyXG4gICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xyXG4gICAgfVxyXG59XHJcbiIsICIvKlxyXG4gX1x0ICAgX19cdCAgXyBfX1xyXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xyXG58IHwgL3wgLyAvIF9fIGAvIC8gLyBfX18vXHJcbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxyXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cclxuVGhlIGVsZWN0cm9uIGFsdGVybmF0aXZlIGZvciBHb1xyXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XHJcbiovXHJcbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cclxuaW1wb3J0ICogYXMgTG9nIGZyb20gJy4vbG9nJztcclxuaW1wb3J0IHtcclxuICBldmVudExpc3RlbmVycyxcclxuICBFdmVudHNFbWl0LFxyXG4gIEV2ZW50c05vdGlmeSxcclxuICBFdmVudHNPZmYsXHJcbiAgRXZlbnRzT2ZmQWxsLFxyXG4gIEV2ZW50c09uLFxyXG4gIEV2ZW50c09uY2UsXHJcbiAgRXZlbnRzT25NdWx0aXBsZSxcclxufSBmcm9tIFwiLi9ldmVudHNcIjtcclxuaW1wb3J0IHsgQ2FsbCwgQ2FsbGJhY2ssIGNhbGxiYWNrcyB9IGZyb20gJy4vY2FsbHMnO1xyXG5pbXBvcnQgeyBTZXRCaW5kaW5ncyB9IGZyb20gXCIuL2JpbmRpbmdzXCI7XHJcbmltcG9ydCAqIGFzIFdpbmRvdyBmcm9tIFwiLi93aW5kb3dcIjtcclxuaW1wb3J0ICogYXMgU2NyZWVuIGZyb20gXCIuL3NjcmVlblwiO1xyXG5pbXBvcnQgKiBhcyBCcm93c2VyIGZyb20gXCIuL2Jyb3dzZXJcIjtcclxuaW1wb3J0ICogYXMgQ2xpcGJvYXJkIGZyb20gXCIuL2NsaXBib2FyZFwiO1xyXG5pbXBvcnQgKiBhcyBEcmFnQW5kRHJvcCBmcm9tIFwiLi9kcmFnYW5kZHJvcFwiO1xyXG5pbXBvcnQgKiBhcyBDb250ZXh0TWVudSBmcm9tIFwiLi9jb250ZXh0bWVudVwiO1xyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIFF1aXQoKSB7XHJcbiAgICB3aW5kb3cuV2FpbHNJbnZva2UoJ1EnKTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIFNob3coKSB7XHJcbiAgICB3aW5kb3cuV2FpbHNJbnZva2UoJ1MnKTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIEhpZGUoKSB7XHJcbiAgICB3aW5kb3cuV2FpbHNJbnZva2UoJ0gnKTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIEVudmlyb25tZW50KCkge1xyXG4gICAgcmV0dXJuIENhbGwoXCI6d2FpbHM6RW52aXJvbm1lbnRcIik7XHJcbn1cclxuXHJcbi8vIFRoZSBKUyBydW50aW1lXHJcbndpbmRvdy5ydW50aW1lID0ge1xyXG4gICAgLi4uTG9nLFxyXG4gICAgLi4uV2luZG93LFxyXG4gICAgLi4uQnJvd3NlcixcclxuICAgIC4uLlNjcmVlbixcclxuICAgIC4uLkNsaXBib2FyZCxcclxuICAgIC4uLkRyYWdBbmREcm9wLFxyXG4gICAgRXZlbnRzT24sXHJcbiAgICBFdmVudHNPbmNlLFxyXG4gICAgRXZlbnRzT25NdWx0aXBsZSxcclxuICAgIEV2ZW50c0VtaXQsXHJcbiAgICBFdmVudHNPZmYsXHJcbiAgICBFdmVudHNPZmZBbGwsXHJcbiAgICBFbnZpcm9ubWVudCxcclxuICAgIFNob3csXHJcbiAgICBIaWRlLFxyXG4gICAgUXVpdFxyXG59O1xyXG5cclxuLy8gSW50ZXJuYWwgd2FpbHMgZW5kcG9pbnRzXHJcbndpbmRvdy53YWlscyA9IHtcclxuICAgIENhbGxiYWNrLFxyXG4gICAgRXZlbnRzTm90aWZ5LFxyXG4gICAgU2V0QmluZGluZ3MsXHJcbiAgICBldmVudExpc3RlbmVycyxcclxuICAgIGNhbGxiYWNrcyxcclxuICAgIGZsYWdzOiB7XHJcbiAgICAgICAgZGlzYWJsZVNjcm9sbGJhckRyYWc6IGZhbHNlLFxyXG4gICAgICAgIGRpc2FibGVEZWZhdWx0Q29udGV4dE1lbnU6IGZhbHNlLFxyXG4gICAgICAgIGVuYWJsZVJlc2l6ZTogZmFsc2UsXHJcbiAgICAgICAgZGVmYXVsdEN1cnNvcjogbnVsbCxcclxuICAgICAgICBib3JkZXJUaGlja25lc3M6IDYsXHJcbiAgICAgICAgc2hvdWxkRHJhZzogZmFsc2UsXHJcbiAgICAgICAgZGVmZXJEcmFnVG9Nb3VzZU1vdmU6IHRydWUsXHJcbiAgICAgICAgY3NzRHJhZ1Byb3BlcnR5OiBcIi0td2FpbHMtZHJhZ2dhYmxlXCIsXHJcbiAgICAgICAgY3NzRHJhZ1ZhbHVlOiBcImRyYWdcIixcclxuICAgICAgICBjc3NEcm9wUHJvcGVydHk6IFwiLS13YWlscy1kcm9wLXRhcmdldFwiLFxyXG4gICAgICAgIGNzc0Ryb3BWYWx1ZTogXCJkcm9wXCIsXHJcbiAgICAgICAgZW5hYmxlV2FpbHNEcmFnQW5kRHJvcDogZmFsc2UsXHJcbiAgICB9XHJcbn07XHJcblxyXG4vLyBTZXQgdGhlIGJpbmRpbmdzXHJcbmlmICh3aW5kb3cud2FpbHNiaW5kaW5ncykge1xyXG4gICAgd2luZG93LndhaWxzLlNldEJpbmRpbmdzKHdpbmRvdy53YWlsc2JpbmRpbmdzKTtcclxuICAgIGRlbGV0ZSB3aW5kb3cud2FpbHMuU2V0QmluZGluZ3M7XHJcbn1cclxuXHJcbi8vIChib29sKSBUaGlzIGlzIGV2YWx1YXRlZCBhdCBidWlsZCB0aW1lIGluIHBhY2thZ2UuanNvblxyXG5pZiAoIURFQlVHKSB7XHJcbiAgICBkZWxldGUgd2luZG93LndhaWxzYmluZGluZ3M7XHJcbn1cclxuXHJcbmxldCBkcmFnVGVzdCA9IGZ1bmN0aW9uKGUpIHtcclxuICAgIHZhciB2YWwgPSB3aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZShlLnRhcmdldCkuZ2V0UHJvcGVydHlWYWx1ZSh3aW5kb3cud2FpbHMuZmxhZ3MuY3NzRHJhZ1Byb3BlcnR5KTtcclxuICAgIGlmICh2YWwpIHtcclxuICAgICAgICB2YWwgPSB2YWwudHJpbSgpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICh2YWwgIT09IHdpbmRvdy53YWlscy5mbGFncy5jc3NEcmFnVmFsdWUpIHtcclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKGUuYnV0dG9ucyAhPT0gMSkge1xyXG4gICAgICAgIC8vIERvIG5vdCBzdGFydCBkcmFnZ2luZyBpZiBub3QgdGhlIHByaW1hcnkgYnV0dG9uIGhhcyBiZWVuIGNsaWNrZWQuXHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChlLmRldGFpbCAhPT0gMSkge1xyXG4gICAgICAgIC8vIERvIG5vdCBzdGFydCBkcmFnZ2luZyBpZiBtb3JlIHRoYW4gb25jZSBoYXMgYmVlbiBjbGlja2VkLCBlLmcuIHdoZW4gZG91YmxlIGNsaWNraW5nXHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB0cnVlO1xyXG59O1xyXG5cclxud2luZG93LndhaWxzLnNldENTU0RyYWdQcm9wZXJ0aWVzID0gZnVuY3Rpb24ocHJvcGVydHksIHZhbHVlKSB7XHJcbiAgICB3aW5kb3cud2FpbHMuZmxhZ3MuY3NzRHJhZ1Byb3BlcnR5ID0gcHJvcGVydHk7XHJcbiAgICB3aW5kb3cud2FpbHMuZmxhZ3MuY3NzRHJhZ1ZhbHVlID0gdmFsdWU7XHJcbn1cclxuXHJcbndpbmRvdy53YWlscy5zZXRDU1NEcm9wUHJvcGVydGllcyA9IGZ1bmN0aW9uKHByb3BlcnR5LCB2YWx1ZSkge1xyXG4gICAgd2luZG93LndhaWxzLmZsYWdzLmNzc0Ryb3BQcm9wZXJ0eSA9IHByb3BlcnR5O1xyXG4gICAgd2luZG93LndhaWxzLmZsYWdzLmNzc0Ryb3BWYWx1ZSA9IHZhbHVlO1xyXG59XHJcblxyXG53aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignbW91c2Vkb3duJywgKGUpID0+IHtcclxuICAgIC8vIENoZWNrIGZvciByZXNpemluZ1xyXG4gICAgaWYgKHdpbmRvdy53YWlscy5mbGFncy5yZXNpemVFZGdlKSB7XHJcbiAgICAgICAgd2luZG93LldhaWxzSW52b2tlKFwicmVzaXplOlwiICsgd2luZG93LndhaWxzLmZsYWdzLnJlc2l6ZUVkZ2UpO1xyXG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcclxuICAgICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKGRyYWdUZXN0KGUpKSB7XHJcbiAgICAgICAgaWYgKHdpbmRvdy53YWlscy5mbGFncy5kaXNhYmxlU2Nyb2xsYmFyRHJhZykge1xyXG4gICAgICAgICAgICAvLyBUaGlzIGNoZWNrcyBmb3IgY2xpY2tzIG9uIHRoZSBzY3JvbGwgYmFyXHJcbiAgICAgICAgICAgIGlmIChlLm9mZnNldFggPiBlLnRhcmdldC5jbGllbnRXaWR0aCB8fCBlLm9mZnNldFkgPiBlLnRhcmdldC5jbGllbnRIZWlnaHQpIHtcclxuICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAod2luZG93LndhaWxzLmZsYWdzLmRlZmVyRHJhZ1RvTW91c2VNb3ZlKSB7XHJcbiAgICAgICAgICAgIHdpbmRvdy53YWlscy5mbGFncy5zaG91bGREcmFnID0gdHJ1ZTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KClcclxuICAgICAgICAgICAgd2luZG93LldhaWxzSW52b2tlKFwiZHJhZ1wiKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgICB3aW5kb3cud2FpbHMuZmxhZ3Muc2hvdWxkRHJhZyA9IGZhbHNlO1xyXG4gICAgfVxyXG59KTtcclxuXHJcbndpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdtb3VzZXVwJywgKCkgPT4ge1xyXG4gICAgd2luZG93LndhaWxzLmZsYWdzLnNob3VsZERyYWcgPSBmYWxzZTtcclxufSk7XHJcblxyXG5mdW5jdGlvbiBzZXRSZXNpemUoY3Vyc29yKSB7XHJcbiAgICBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuc3R5bGUuY3Vyc29yID0gY3Vyc29yIHx8IHdpbmRvdy53YWlscy5mbGFncy5kZWZhdWx0Q3Vyc29yO1xyXG4gICAgd2luZG93LndhaWxzLmZsYWdzLnJlc2l6ZUVkZ2UgPSBjdXJzb3I7XHJcbn1cclxuXHJcbndpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdtb3VzZW1vdmUnLCBmdW5jdGlvbihlKSB7XHJcbiAgICBpZiAod2luZG93LndhaWxzLmZsYWdzLnNob3VsZERyYWcpIHtcclxuICAgICAgICB3aW5kb3cud2FpbHMuZmxhZ3Muc2hvdWxkRHJhZyA9IGZhbHNlO1xyXG4gICAgICAgIGxldCBtb3VzZVByZXNzZWQgPSBlLmJ1dHRvbnMgIT09IHVuZGVmaW5lZCA/IGUuYnV0dG9ucyA6IGUud2hpY2g7XHJcbiAgICAgICAgaWYgKG1vdXNlUHJlc3NlZCA+IDApIHtcclxuICAgICAgICAgICAgd2luZG93LldhaWxzSW52b2tlKFwiZHJhZ1wiKTtcclxuICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIGlmICghd2luZG93LndhaWxzLmZsYWdzLmVuYWJsZVJlc2l6ZSkge1xyXG4gICAgICAgIHJldHVybjtcclxuICAgIH1cclxuICAgIGlmICh3aW5kb3cud2FpbHMuZmxhZ3MuZGVmYXVsdEN1cnNvciA9PSBudWxsKSB7XHJcbiAgICAgICAgd2luZG93LndhaWxzLmZsYWdzLmRlZmF1bHRDdXJzb3IgPSBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuc3R5bGUuY3Vyc29yO1xyXG4gICAgfVxyXG4gICAgaWYgKHdpbmRvdy5vdXRlcldpZHRoIC0gZS5jbGllbnRYIDwgd2luZG93LndhaWxzLmZsYWdzLmJvcmRlclRoaWNrbmVzcyAmJiB3aW5kb3cub3V0ZXJIZWlnaHQgLSBlLmNsaWVudFkgPCB3aW5kb3cud2FpbHMuZmxhZ3MuYm9yZGVyVGhpY2tuZXNzKSB7XHJcbiAgICAgICAgZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LnN0eWxlLmN1cnNvciA9IFwic2UtcmVzaXplXCI7XHJcbiAgICB9XHJcbiAgICBsZXQgcmlnaHRCb3JkZXIgPSB3aW5kb3cub3V0ZXJXaWR0aCAtIGUuY2xpZW50WCA8IHdpbmRvdy53YWlscy5mbGFncy5ib3JkZXJUaGlja25lc3M7XHJcbiAgICBsZXQgbGVmdEJvcmRlciA9IGUuY2xpZW50WCA8IHdpbmRvdy53YWlscy5mbGFncy5ib3JkZXJUaGlja25lc3M7XHJcbiAgICBsZXQgdG9wQm9yZGVyID0gZS5jbGllbnRZIDwgd2luZG93LndhaWxzLmZsYWdzLmJvcmRlclRoaWNrbmVzcztcclxuICAgIGxldCBib3R0b21Cb3JkZXIgPSB3aW5kb3cub3V0ZXJIZWlnaHQgLSBlLmNsaWVudFkgPCB3aW5kb3cud2FpbHMuZmxhZ3MuYm9yZGVyVGhpY2tuZXNzO1xyXG5cclxuICAgIC8vIElmIHdlIGFyZW4ndCBvbiBhbiBlZGdlLCBidXQgd2VyZSwgcmVzZXQgdGhlIGN1cnNvciB0byBkZWZhdWx0XHJcbiAgICBpZiAoIWxlZnRCb3JkZXIgJiYgIXJpZ2h0Qm9yZGVyICYmICF0b3BCb3JkZXIgJiYgIWJvdHRvbUJvcmRlciAmJiB3aW5kb3cud2FpbHMuZmxhZ3MucmVzaXplRWRnZSAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgc2V0UmVzaXplKCk7XHJcbiAgICB9IGVsc2UgaWYgKHJpZ2h0Qm9yZGVyICYmIGJvdHRvbUJvcmRlcikgc2V0UmVzaXplKFwic2UtcmVzaXplXCIpO1xyXG4gICAgZWxzZSBpZiAobGVmdEJvcmRlciAmJiBib3R0b21Cb3JkZXIpIHNldFJlc2l6ZShcInN3LXJlc2l6ZVwiKTtcclxuICAgIGVsc2UgaWYgKGxlZnRCb3JkZXIgJiYgdG9wQm9yZGVyKSBzZXRSZXNpemUoXCJudy1yZXNpemVcIik7XHJcbiAgICBlbHNlIGlmICh0b3BCb3JkZXIgJiYgcmlnaHRCb3JkZXIpIHNldFJlc2l6ZShcIm5lLXJlc2l6ZVwiKTtcclxuICAgIGVsc2UgaWYgKGxlZnRCb3JkZXIpIHNldFJlc2l6ZShcInctcmVzaXplXCIpO1xyXG4gICAgZWxzZSBpZiAodG9wQm9yZGVyKSBzZXRSZXNpemUoXCJuLXJlc2l6ZVwiKTtcclxuICAgIGVsc2UgaWYgKGJvdHRvbUJvcmRlcikgc2V0UmVzaXplKFwicy1yZXNpemVcIik7XHJcbiAgICBlbHNlIGlmIChyaWdodEJvcmRlcikgc2V0UmVzaXplKFwiZS1yZXNpemVcIik7XHJcblxyXG59KTtcclxuXHJcbi8vIFNldHVwIGNvbnRleHQgbWVudSBob29rXHJcbndpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdjb250ZXh0bWVudScsIGZ1bmN0aW9uKGUpIHtcclxuICAgIC8vIGFsd2F5cyBzaG93IHRoZSBjb250ZXh0bWVudSBpbiBkZWJ1ZyAmIGRldlxyXG4gICAgaWYgKERFQlVHKSByZXR1cm47XHJcblxyXG4gICAgaWYgKHdpbmRvdy53YWlscy5mbGFncy5kaXNhYmxlRGVmYXVsdENvbnRleHRNZW51KSB7XHJcbiAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgICBDb250ZXh0TWVudS5wcm9jZXNzRGVmYXVsdENvbnRleHRNZW51KGUpO1xyXG4gICAgfVxyXG59KTtcclxuXHJcbndpbmRvdy5XYWlsc0ludm9rZShcInJ1bnRpbWU6cmVhZHlcIik7Il0sCiAgIm1hcHBpbmdzIjogIjs7Ozs7Ozs7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFrQkEsV0FBUyxlQUFlLE9BQU8sU0FBUztBQUl2QyxXQUFPLFlBQVksTUFBTSxRQUFRLE9BQU87QUFBQSxFQUN6QztBQVFPLFdBQVMsU0FBUyxTQUFTO0FBQ2pDLG1CQUFlLEtBQUssT0FBTztBQUFBLEVBQzVCO0FBUU8sV0FBUyxTQUFTLFNBQVM7QUFDakMsbUJBQWUsS0FBSyxPQUFPO0FBQUEsRUFDNUI7QUFRTyxXQUFTLFNBQVMsU0FBUztBQUNqQyxtQkFBZSxLQUFLLE9BQU87QUFBQSxFQUM1QjtBQVFPLFdBQVMsUUFBUSxTQUFTO0FBQ2hDLG1CQUFlLEtBQUssT0FBTztBQUFBLEVBQzVCO0FBUU8sV0FBUyxXQUFXLFNBQVM7QUFDbkMsbUJBQWUsS0FBSyxPQUFPO0FBQUEsRUFDNUI7QUFRTyxXQUFTLFNBQVMsU0FBUztBQUNqQyxtQkFBZSxLQUFLLE9BQU87QUFBQSxFQUM1QjtBQVFPLFdBQVMsU0FBUyxTQUFTO0FBQ2pDLG1CQUFlLEtBQUssT0FBTztBQUFBLEVBQzVCO0FBUU8sV0FBUyxZQUFZLFVBQVU7QUFDckMsbUJBQWUsS0FBSyxRQUFRO0FBQUEsRUFDN0I7QUFHTyxNQUFNLFdBQVc7QUFBQSxJQUN2QixPQUFPO0FBQUEsSUFDUCxPQUFPO0FBQUEsSUFDUCxNQUFNO0FBQUEsSUFDTixTQUFTO0FBQUEsSUFDVCxPQUFPO0FBQUEsRUFDUjs7O0FDOUZBLE1BQU0sV0FBTixNQUFlO0FBQUEsSUFRWCxZQUFZLFdBQVcsVUFBVSxjQUFjO0FBQzNDLFdBQUssWUFBWTtBQUVqQixXQUFLLGVBQWUsZ0JBQWdCO0FB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 diff --git a/v2/internal/frontend/runtime/runtime_dev_desktop.go b/v2/internal/frontend/runtime/runtime_dev_desktop.go new file mode 100644 index 000000000..c0dcb1fc5 --- /dev/null +++ b/v2/internal/frontend/runtime/runtime_dev_desktop.go @@ -0,0 +1,8 @@ +//go:build dev || bindings || (!dev && !production && !bindings) + +package runtime + +import _ "embed" + +//go:embed runtime_dev_desktop.js +var RuntimeDesktopJS []byte diff --git a/v2/internal/frontend/runtime/runtime_dev_desktop.js b/v2/internal/frontend/runtime/runtime_dev_desktop.js new file mode 100644 index 000000000..9106a51cf --- /dev/null +++ b/v2/internal/frontend/runtime/runtime_dev_desktop.js @@ -0,0 +1,369 @@ +(() => { + var __defProp = Object.defineProperty; + var __markAsModule = (target) => __defProp(target, "__esModule", { value: true }); + var __export = (target, all) => { + __markAsModule(target); + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); + }; + + // desktop/log.js + var log_exports = {}; + __export(log_exports, { + LogDebug: () => LogDebug, + LogError: () => LogError, + LogFatal: () => LogFatal, + LogInfo: () => LogInfo, + LogLevel: () => LogLevel, + LogPrint: () => LogPrint, + LogTrace: () => LogTrace, + LogWarning: () => LogWarning, + SetLogLevel: () => SetLogLevel + }); + function sendLogMessage(level, message) { + window.WailsInvoke("L" + level + message); + } + function LogTrace(message) { + sendLogMessage("T", message); + } + function LogPrint(message) { + sendLogMessage("P", message); + } + function LogDebug(message) { + sendLogMessage("D", message); + } + function LogInfo(message) { + sendLogMessage("I", message); + } + function LogWarning(message) { + sendLogMessage("W", message); + } + function LogError(message) { + sendLogMessage("E", message); + } + function LogFatal(message) { + sendLogMessage("F", message); + } + function SetLogLevel(loglevel) { + sendLogMessage("S", loglevel); + } + var LogLevel = { + TRACE: 1, + DEBUG: 2, + INFO: 3, + WARNING: 4, + ERROR: 5 + }; + + // desktop/events.js + var Listener = class { + constructor(callback, maxCallbacks) { + maxCallbacks = maxCallbacks || -1; + this.Callback = (data) => { + callback.apply(null, data); + if (maxCallbacks === -1) { + return false; + } + maxCallbacks -= 1; + return maxCallbacks === 0; + }; + } + }; + var eventListeners = {}; + function EventsOnMultiple(eventName, callback, maxCallbacks) { + eventListeners[eventName] = eventListeners[eventName] || []; + const thisListener = new Listener(callback, maxCallbacks); + eventListeners[eventName].push(thisListener); + } + function EventsOn(eventName, callback) { + EventsOnMultiple(eventName, callback, -1); + } + function EventsOnce(eventName, callback) { + EventsOnMultiple(eventName, callback, 1); + } + function notifyListeners(eventData) { + let eventName = eventData.name; + if (eventListeners[eventName]) { + const newEventListenerList = eventListeners[eventName].slice(); + for (let count = 0; count < eventListeners[eventName].length; count += 1) { + const listener = eventListeners[eventName][count]; + let data = eventData.data; + const destroy = listener.Callback(data); + if (destroy) { + newEventListenerList.splice(count, 1); + } + } + eventListeners[eventName] = newEventListenerList; + } + } + function EventsNotify(notifyMessage) { + let message; + try { + message = JSON.parse(notifyMessage); + } catch (e) { + const error = "Invalid JSON passed to Notify: " + notifyMessage; + throw new Error(error); + } + notifyListeners(message); + } + function EventsEmit(eventName) { + const payload = { + name: eventName, + data: [].slice.apply(arguments).slice(1) + }; + notifyListeners(payload); + window.WailsInvoke("EE" + JSON.stringify(payload)); + } + function EventsOff(eventName) { + eventListeners.delete(eventName); + window.WailsInvoke("EX" + eventName); + } + + // desktop/calls.js + var callbacks = {}; + function cryptoRandom() { + var array = new Uint32Array(1); + return window.crypto.getRandomValues(array)[0]; + } + function basicRandom() { + return Math.random() * 9007199254740991; + } + var randomFunc; + if (window.crypto) { + randomFunc = cryptoRandom; + } else { + randomFunc = basicRandom; + } + function Call(name, args, timeout) { + if (timeout == null) { + timeout = 0; + } + return new Promise(function(resolve, reject) { + var callbackID; + do { + callbackID = name + "-" + randomFunc(); + } while (callbacks[callbackID]); + var timeoutHandle; + if (timeout > 0) { + timeoutHandle = setTimeout(function() { + reject(Error("Call to " + name + " timed out. Request ID: " + callbackID)); + }, timeout); + } + callbacks[callbackID] = { + timeoutHandle, + reject, + resolve + }; + try { + const payload = { + name, + args, + callbackID + }; + window.WailsInvoke("C" + JSON.stringify(payload)); + } catch (e) { + console.error(e); + } + }); + } + function Callback(incomingMessage) { + var message; + try { + message = JSON.parse(incomingMessage); + } catch (e) { + const error = `Invalid JSON passed to callback: ${e.message}. Message: ${incomingMessage}`; + wails.LogDebug(error); + throw new Error(error); + } + var callbackID = message.callbackid; + var callbackData = callbacks[callbackID]; + if (!callbackData) { + const error = `Callback '${callbackID}' not registered!!!`; + console.error(error); + throw new Error(error); + } + clearTimeout(callbackData.timeoutHandle); + delete callbacks[callbackID]; + if (message.error) { + callbackData.reject(message.error); + } else { + callbackData.resolve(message.result); + } + } + + // desktop/bindings.js + window.go = {}; + function SetBindings(bindingsMap) { + try { + bindingsMap = JSON.parse(bindingsMap); + } catch (e) { + console.error(e); + } + window.go = window.go || {}; + Object.keys(bindingsMap).forEach((packageName) => { + window.go[packageName] = window.go[packageName] || {}; + Object.keys(bindingsMap[packageName]).forEach((structName) => { + window.go[packageName][structName] = window.go[packageName][structName] || {}; + Object.keys(bindingsMap[packageName][structName]).forEach((methodName) => { + window.go[packageName][structName][methodName] = function() { + let timeout = 0; + function dynamic() { + const args = [].slice.call(arguments); + return Call([packageName, structName, methodName].join("."), args, timeout); + } + dynamic.setTimeout = function(newTimeout) { + timeout = newTimeout; + }; + dynamic.getTimeout = function() { + return timeout; + }; + return dynamic; + }(); + }); + }); + }); + } + + // desktop/window.js + var window_exports = {}; + __export(window_exports, { + WindowCenter: () => WindowCenter, + WindowFullscreen: () => WindowFullscreen, + WindowGetPosition: () => WindowGetPosition, + WindowGetSize: () => WindowGetSize, + WindowHide: () => WindowHide, + WindowMaximise: () => WindowMaximise, + WindowMinimise: () => WindowMinimise, + WindowReload: () => WindowReload, + WindowSetMaxSize: () => WindowSetMaxSize, + WindowSetMinSize: () => WindowSetMinSize, + WindowSetPosition: () => WindowSetPosition, + WindowSetRGBA: () => WindowSetRGBA, + WindowSetSize: () => WindowSetSize, + WindowSetTitle: () => WindowSetTitle, + WindowShow: () => WindowShow, + WindowUnFullscreen: () => WindowUnFullscreen, + WindowUnmaximise: () => WindowUnmaximise, + WindowUnminimise: () => WindowUnminimise + }); + function WindowReload() { + window.location.reload(); + } + function WindowCenter() { + window.WailsInvoke("Wc"); + } + function WindowSetTitle(title) { + window.WailsInvoke("WT" + title); + } + function WindowFullscreen() { + window.WailsInvoke("WF"); + } + function WindowUnFullscreen() { + window.WailsInvoke("Wf"); + } + function WindowSetSize(width, height) { + window.WailsInvoke("Ws:" + width + ":" + height); + } + function WindowGetSize() { + return Call(":wails:WindowGetSize"); + } + function WindowSetMaxSize(width, height) { + window.WailsInvoke("WZ:" + width + ":" + height); + } + function WindowSetMinSize(width, height) { + window.WailsInvoke("Wz:" + width + ":" + height); + } + function WindowSetPosition(x, y) { + window.WailsInvoke("Wp:" + x + ":" + y); + } + function WindowGetPosition() { + return Call(":wails:WindowGetPos"); + } + function WindowHide() { + window.WailsInvoke("WH"); + } + function WindowShow() { + window.WailsInvoke("WS"); + } + function WindowMaximise() { + window.WailsInvoke("WM"); + } + function WindowUnmaximise() { + window.WailsInvoke("WU"); + } + function WindowMinimise() { + window.WailsInvoke("Wm"); + } + function WindowUnminimise() { + window.WailsInvoke("Wu"); + } + function WindowSetRGBA(RGBA) { + let rgba = JSON.stringify(RGBA); + window.WailsInvoke("Wr:" + rgba); + } + + // desktop/browser.js + var browser_exports = {}; + __export(browser_exports, { + BrowserOpenURL: () => BrowserOpenURL + }); + function BrowserOpenURL(url) { + window.WailsInvoke("BO:" + url); + } + + // desktop/main.js + function Quit() { + window.WailsInvoke("Q"); + } + window.runtime = { + ...log_exports, + ...window_exports, + ...browser_exports, + EventsOn, + EventsOnce, + EventsOnMultiple, + EventsEmit, + EventsOff, + Quit + }; + window.wails = { + Callback, + EventsNotify, + SetBindings, + eventListeners, + callbacks, + flags: { + disableScrollbarDrag: false, + disableWailsDefaultContextMenu: false + } + }; + window.wails.SetBindings(window.wailsbindings); + delete window.wails.SetBindings; + if (true) { + delete window.wailsbindings; + } + window.addEventListener("mousedown", (e) => { + let currentElement = e.target; + while (currentElement != null) { + if (currentElement.hasAttribute("data-wails-no-drag")) { + break; + } else if (currentElement.hasAttribute("data-wails-drag")) { + if (window.wails.flags.disableScrollbarDrag) { + if (e.offsetX > e.target.clientWidth || e.offsetY > e.target.clientHeight) { + break; + } + } + window.WailsInvoke("drag"); + e.preventDefault(); + break; + } + currentElement = currentElement.parentElement; + } + }); + window.addEventListener("contextmenu", function(e) { + if (window.wails.flags.disableWailsDefaultContextMenu) { + e.preventDefault(); + } + }); +})(); +//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiZGVza3RvcC9sb2cuanMiLCAiZGVza3RvcC9ldmVudHMuanMiLCAiZGVza3RvcC9jYWxscy5qcyIsICJkZXNrdG9wL2JpbmRpbmdzLmpzIiwgImRlc2t0b3Avd2luZG93LmpzIiwgImRlc2t0b3AvYnJvd3Nlci5qcyIsICJkZXNrdG9wL21haW4uanMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbIi8qXG4gXyAgICAgICBfXyAgICAgIF8gX19cbnwgfCAgICAgLyAvX19fIF8oXykgL19fX19cbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxufF9fL3xfXy9cXF9fLF8vXy9fL19fX18vXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XG4qL1xuXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA2ICovXG5cbi8qKlxuICogU2VuZHMgYSBsb2cgbWVzc2FnZSB0byB0aGUgYmFja2VuZCB3aXRoIHRoZSBnaXZlbiBsZXZlbCArIG1lc3NhZ2VcbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gbGV2ZWxcbiAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlXG4gKi9cbmZ1bmN0aW9uIHNlbmRMb2dNZXNzYWdlKGxldmVsLCBtZXNzYWdlKSB7XG5cblx0Ly8gTG9nIE1lc3NhZ2UgZm9ybWF0OlxuXHQvLyBsW3R5cGVdW21lc3NhZ2VdXG5cdHdpbmRvdy5XYWlsc0ludm9rZSgnTCcgKyBsZXZlbCArIG1lc3NhZ2UpO1xufVxuXG4vKipcbiAqIExvZyB0aGUgZ2l2ZW4gdHJhY2UgbWVzc2FnZSB3aXRoIHRoZSBiYWNrZW5kXG4gKlxuICogQGV4cG9ydFxuICogQHBhcmFtIHtzdHJpbmd9IG1lc3NhZ2VcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIExvZ1RyYWNlKG1lc3NhZ2UpIHtcblx0c2VuZExvZ01lc3NhZ2UoJ1QnLCBtZXNzYWdlKTtcbn1cblxuLyoqXG4gKiBMb2cgdGhlIGdpdmVuIG1lc3NhZ2Ugd2l0aCB0aGUgYmFja2VuZFxuICpcbiAqIEBleHBvcnRcbiAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBMb2dQcmludChtZXNzYWdlKSB7XG5cdHNlbmRMb2dNZXNzYWdlKCdQJywgbWVzc2FnZSk7XG59XG5cbi8qKlxuICogTG9nIHRoZSBnaXZlbiBkZWJ1ZyBtZXNzYWdlIHdpdGggdGhlIGJhY2tlbmRcbiAqXG4gKiBAZXhwb3J0XG4gKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZVxuICovXG5leHBvcnQgZnVuY3Rpb24gTG9nRGVidWcobWVzc2FnZSkge1xuXHRzZW5kTG9nTWVzc2FnZSgnRCcsIG1lc3NhZ2UpO1xufVxuXG4vKipcbiAqIExvZyB0aGUgZ2l2ZW4gaW5mbyBtZXNzYWdlIHdpdGggdGhlIGJhY2tlbmRcbiAqXG4gKiBAZXhwb3J0XG4gKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZVxuICovXG5leHBvcnQgZnVuY3Rpb24gTG9nSW5mbyhtZXNzYWdlKSB7XG5cdHNlbmRMb2dNZXNzYWdlKCdJJywgbWVzc2FnZSk7XG59XG5cbi8qKlxuICogTG9nIHRoZSBnaXZlbiB3YXJuaW5nIG1lc3NhZ2Ugd2l0aCB0aGUgYmFja2VuZFxuICpcbiAqIEBleHBvcnRcbiAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBMb2dXYXJuaW5nKG1lc3NhZ2UpIHtcblx0c2VuZExvZ01lc3NhZ2UoJ1cnLCBtZXNzYWdlKTtcbn1cblxuLyoqXG4gKiBMb2cgdGhlIGdpdmVuIGVycm9yIG1lc3NhZ2Ugd2l0aCB0aGUgYmFja2VuZFxuICpcbiAqIEBleHBvcnRcbiAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBMb2dFcnJvcihtZXNzYWdlKSB7XG5cdHNlbmRMb2dNZXNzYWdlKCdFJywgbWVzc2FnZSk7XG59XG5cbi8qKlxuICogTG9nIHRoZSBnaXZlbiBmYXRhbCBtZXNzYWdlIHdpdGggdGhlIGJhY2tlbmRcbiAqXG4gKiBAZXhwb3J0XG4gKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZVxuICovXG5leHBvcnQgZnVuY3Rpb24gTG9nRmF0YWwobWVzc2FnZSkge1xuXHRzZW5kTG9nTWVzc2FnZSgnRicsIG1lc3NhZ2UpO1xufVxuXG4vKipcbiAqIFNldHMgdGhlIExvZyBsZXZlbCB0byB0aGUgZ2l2ZW4gbG9nIGxldmVsXG4gKlxuICogQGV4cG9ydFxuICogQHBhcmFtIHtudW1iZXJ9IGxvZ2xldmVsXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBTZXRMb2dMZXZlbChsb2dsZXZlbCkge1xuXHRzZW5kTG9nTWVzc2FnZSgnUycsIGxvZ2xldmVsKTtcbn1cblxuLy8gTG9nIGxldmVsc1xuZXhwb3J0IGNvbnN0IExvZ0xldmVsID0ge1xuXHRUUkFDRTogMSxcblx0REVCVUc6IDIsXG5cdElORk86IDMsXG5cdFdBUk5JTkc6IDQsXG5cdEVSUk9SOiA1LFxufTtcbiIsICIvKlxuIF8gICAgICAgX18gICAgICBfIF9fXG58IHwgICAgIC8gL19fXyBfKF8pIC9fX19fXG58IHwgL3wgLyAvIF9fIGAvIC8gLyBfX18vXG58IHwvIHwvIC8gL18vIC8gLyAoX18gIClcbnxfXy98X18vXFxfXyxfL18vXy9fX19fL1xuVGhlIGVsZWN0cm9uIGFsdGVybmF0aXZlIGZvciBHb1xuKGMpIExlYSBBbnRob255IDIwMTktcHJlc2VudFxuKi9cbi8qIGpzaGludCBlc3ZlcnNpb246IDYgKi9cblxuLy8gRGVmaW5lcyBhIHNpbmdsZSBsaXN0ZW5lciB3aXRoIGEgbWF4aW11bSBudW1iZXIgb2YgdGltZXMgdG8gY2FsbGJhY2tcblxuLyoqXG4gKiBUaGUgTGlzdGVuZXIgY2xhc3MgZGVmaW5lcyBhIGxpc3RlbmVyISA6LSlcbiAqXG4gKiBAY2xhc3MgTGlzdGVuZXJcbiAqL1xuY2xhc3MgTGlzdGVuZXIge1xuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYW4gaW5zdGFuY2Ugb2YgTGlzdGVuZXIuXG4gICAgICogQHBhcmFtIHtmdW5jdGlvbn0gY2FsbGJhY2tcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gbWF4Q2FsbGJhY2tzXG4gICAgICogQG1lbWJlcm9mIExpc3RlbmVyXG4gICAgICovXG4gICAgY29uc3RydWN0b3IoY2FsbGJhY2ssIG1heENhbGxiYWNrcykge1xuICAgICAgICAvLyBEZWZhdWx0IG9mIC0xIG1lYW5zIGluZmluaXRlXG4gICAgICAgIG1heENhbGxiYWNrcyA9IG1heENhbGxiYWNrcyB8fCAtMTtcbiAgICAgICAgLy8gQ2FsbGJhY2sgaW52b2tlcyB0aGUgY2FsbGJhY2sgd2l0aCB0aGUgZ2l2ZW4gZGF0YVxuICAgICAgICAvLyBSZXR1cm5zIHRydWUgaWYgdGhpcyBsaXN0ZW5lciBzaG91bGQgYmUgZGVzdHJveWVkXG4gICAgICAgIHRoaXMuQ2FsbGJhY2sgPSAoZGF0YSkgPT4ge1xuICAgICAgICAgICAgY2FsbGJhY2suYXBwbHkobnVsbCwgZGF0YSk7XG4gICAgICAgICAgICAvLyBJZiBtYXhDYWxsYmFja3MgaXMgaW5maW5pdGUsIHJldHVybiBmYWxzZSAoZG8gbm90IGRlc3Ryb3kpXG4gICAgICAgICAgICBpZiAobWF4Q2FsbGJhY2tzID09PSAtMSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIERlY3JlbWVudCBtYXhDYWxsYmFja3MuIFJldHVybiB0cnVlIGlmIG5vdyAwLCBvdGhlcndpc2UgZmFsc2VcbiAgICAgICAgICAgIG1heENhbGxiYWNrcyAtPSAxO1xuICAgICAgICAgICAgcmV0dXJuIG1heENhbGxiYWNrcyA9PT0gMDtcbiAgICAgICAgfTtcbiAgICB9XG59XG5cbmV4cG9ydCBjb25zdCBldmVudExpc3RlbmVycyA9IHt9O1xuXG4vKipcbiAqIFJlZ2lzdGVycyBhbiBldmVudCBsaXN0ZW5lciB0aGF0IHdpbGwgYmUgaW52b2tlZCBgbWF4Q2FsbGJhY2tzYCB0aW1lcyBiZWZvcmUgYmVpbmcgZGVzdHJveWVkXG4gKlxuICogQGV4cG9ydFxuICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50TmFtZVxuICogQHBhcmFtIHtmdW5jdGlvbn0gY2FsbGJhY2tcbiAqIEBwYXJhbSB7bnVtYmVyfSBtYXhDYWxsYmFja3NcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIEV2ZW50c09uTXVsdGlwbGUoZXZlbnROYW1lLCBjYWxsYmFjaywgbWF4Q2FsbGJhY2tzKSB7XG4gICAgZXZlbnRMaXN0ZW5lcnNbZXZlbnROYW1lXSA9IGV2ZW50TGlzdGVuZXJzW2V2ZW50TmFtZV0gfHwgW107XG4gICAgY29uc3QgdGhpc0xpc3RlbmVyID0gbmV3IExpc3RlbmVyKGNhbGxiYWNrLCBtYXhDYWxsYmFja3MpO1xuICAgIGV2ZW50TGlzdGVuZXJzW2V2ZW50TmFtZV0ucHVzaCh0aGlzTGlzdGVuZXIpO1xufVxuXG4vKipcbiAqIFJlZ2lzdGVycyBhbiBldmVudCBsaXN0ZW5lciB0aGF0IHdpbGwgYmUgaW52b2tlZCBldmVyeSB0aW1lIHRoZSBldmVudCBpcyBlbWl0dGVkXG4gKlxuICogQGV4cG9ydFxuICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50TmFtZVxuICogQHBhcmFtIHtmdW5jdGlvbn0gY2FsbGJhY2tcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIEV2ZW50c09uKGV2ZW50TmFtZSwgY2FsbGJhY2spIHtcbiAgICBFdmVudHNPbk11bHRpcGxlKGV2ZW50TmFtZSwgY2FsbGJhY2ssIC0xKTtcbn1cblxuLyoqXG4gKiBSZWdpc3RlcnMgYW4gZXZlbnQgbGlzdGVuZXIgdGhhdCB3aWxsIGJlIGludm9rZWQgb25jZSB0aGVuIGRlc3Ryb3llZFxuICpcbiAqIEBleHBvcnRcbiAqIEBwYXJhbSB7c3RyaW5nfSBldmVudE5hbWVcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGNhbGxiYWNrXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBFdmVudHNPbmNlKGV2ZW50TmFtZSwgY2FsbGJhY2spIHtcbiAgICBFdmVudHNPbk11bHRpcGxlKGV2ZW50TmFtZSwgY2FsbGJhY2ssIDEpO1xufVxuXG5mdW5jdGlvbiBub3RpZnlMaXN0ZW5lcnMoZXZlbnREYXRhKSB7XG5cbiAgICAvLyBHZXQgdGhlIGV2ZW50IG5hbWVcbiAgICBsZXQgZXZlbnROYW1lID0gZXZlbnREYXRhLm5hbWU7XG5cbiAgICAvLyBDaGVjayBpZiB3ZSBoYXZlIGFueSBsaXN0ZW5lcnMgZm9yIHRoaXMgZXZlbnRcbiAgICBpZiAoZXZlbnRMaXN0ZW5lcnNbZXZlbnROYW1lXSkge1xuXG4gICAgICAgIC8vIEtlZXAgYSBsaXN0IG9mIGxpc3RlbmVyIGluZGV4ZXMgdG8gZGVzdHJveVxuICAgICAgICBjb25zdCBuZXdFdmVudExpc3RlbmVyTGlzdCA9IGV2ZW50TGlzdGVuZXJzW2V2ZW50TmFtZV0uc2xpY2UoKTtcblxuICAgICAgICAvLyBJdGVyYXRlIGxpc3RlbmVyc1xuICAgICAgICBmb3IgKGxldCBjb3VudCA9IDA7IGNvdW50IDwgZXZlbnRMaXN0ZW5lcnNbZXZlbnROYW1lXS5sZW5ndGg7IGNvdW50ICs9IDEpIHtcblxuICAgICAgICAgICAgLy8gR2V0IG5leHQgbGlzdGVuZXJcbiAgICAgICAgICAgIGNvbnN0IGxpc3RlbmVyID0gZXZlbnRMaXN0ZW5lcnNbZXZlbnROYW1lXVtjb3VudF07XG5cbiAgICAgICAgICAgIGxldCBkYXRhID0gZXZlbnREYXRhLmRhdGE7XG5cbiAgICAgICAgICAgIC8vIERvIHRoZSBjYWxsYmFja1xuICAgICAgICAgICAgY29uc3QgZGVzdHJveSA9IGxpc3RlbmVyLkNhbGxiYWNrKGRhdGEpO1xuICAgICAgICAgICAgaWYgKGRlc3Ryb3kpIHtcbiAgICAgICAgICAgICAgICAvLyBpZiB0aGUgbGlzdGVuZXIgaW5kaWNhdGVkIHRvIGRlc3Ryb3kgaXRzZWxmLCBhZGQgaXQgdG8gdGhlIGRlc3Ryb3kgbGlzdFxuICAgICAgICAgICAgICAgIG5ld0V2ZW50TGlzdGVuZXJMaXN0LnNwbGljZShjb3VudCwgMSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBVcGRhdGUgY2FsbGJhY2tzIHdpdGggbmV3IGxpc3Qgb2YgbGlzdGVuZXJzXG4gICAgICAgIGV2ZW50TGlzdGVuZXJzW2V2ZW50TmFtZV0gPSBuZXdFdmVudExpc3RlbmVyTGlzdDtcbiAgICB9XG59XG5cbi8qKlxuICogTm90aWZ5IGluZm9ybXMgZnJvbnRlbmQgbGlzdGVuZXJzIHRoYXQgYW4gZXZlbnQgd2FzIGVtaXR0ZWQgd2l0aCB0aGUgZ2l2ZW4gZGF0YVxuICpcbiAqIEBleHBvcnRcbiAqIEBwYXJhbSB7c3RyaW5nfSBub3RpZnlNZXNzYWdlIC0gZW5jb2RlZCBub3RpZmljYXRpb24gbWVzc2FnZVxuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBFdmVudHNOb3RpZnkobm90aWZ5TWVzc2FnZSkge1xuICAgIC8vIFBhcnNlIHRoZSBtZXNzYWdlXG4gICAgbGV0IG1lc3NhZ2U7XG4gICAgdHJ5IHtcbiAgICAgICAgbWVzc2FnZSA9IEpTT04ucGFyc2Uobm90aWZ5TWVzc2FnZSk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBjb25zdCBlcnJvciA9ICdJbnZhbGlkIEpTT04gcGFzc2VkIHRvIE5vdGlmeTogJyArIG5vdGlmeU1lc3NhZ2U7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihlcnJvcik7XG4gICAgfVxuICAgIG5vdGlmeUxpc3RlbmVycyhtZXNzYWdlKTtcbn1cblxuLyoqXG4gKiBFbWl0IGFuIGV2ZW50IHdpdGggdGhlIGdpdmVuIG5hbWUgYW5kIGRhdGFcbiAqXG4gKiBAZXhwb3J0XG4gKiBAcGFyYW0ge3N0cmluZ30gZXZlbnROYW1lXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBFdmVudHNFbWl0KGV2ZW50TmFtZSkge1xuXG4gICAgY29uc3QgcGF5bG9hZCA9IHtcbiAgICAgICAgbmFtZTogZXZlbnROYW1lLFxuICAgICAgICBkYXRhOiBbXS5zbGljZS5hcHBseShhcmd1bWVudHMpLnNsaWNlKDEpLFxuICAgIH07XG5cbiAgICAvLyBOb3RpZnkgSlMgbGlzdGVuZXJzXG4gICAgbm90aWZ5TGlzdGVuZXJzKHBheWxvYWQpO1xuXG4gICAgLy8gTm90aWZ5IEdvIGxpc3RlbmVyc1xuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnRUUnICsgSlNPTi5zdHJpbmdpZnkocGF5bG9hZCkpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gRXZlbnRzT2ZmKGV2ZW50TmFtZSkge1xuICAgIC8vIFJlbW92ZSBsb2NhbCBsaXN0ZW5lcnNcbiAgICBldmVudExpc3RlbmVycy5kZWxldGUoZXZlbnROYW1lKTtcblxuICAgIC8vIE5vdGlmeSBHbyBsaXN0ZW5lcnNcbiAgICB3aW5kb3cuV2FpbHNJbnZva2UoJ0VYJyArIGV2ZW50TmFtZSk7XG59IiwgIi8qXG4gXyAgICAgICBfXyAgICAgIF8gX19cbnwgfCAgICAgLyAvX19fIF8oXykgL19fX19cbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxufF9fL3xfXy9cXF9fLF8vXy9fL19fX18vXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XG4qL1xuLyoganNoaW50IGVzdmVyc2lvbjogNiAqL1xuXG5leHBvcnQgY29uc3QgY2FsbGJhY2tzID0ge307XG5cbi8qKlxuICogUmV0dXJucyBhIG51bWJlciBmcm9tIHRoZSBuYXRpdmUgYnJvd3NlciByYW5kb20gZnVuY3Rpb25cbiAqXG4gKiBAcmV0dXJucyBudW1iZXJcbiAqL1xuZnVuY3Rpb24gY3J5cHRvUmFuZG9tKCkge1xuXHR2YXIgYXJyYXkgPSBuZXcgVWludDMyQXJyYXkoMSk7XG5cdHJldHVybiB3aW5kb3cuY3J5cHRvLmdldFJhbmRvbVZhbHVlcyhhcnJheSlbMF07XG59XG5cbi8qKlxuICogUmV0dXJucyBhIG51bWJlciB1c2luZyBkYSBvbGQtc2tvb2wgTWF0aC5SYW5kb21cbiAqIEkgbGlrZXMgdG8gY2FsbCBpdCBMT0xSYW5kb21cbiAqXG4gKiBAcmV0dXJucyBudW1iZXJcbiAqL1xuZnVuY3Rpb24gYmFzaWNSYW5kb20oKSB7XG5cdHJldHVybiBNYXRoLnJhbmRvbSgpICogOTAwNzE5OTI1NDc0MDk5MTtcbn1cblxuLy8gUGljayBhIHJhbmRvbSBudW1iZXIgZnVuY3Rpb24gYmFzZWQgb24gYnJvd3NlciBjYXBhYmlsaXR5XG52YXIgcmFuZG9tRnVuYztcbmlmICh3aW5kb3cuY3J5cHRvKSB7XG5cdHJhbmRvbUZ1bmMgPSBjcnlwdG9SYW5kb207XG59IGVsc2Uge1xuXHRyYW5kb21GdW5jID0gYmFzaWNSYW5kb207XG59XG5cblxuLyoqXG4gKiBDYWxsIHNlbmRzIGEgbWVzc2FnZSB0byB0aGUgYmFja2VuZCB0byBjYWxsIHRoZSBiaW5kaW5nIHdpdGggdGhlXG4gKiBnaXZlbiBkYXRhLiBBIHByb21pc2UgaXMgcmV0dXJuZWQgYW5kIHdpbGwgYmUgY29tcGxldGVkIHdoZW4gdGhlXG4gKiBiYWNrZW5kIHJlc3BvbmRzLiBUaGlzIHdpbGwgYmUgcmVzb2x2ZWQgd2hlbiB0aGUgY2FsbCB3YXMgc3VjY2Vzc2Z1bFxuICogb3IgcmVqZWN0ZWQgaWYgYW4gZXJyb3IgaXMgcGFzc2VkIGJhY2suXG4gKiBUaGVyZSBpcyBhIHRpbWVvdXQgbWVjaGFuaXNtLiBJZiB0aGUgY2FsbCBkb2Vzbid0IHJlc3BvbmQgaW4gdGhlIGdpdmVuXG4gKiB0aW1lIChpbiBtaWxsaXNlY29uZHMpIHRoZW4gdGhlIHByb21pc2UgaXMgcmVqZWN0ZWQuXG4gKlxuICogQGV4cG9ydFxuICogQHBhcmFtIHtzdHJpbmd9IG5hbWVcbiAqIEBwYXJhbSB7YW55PX0gYXJnc1xuICogQHBhcmFtIHtudW1iZXI9fSB0aW1lb3V0XG4gKiBAcmV0dXJuc1xuICovXG5leHBvcnQgZnVuY3Rpb24gQ2FsbChuYW1lLCBhcmdzLCB0aW1lb3V0KSB7XG5cblx0Ly8gVGltZW91dCBpbmZpbml0ZSBieSBkZWZhdWx0XG5cdGlmICh0aW1lb3V0ID09IG51bGwpIHtcblx0XHR0aW1lb3V0ID0gMDtcblx0fVxuXG5cdC8vIENyZWF0ZSBhIHByb21pc2Vcblx0cmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHtcblxuXHRcdC8vIENyZWF0ZSBhIHVuaXF1ZSBjYWxsYmFja0lEXG5cdFx0dmFyIGNhbGxiYWNrSUQ7XG5cdFx0ZG8ge1xuXHRcdFx0Y2FsbGJhY2tJRCA9IG5hbWUgKyAnLScgKyByYW5kb21GdW5jKCk7XG5cdFx0fSB3aGlsZSAoY2FsbGJhY2tzW2NhbGxiYWNrSURdKTtcblxuXHRcdHZhciB0aW1lb3V0SGFuZGxlO1xuXHRcdC8vIFNldCB0aW1lb3V0XG5cdFx0aWYgKHRpbWVvdXQgPiAwKSB7XG5cdFx0XHR0aW1lb3V0SGFuZGxlID0gc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG5cdFx0XHRcdHJlamVjdChFcnJvcignQ2FsbCB0byAnICsgbmFtZSArICcgdGltZWQgb3V0LiBSZXF1ZXN0IElEOiAnICsgY2FsbGJhY2tJRCkpO1xuXHRcdFx0fSwgdGltZW91dCk7XG5cdFx0fVxuXG5cdFx0Ly8gU3RvcmUgY2FsbGJhY2tcblx0XHRjYWxsYmFja3NbY2FsbGJhY2tJRF0gPSB7XG5cdFx0XHR0aW1lb3V0SGFuZGxlOiB0aW1lb3V0SGFuZGxlLFxuXHRcdFx0cmVqZWN0OiByZWplY3QsXG5cdFx0XHRyZXNvbHZlOiByZXNvbHZlXG5cdFx0fTtcblxuXHRcdHRyeSB7XG5cdFx0XHRjb25zdCBwYXlsb2FkID0ge1xuXHRcdFx0XHRuYW1lLFxuXHRcdFx0XHRhcmdzLFxuXHRcdFx0XHRjYWxsYmFja0lELFxuXHRcdFx0fTtcblxuXHRcdFx0Ly8gTWFrZSB0aGUgY2FsbFxuXHRcdFx0d2luZG93LldhaWxzSW52b2tlKCdDJyArIEpTT04uc3RyaW5naWZ5KHBheWxvYWQpKTtcblx0XHR9IGNhdGNoIChlKSB7XG5cdFx0XHQvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmVcblx0XHRcdGNvbnNvbGUuZXJyb3IoZSk7XG5cdFx0fVxuXHR9KTtcbn1cblxuXG5cbi8qKlxuICogQ2FsbGVkIGJ5IHRoZSBiYWNrZW5kIHRvIHJldHVybiBkYXRhIHRvIGEgcHJldmlvdXNseSBjYWxsZWRcbiAqIGJpbmRpbmcgaW52b2NhdGlvblxuICpcbiAqIEBleHBvcnRcbiAqIEBwYXJhbSB7c3RyaW5nfSBpbmNvbWluZ01lc3NhZ2VcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIENhbGxiYWNrKGluY29taW5nTWVzc2FnZSkge1xuXHQvLyBEZWNvZGUgdGhlIG1lc3NhZ2UgLSBDcmVkaXQ6IGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vYS8xMzg2NTY4MFxuXHQvL2luY29taW5nTWVzc2FnZSA9IGRlY29kZVVSSUNvbXBvbmVudChpbmNvbWluZ01lc3NhZ2UucmVwbGFjZSgvXFxzKy9nLCAnJykucmVwbGFjZSgvWzAtOWEtZl17Mn0vZywgJyUkJicpKTtcblxuXHQvLyBQYXJzZSB0aGUgbWVzc2FnZVxuXHR2YXIgbWVzc2FnZTtcblx0dHJ5IHtcblx0XHRtZXNzYWdlID0gSlNPTi5wYXJzZShpbmNvbWluZ01lc3NhZ2UpO1xuXHR9IGNhdGNoIChlKSB7XG5cdFx0Y29uc3QgZXJyb3IgPSBgSW52YWxpZCBKU09OIHBhc3NlZCB0byBjYWxsYmFjazogJHtlLm1lc3NhZ2V9LiBNZXNzYWdlOiAke2luY29taW5nTWVzc2FnZX1gO1xuXHRcdHdhaWxzLkxvZ0RlYnVnKGVycm9yKTtcblx0XHR0aHJvdyBuZXcgRXJyb3IoZXJyb3IpO1xuXHR9XG5cdHZhciBjYWxsYmFja0lEID0gbWVzc2FnZS5jYWxsYmFja2lkO1xuXHR2YXIgY2FsbGJhY2tEYXRhID0gY2FsbGJhY2tzW2NhbGxiYWNrSURdO1xuXHRpZiAoIWNhbGxiYWNrRGF0YSkge1xuXHRcdGNvbnN0IGVycm9yID0gYENhbGxiYWNrICcke2NhbGxiYWNrSUR9JyBub3QgcmVnaXN0ZXJlZCEhIWA7XG5cdFx0Y29uc29sZS5lcnJvcihlcnJvcik7IC8vIGVzbGludC1kaXNhYmxlLWxpbmVcblx0XHR0aHJvdyBuZXcgRXJyb3IoZXJyb3IpO1xuXHR9XG5cdGNsZWFyVGltZW91dChjYWxsYmFja0RhdGEudGltZW91dEhhbmRsZSk7XG5cblx0ZGVsZXRlIGNhbGxiYWNrc1tjYWxsYmFja0lEXTtcblxuXHRpZiAobWVzc2FnZS5lcnJvcikge1xuXHRcdGNhbGxiYWNrRGF0YS5yZWplY3QobWVzc2FnZS5lcnJvcik7XG5cdH0gZWxzZSB7XG5cdFx0Y2FsbGJhY2tEYXRhLnJlc29sdmUobWVzc2FnZS5yZXN1bHQpO1xuXHR9XG59XG4iLCAiLypcbiBfICAgICAgIF9fICAgICAgXyBfXyAgICBcbnwgfCAgICAgLyAvX19fIF8oXykgL19fX19cbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKSBcbnxfXy98X18vXFxfXyxfL18vXy9fX19fLyAgXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XG4qL1xuLyoganNoaW50IGVzdmVyc2lvbjogNiAqL1xuXG5pbXBvcnQge0NhbGx9IGZyb20gJy4vY2FsbHMnO1xuXG4vLyBUaGlzIGlzIHdoZXJlIHdlIGJpbmQgZ28gbWV0aG9kIHdyYXBwZXJzXG53aW5kb3cuZ28gPSB7fTtcblxuZXhwb3J0IGZ1bmN0aW9uIFNldEJpbmRpbmdzKGJpbmRpbmdzTWFwKSB7XG5cdHRyeSB7XG5cdFx0YmluZGluZ3NNYXAgPSBKU09OLnBhcnNlKGJpbmRpbmdzTWFwKTtcblx0fSBjYXRjaCAoZSkge1xuXHRcdGNvbnNvbGUuZXJyb3IoZSk7XG5cdH1cblxuXHQvLyBJbml0aWFsaXNlIHRoZSBiaW5kaW5ncyBtYXBcblx0d2luZG93LmdvID0gd2luZG93LmdvIHx8IHt9O1xuXG5cdC8vIEl0ZXJhdGUgcGFja2FnZSBuYW1lc1xuXHRPYmplY3Qua2V5cyhiaW5kaW5nc01hcCkuZm9yRWFjaCgocGFja2FnZU5hbWUpID0+IHtcblxuXHRcdC8vIENyZWF0ZSBpbm5lciBtYXAgaWYgaXQgZG9lc24ndCBleGlzdFxuXHRcdHdpbmRvdy5nb1twYWNrYWdlTmFtZV0gPSB3aW5kb3cuZ29bcGFja2FnZU5hbWVdIHx8IHt9O1xuXG5cdFx0Ly8gSXRlcmF0ZSBzdHJ1Y3QgbmFtZXNcblx0XHRPYmplY3Qua2V5cyhiaW5kaW5nc01hcFtwYWNrYWdlTmFtZV0pLmZvckVhY2goKHN0cnVjdE5hbWUpID0+IHtcblxuXHRcdFx0Ly8gQ3JlYXRlIGlubmVyIG1hcCBpZiBpdCBkb2Vzbid0IGV4aXN0XG5cdFx0XHR3aW5kb3cuZ29bcGFja2FnZU5hbWVdW3N0cnVjdE5hbWVdID0gd2luZG93LmdvW3BhY2thZ2VOYW1lXVtzdHJ1Y3ROYW1lXSB8fCB7fTtcblxuXHRcdFx0T2JqZWN0LmtleXMoYmluZGluZ3NNYXBbcGFja2FnZU5hbWVdW3N0cnVjdE5hbWVdKS5mb3JFYWNoKChtZXRob2ROYW1lKSA9PiB7XG5cblx0XHRcdFx0d2luZG93LmdvW3BhY2thZ2VOYW1lXVtzdHJ1Y3ROYW1lXVttZXRob2ROYW1lXSA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0XHRcdC8vIE5vIHRpbWVvdXQgYnkgZGVmYXVsdFxuXHRcdFx0XHRcdGxldCB0aW1lb3V0ID0gMDtcblxuXHRcdFx0XHRcdC8vIEFjdHVhbCBmdW5jdGlvblxuXHRcdFx0XHRcdGZ1bmN0aW9uIGR5bmFtaWMoKSB7XG5cdFx0XHRcdFx0XHRjb25zdCBhcmdzID0gW10uc2xpY2UuY2FsbChhcmd1bWVudHMpO1xuXHRcdFx0XHRcdFx0cmV0dXJuIENhbGwoW3BhY2thZ2VOYW1lLCBzdHJ1Y3ROYW1lLCBtZXRob2ROYW1lXS5qb2luKCcuJyksIGFyZ3MsIHRpbWVvdXQpO1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdC8vIEFsbG93IHNldHRpbmcgdGltZW91dCB0byBmdW5jdGlvblxuXHRcdFx0XHRcdGR5bmFtaWMuc2V0VGltZW91dCA9IGZ1bmN0aW9uIChuZXdUaW1lb3V0KSB7XG5cdFx0XHRcdFx0XHR0aW1lb3V0ID0gbmV3VGltZW91dDtcblx0XHRcdFx0XHR9O1xuXG5cdFx0XHRcdFx0Ly8gQWxsb3cgZ2V0dGluZyB0aW1lb3V0IHRvIGZ1bmN0aW9uXG5cdFx0XHRcdFx0ZHluYW1pYy5nZXRUaW1lb3V0ID0gZnVuY3Rpb24gKCkge1xuXHRcdFx0XHRcdFx0cmV0dXJuIHRpbWVvdXQ7XG5cdFx0XHRcdFx0fTtcblxuXHRcdFx0XHRcdHJldHVybiBkeW5hbWljO1xuXHRcdFx0XHR9KCk7XG5cdFx0XHR9KTtcblx0XHR9KTtcblx0fSk7XG59XG4iLCAiLypcbiBfXHQgICBfX1x0ICBfIF9fXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcbiovXG5cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cblxuXG5pbXBvcnQge0NhbGx9IGZyb20gXCIuL2NhbGxzXCI7XG5cbmV4cG9ydCBmdW5jdGlvbiBXaW5kb3dSZWxvYWQoKSB7XG4gICAgd2luZG93LmxvY2F0aW9uLnJlbG9hZCgpO1xufVxuXG4vKipcbiAqIFBsYWNlIHRoZSB3aW5kb3cgaW4gdGhlIGNlbnRlciBvZiB0aGUgc2NyZWVuXG4gKlxuICogQGV4cG9ydFxuICovXG5leHBvcnQgZnVuY3Rpb24gV2luZG93Q2VudGVyKCkge1xuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV2MnKTtcbn1cblxuLyoqXG4gKiBTZXRzIHRoZSB3aW5kb3cgdGl0bGVcbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gdGl0bGVcbiAqIEBleHBvcnRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd1NldFRpdGxlKHRpdGxlKSB7XG4gICAgd2luZG93LldhaWxzSW52b2tlKCdXVCcgKyB0aXRsZSk7XG59XG5cbi8qKlxuICogTWFrZXMgdGhlIHdpbmRvdyBnbyBmdWxsc2NyZWVuXG4gKlxuICogQGV4cG9ydFxuICovXG5leHBvcnQgZnVuY3Rpb24gV2luZG93RnVsbHNjcmVlbigpIHtcbiAgICB3aW5kb3cuV2FpbHNJbnZva2UoJ1dGJyk7XG59XG5cbi8qKlxuICogUmV2ZXJ0cyB0aGUgd2luZG93IGZyb20gZnVsbHNjcmVlblxuICpcbiAqIEBleHBvcnRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd1VuRnVsbHNjcmVlbigpIHtcbiAgICB3aW5kb3cuV2FpbHNJbnZva2UoJ1dmJyk7XG59XG5cbi8qKlxuICogU2V0IHRoZSBTaXplIG9mIHRoZSB3aW5kb3dcbiAqXG4gKiBAZXhwb3J0XG4gKiBAcGFyYW0ge251bWJlcn0gd2lkdGhcbiAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd1NldFNpemUod2lkdGgsIGhlaWdodCkge1xuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV3M6JyArIHdpZHRoICsgJzonICsgaGVpZ2h0KTtcbn1cblxuLyoqXG4gKiBHZXQgdGhlIFNpemUgb2YgdGhlIHdpbmRvd1xuICpcbiAqIEBleHBvcnRcbiAqIEByZXR1cm4ge1Byb21pc2U8e3c6IG51bWJlciwgaDogbnVtYmVyfT59IFRoZSBzaXplIG9mIHRoZSB3aW5kb3dcblxuICovXG5leHBvcnQgZnVuY3Rpb24gV2luZG93R2V0U2l6ZSgpIHtcbiAgICByZXR1cm4gQ2FsbChcIjp3YWlsczpXaW5kb3dHZXRTaXplXCIpO1xufVxuXG4vKipcbiAqIFNldCB0aGUgbWF4aW11bSBzaXplIG9mIHRoZSB3aW5kb3dcbiAqXG4gKiBAZXhwb3J0XG4gKiBAcGFyYW0ge251bWJlcn0gd2lkdGhcbiAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd1NldE1heFNpemUod2lkdGgsIGhlaWdodCkge1xuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV1o6JyArIHdpZHRoICsgJzonICsgaGVpZ2h0KTtcbn1cblxuLyoqXG4gKiBTZXQgdGhlIG1pbmltdW0gc2l6ZSBvZiB0aGUgd2luZG93XG4gKlxuICogQGV4cG9ydFxuICogQHBhcmFtIHtudW1iZXJ9IHdpZHRoXG4gKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBXaW5kb3dTZXRNaW5TaXplKHdpZHRoLCBoZWlnaHQpIHtcbiAgICB3aW5kb3cuV2FpbHNJbnZva2UoJ1d6OicgKyB3aWR0aCArICc6JyArIGhlaWdodCk7XG59XG5cbi8qKlxuICogU2V0IHRoZSBQb3NpdGlvbiBvZiB0aGUgd2luZG93XG4gKlxuICogQGV4cG9ydFxuICogQHBhcmFtIHtudW1iZXJ9IHhcbiAqIEBwYXJhbSB7bnVtYmVyfSB5XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBXaW5kb3dTZXRQb3NpdGlvbih4LCB5KSB7XG4gICAgd2luZG93LldhaWxzSW52b2tlKCdXcDonICsgeCArICc6JyArIHkpO1xufVxuXG4vKipcbiAqIEdldCB0aGUgUG9zaXRpb24gb2YgdGhlIHdpbmRvd1xuICpcbiAqIEBleHBvcnRcbiAqIEByZXR1cm4ge1Byb21pc2U8e3g6IG51bWJlciwgeTogbnVtYmVyfT59IFRoZSBwb3NpdGlvbiBvZiB0aGUgd2luZG93XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBXaW5kb3dHZXRQb3NpdGlvbigpIHtcbiAgICByZXR1cm4gQ2FsbChcIjp3YWlsczpXaW5kb3dHZXRQb3NcIik7XG59XG5cbi8qKlxuICogSGlkZSB0aGUgV2luZG93XG4gKlxuICogQGV4cG9ydFxuICovXG5leHBvcnQgZnVuY3Rpb24gV2luZG93SGlkZSgpIHtcbiAgICB3aW5kb3cuV2FpbHNJbnZva2UoJ1dIJyk7XG59XG5cbi8qKlxuICogU2hvdyB0aGUgV2luZG93XG4gKlxuICogQGV4cG9ydFxuICovXG5leHBvcnQgZnVuY3Rpb24gV2luZG93U2hvdygpIHtcbiAgICB3aW5kb3cuV2FpbHNJbnZva2UoJ1dTJyk7XG59XG5cbi8qKlxuICogTWF4aW1pc2UgdGhlIFdpbmRvd1xuICpcbiAqIEBleHBvcnRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd01heGltaXNlKCkge1xuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV00nKTtcbn1cblxuLyoqXG4gKiBVbm1heGltaXNlIHRoZSBXaW5kb3dcbiAqXG4gKiBAZXhwb3J0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBXaW5kb3dVbm1heGltaXNlKCkge1xuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV1UnKTtcbn1cblxuLyoqXG4gKiBNaW5pbWlzZSB0aGUgV2luZG93XG4gKlxuICogQGV4cG9ydFxuICovXG5leHBvcnQgZnVuY3Rpb24gV2luZG93TWluaW1pc2UoKSB7XG4gICAgd2luZG93LldhaWxzSW52b2tlKCdXbScpO1xufVxuXG4vKipcbiAqIFVubWluaW1pc2UgdGhlIFdpbmRvd1xuICpcbiAqIEBleHBvcnRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd1VubWluaW1pc2UoKSB7XG4gICAgd2luZG93LldhaWxzSW52b2tlKCdXdScpO1xufVxuXG5cbi8qKlxuICogU2V0cyB0aGUgYmFja2dyb3VuZCBjb2xvdXIgb2YgdGhlIHdpbmRvd1xuICpcbiAqIEBleHBvcnRcbiAqIEBwYXJhbSB7UkdCQX0gUkdCQSBiYWNrZ3JvdW5kIGNvbG91clxuICovXG5leHBvcnQgZnVuY3Rpb24gV2luZG93U2V0UkdCQShSR0JBKSB7XG4gICAgbGV0IHJnYmEgPSBKU09OLnN0cmluZ2lmeShSR0JBKTtcbiAgICB3aW5kb3cuV2FpbHNJbnZva2UoJ1dyOicgKyByZ2JhKTtcbn1cblxuIiwgIi8qKlxuICogQGRlc2NyaXB0aW9uOiBVc2UgdGhlIHN5c3RlbSBkZWZhdWx0IGJyb3dzZXIgdG8gb3BlbiB0aGUgdXJsXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIFxuICogQHJldHVybiB7dm9pZH1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIEJyb3dzZXJPcGVuVVJMKHVybCkge1xuICB3aW5kb3cuV2FpbHNJbnZva2UoJ0JPOicgKyB1cmwpO1xufSIsICIvKlxuIF9cdCAgIF9fXHQgIF8gX19cbnwgfFx0IC8gL19fXyBfKF8pIC9fX19fXG58IHwgL3wgLyAvIF9fIGAvIC8gLyBfX18vXG58IHwvIHwvIC8gL18vIC8gLyAoX18gIClcbnxfXy98X18vXFxfXyxfL18vXy9fX19fL1xuVGhlIGVsZWN0cm9uIGFsdGVybmF0aXZlIGZvciBHb1xuKGMpIExlYSBBbnRob255IDIwMTktcHJlc2VudFxuKi9cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cbmltcG9ydCAqIGFzIExvZyBmcm9tICcuL2xvZyc7XG5pbXBvcnQge2V2ZW50TGlzdGVuZXJzLCBFdmVudHNFbWl0LCBFdmVudHNOb3RpZnksIEV2ZW50c09mZiwgRXZlbnRzT24sIEV2ZW50c09uY2UsIEV2ZW50c09uTXVsdGlwbGV9IGZyb20gJy4vZXZlbnRzJztcbmltcG9ydCB7Q2FsbGJhY2ssIGNhbGxiYWNrc30gZnJvbSAnLi9jYWxscyc7XG5pbXBvcnQge1NldEJpbmRpbmdzfSBmcm9tIFwiLi9iaW5kaW5nc1wiO1xuaW1wb3J0ICogYXMgV2luZG93IGZyb20gXCIuL3dpbmRvd1wiO1xuaW1wb3J0ICogYXMgQnJvd3NlciBmcm9tIFwiLi9icm93c2VyXCI7XG5cblxuZXhwb3J0IGZ1bmN0aW9uIFF1aXQoKSB7XG4gICAgd2luZG93LldhaWxzSW52b2tlKCdRJyk7XG59XG5cbi8vIFRoZSBKUyBydW50aW1lXG53aW5kb3cucnVudGltZSA9IHtcbiAgICAuLi5Mb2csXG4gICAgLi4uV2luZG93LFxuICAgIC4uLkJyb3dzZXIsXG4gICAgRXZlbnRzT24sXG4gICAgRXZlbnRzT25jZSxcbiAgICBFdmVudHNPbk11bHRpcGxlLFxuICAgIEV2ZW50c0VtaXQsXG4gICAgRXZlbnRzT2ZmLFxuICAgIFF1aXRcbn07XG5cbi8vIEludGVybmFsIHdhaWxzIGVuZHBvaW50c1xud2luZG93LndhaWxzID0ge1xuICAgIENhbGxiYWNrLFxuICAgIEV2ZW50c05vdGlmeSxcbiAgICBTZXRCaW5kaW5ncyxcbiAgICBldmVudExpc3RlbmVycyxcbiAgICBjYWxsYmFja3MsXG4gICAgZmxhZ3M6IHtcbiAgICAgICAgZGlzYWJsZVNjcm9sbGJhckRyYWc6IGZhbHNlLFxuICAgICAgICBkaXNhYmxlV2FpbHNEZWZhdWx0Q29udGV4dE1lbnU6IGZhbHNlLFxuICAgIH1cbn07XG5cbi8vIFNldCB0aGUgYmluZGluZ3NcbndpbmRvdy53YWlscy5TZXRCaW5kaW5ncyh3aW5kb3cud2FpbHNiaW5kaW5ncyk7XG5kZWxldGUgd2luZG93LndhaWxzLlNldEJpbmRpbmdzO1xuXG4vLyBUaGlzIGlzIGV2YWx1YXRlZCBhdCBidWlsZCB0aW1lIGluIHBhY2thZ2UuanNvblxuLy8gY29uc3QgZGV2ID0gMDtcbi8vIGNvbnN0IHByb2R1Y3Rpb24gPSAxO1xuaWYgKEVOViA9PT0gMCkge1xuICAgIGRlbGV0ZSB3aW5kb3cud2FpbHNiaW5kaW5ncztcbn1cblxuLy8gU2V0dXAgZHJhZyBoYW5kbGVyXG4vLyBCYXNlZCBvbiBjb2RlIGZyb206IGh0dHBzOi8vZ2l0aHViLmNvbS9wYXRyMG51cy9EZXNrR2FwXG53aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignbW91c2Vkb3duJywgKGUpID0+IHtcbiAgICBsZXQgY3VycmVudEVsZW1lbnQgPSBlLnRhcmdldDtcbiAgICB3aGlsZSAoY3VycmVudEVsZW1lbnQgIT0gbnVsbCkge1xuICAgICAgICBpZiAoY3VycmVudEVsZW1lbnQuaGFzQXR0cmlidXRlKCdkYXRhLXdhaWxzLW5vLWRyYWcnKSkge1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH0gZWxzZSBpZiAoY3VycmVudEVsZW1lbnQuaGFzQXR0cmlidXRlKCdkYXRhLXdhaWxzLWRyYWcnKSkge1xuICAgICAgICAgICAgaWYgKHdpbmRvdy53YWlscy5mbGFncy5kaXNhYmxlU2Nyb2xsYmFyRHJhZykge1xuICAgICAgICAgICAgICAgIC8vIFRoaXMgY2hlY2tzIGZvciBjbGlja3Mgb24gdGhlIHNjcm9sbCBiYXJcbiAgICAgICAgICAgICAgICBpZiAoZS5vZmZzZXRYID4gZS50YXJnZXQuY2xpZW50V2lkdGggfHwgZS5vZmZzZXRZID4gZS50YXJnZXQuY2xpZW50SGVpZ2h0KSB7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHdpbmRvdy5XYWlsc0ludm9rZShcImRyYWdcIik7XG4gICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgICBjdXJyZW50RWxlbWVudCA9IGN1cnJlbnRFbGVtZW50LnBhcmVudEVsZW1lbnQ7XG4gICAgfVxufSk7XG5cbi8vIFNldHVwIGNvbnRleHQgbWVudSBob29rXG53aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignY29udGV4dG1lbnUnLCBmdW5jdGlvbiAoZSkge1xuICAgIGlmICh3aW5kb3cud2FpbHMuZmxhZ3MuZGlzYWJsZVdhaWxzRGVmYXVsdENvbnRleHRNZW51KSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICB9XG59KTsiXSwKICAibWFwcGluZ3MiOiAiOzs7Ozs7Ozs7O0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBa0JBLDBCQUF3QixPQUFPLFNBQVM7QUFJdkMsV0FBTyxZQUFZLE1BQU0sUUFBUTtBQUFBO0FBUzNCLG9CQUFrQixTQUFTO0FBQ2pDLG1CQUFlLEtBQUs7QUFBQTtBQVNkLG9CQUFrQixTQUFTO0FBQ2pDLG1CQUFlLEtBQUs7QUFBQTtBQVNkLG9CQUFrQixTQUFTO0FBQ2pDLG1CQUFlLEtBQUs7QUFBQTtBQVNkLG1CQUFpQixTQUFTO0FBQ2hDLG1CQUFlLEtBQUs7QUFBQTtBQVNkLHNCQUFvQixTQUFTO0FBQ25DLG1CQUFlLEtBQUs7QUFBQTtBQVNkLG9CQUFrQixTQUFTO0FBQ2pDLG1CQUFlLEtBQUs7QUFBQTtBQVNkLG9CQUFrQixTQUFTO0FBQ2pDLG1CQUFlLEtBQUs7QUFBQTtBQVNkLHVCQUFxQixVQUFVO0FBQ3JDLG1CQUFlLEtBQUs7QUFBQTtBQUlkLE1BQU0sV0FBVztBQUFBLElBQ3ZCLE9BQU87QUFBQSxJQUNQLE9BQU87QUFBQSxJQUNQLE1BQU07QUFBQSxJQUNOLFNBQVM7QUFBQSxJQUNULE9BQU87QUFBQTs7O0FDN0ZSLHVCQUFlO0FBQUEsSUFPWCxZQUFZLFVBQVUsY0FBYztBQUVoQyxxQkFBZSxnQkFBZ0I7QUFHL0IsV0FBSyxXQUFXLENBQUMsU0FBUztBQUN0QixpQkFBUyxNQUFNLE1BQU07QUFFckIsWUFBSSxpQkFBaUIsSUFBSTtBQUNyQixpQkFBTztBQUFBO0FBR1gsd0JBQWdCO0FBQ2hCLGVBQU8saUJBQWlCO0FBQUE7QUFBQTtBQUFBO0FBSzdCLE1BQU0saUJBQWlCO0FBVXZCLDRCQUEwQixXQUFXLFVBQVUsY0FBYztBQUNoRSxtQkFBZSxhQUFhLGVBQWUsY0FBYztBQUN6RCxVQUFNLGVBQWUsSUFBSSxTQUFTLFVBQVU7QUFDNUMsbUJBQWUsV0FBVyxLQUFLO0FBQUE7QUFVNUIsb0JBQWtCLFdBQVcsVUFBVTtBQUMxQyxxQkFBaUIsV0FBVyxVQUFVO0FBQUE7QUFVbkMsc0JBQW9CLFdBQVcsVUFBVTtBQUM1QyxxQkFBaUIsV0FBVyxVQUFVO0FBQUE7QUFHMUMsMkJBQXlCLFdBQVc7QUFHaEMsUUFBSSxZQUFZLFVBQVU7QUFHMUIsUUFBSSxlQUFlLFlBQVk7QUFHM0IsWUFBTSx1QkFBdUIsZUFBZSxXQUFXO0FBR3ZELGVBQVMsUUFBUSxHQUFHLFFBQVEsZUFBZSxXQUFXLFFBQVEsU0FBUyxHQUFHO0FBR3RFLGNBQU0sV0FBVyxlQUFlLFdBQVc7QUFFM0MsWUFBSSxPQUFPLFVBQVU7QUFHckIsY0FBTSxVQUFVLFNBQVMsU0FBUztBQUNsQyxZQUFJLFNBQVM7QUFFVCwrQkFBcUIsT0FBTyxPQUFPO0FBQUE7QUFBQTtBQUszQyxxQkFBZSxhQUFhO0FBQUE7QUFBQTtBQVc3Qix3QkFBc0IsZUFBZTtBQUV4QyxRQUFJO0FBQ0osUUFBSTtBQUNBLGdCQUFVLEtBQUssTUFBTTtBQUFBLGFBQ2hCLEdBQVA7QUFDRSxZQUFNLFFBQVEsb0NBQW9DO0FBQ2xELFlBQU0sSUFBSSxNQUFNO0FBQUE7QUFFcEIsb0JBQWdCO0FBQUE7QUFTYixzQkFBb0IsV0FBVztBQUVsQyxVQUFNLFVBQVU7QUFBQSxNQUNaLE1BQU07QUFBQSxNQUNOLE1BQU0sR0FBRyxNQUFNLE1BQU0sV0FBVyxNQUFNO0FBQUE7QUFJMUMsb0JBQWdCO0FBR2hCLFdBQU8sWUFBWSxPQUFPLEtBQUssVUFBVTtBQUFBO0FBR3RDLHFCQUFtQixXQUFXO0FBRWpDLG1CQUFlLE9BQU87QUFHdEIsV0FBTyxZQUFZLE9BQU87QUFBQTs7O0FDbEp2QixNQUFNLFlBQVk7QUFPekIsMEJBQXdCO0FBQ3ZCLFFBQUksUUFBUSxJQUFJLFlBQVk7QUFDNUIsV0FBTyxPQUFPLE9BQU8sZ0JBQWdCLE9BQU87QUFBQTtBQVM3Qyx5QkFBdUI7QUFDdEIsV0FBTyxLQUFLLFdBQVc7QUFBQTtBQUl4QixNQUFJO0FBQ0osTUFBSSxPQUFPLFFBQVE7QUFDbEIsaUJBQWE7QUFBQSxTQUNQO0FBQ04saUJBQWE7QUFBQTtBQWtCUCxnQkFBYyxNQUFNLE1BQU0sU0FBUztBQUd6QyxRQUFJLFdBQVcsTUFBTTtBQUNwQixnQkFBVTtBQUFBO0FBSVgsV0FBTyxJQUFJLFFBQVEsU0FBVSxTQUFTLFFBQVE7QUFHN0MsVUFBSTtBQUNKLFNBQUc7QUFDRixxQkFBYSxPQUFPLE1BQU07QUFBQSxlQUNsQixVQUFVO0FBRW5CLFVBQUk7QUFFSixVQUFJLFVBQVUsR0FBRztBQUNoQix3QkFBZ0IsV0FBVyxXQUFZO0FBQ3RDLGlCQUFPLE1BQU0sYUFBYSxPQUFPLDZCQUE2QjtBQUFBLFdBQzVEO0FBQUE7QUFJSixnQkFBVSxjQUFjO0FBQUEsUUFDdkI7QUFBQSxRQUNBO0FBQUEsUUFDQTtBQUFBO0FBR0QsVUFBSTtBQUNILGNBQU0sVUFBVTtBQUFBLFVBQ2Y7QUFBQSxVQUNBO0FBQUEsVUFDQTtBQUFBO0FBSUQsZUFBTyxZQUFZLE1BQU0sS0FBSyxVQUFVO0FBQUEsZUFDaEMsR0FBUDtBQUVELGdCQUFRLE1BQU07QUFBQTtBQUFBO0FBQUE7QUFjVixvQkFBa0IsaUJBQWlCO0FBS3pDLFFBQUk7QUFDSixRQUFJO0FBQ0gsZ0JBQVUsS0FBSyxNQUFNO0FBQUEsYUFDYixHQUFQO0FBQ0QsWUFBTSxRQUFRLG9DQUFvQyxFQUFFLHFCQUFxQjtBQUN6RSxZQUFNLFNBQVM7QUFDZixZQUFNLElBQUksTUFBTTtBQUFBO0FBRWpCLFFBQUksYUFBYSxRQUFRO0FBQ3pCLFFBQUksZUFBZSxVQUFVO0FBQzdCLFFBQUksQ0FBQyxjQUFjO0FBQ2xCLFlBQU0sUUFBUSxhQUFhO0FBQzNCLGNBQVEsTUFBTTtBQUNkLFlBQU0sSUFBSSxNQUFNO0FBQUE7QUFFakIsaUJBQWEsYUFBYTtBQUUxQixXQUFPLFVBQVU7QUFFakIsUUFBSSxRQUFRLE9BQU87QUFDbEIsbUJBQWEsT0FBTyxRQUFRO0FBQUEsV0FDdEI7QUFDTixtQkFBYSxRQUFRLFFBQVE7QUFBQTtBQUFBOzs7QUM3SC9CLFNBQU8sS0FBSztBQUVMLHVCQUFxQixhQUFhO0FBQ3hDLFFBQUk7QUFDSCxvQkFBYyxLQUFLLE1BQU07QUFBQSxhQUNqQixHQUFQO0FBQ0QsY0FBUSxNQUFNO0FBQUE7QUFJZixXQUFPLEtBQUssT0FBTyxNQUFNO0FBR3pCLFdBQU8sS0FBSyxhQUFhLFFBQVEsQ0FBQyxnQkFBZ0I7QUFHakQsYUFBTyxHQUFHLGVBQWUsT0FBTyxHQUFHLGdCQUFnQjtBQUduRCxhQUFPLEtBQUssWUFBWSxjQUFjLFFBQVEsQ0FBQyxlQUFlO0FBRzdELGVBQU8sR0FBRyxhQUFhLGNBQWMsT0FBTyxHQUFHLGFBQWEsZUFBZTtBQUUzRSxlQUFPLEtBQUssWUFBWSxhQUFhLGFBQWEsUUFBUSxDQUFDLGVBQWU7QUFFekUsaUJBQU8sR0FBRyxhQUFhLFlBQVksY0FBYyxXQUFZO0FBRzVELGdCQUFJLFVBQVU7QUFHZCwrQkFBbUI7QUFDbEIsb0JBQU0sT0FBTyxHQUFHLE1BQU0sS0FBSztBQUMzQixxQkFBTyxLQUFLLENBQUMsYUFBYSxZQUFZLFlBQVksS0FBSyxNQUFNLE1BQU07QUFBQTtBQUlwRSxvQkFBUSxhQUFhLFNBQVUsWUFBWTtBQUMxQyx3QkFBVTtBQUFBO0FBSVgsb0JBQVEsYUFBYSxXQUFZO0FBQ2hDLHFCQUFPO0FBQUE7QUFHUixtQkFBTztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7OztBQzdEWjtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFlTywwQkFBd0I7QUFDM0IsV0FBTyxTQUFTO0FBQUE7QUFRYiwwQkFBd0I7QUFDM0IsV0FBTyxZQUFZO0FBQUE7QUFTaEIsMEJBQXdCLE9BQU87QUFDbEMsV0FBTyxZQUFZLE9BQU87QUFBQTtBQVF2Qiw4QkFBNEI7QUFDL0IsV0FBTyxZQUFZO0FBQUE7QUFRaEIsZ0NBQThCO0FBQ2pDLFdBQU8sWUFBWTtBQUFBO0FBVWhCLHlCQUF1QixPQUFPLFFBQVE7QUFDekMsV0FBTyxZQUFZLFFBQVEsUUFBUSxNQUFNO0FBQUE7QUFVdEMsMkJBQXlCO0FBQzVCLFdBQU8sS0FBSztBQUFBO0FBVVQsNEJBQTBCLE9BQU8sUUFBUTtBQUM1QyxXQUFPLFlBQVksUUFBUSxRQUFRLE1BQU07QUFBQTtBQVV0Qyw0QkFBMEIsT0FBTyxRQUFRO0FBQzVDLFdBQU8sWUFBWSxRQUFRLFFBQVEsTUFBTTtBQUFBO0FBVXRDLDZCQUEyQixHQUFHLEdBQUc7QUFDcEMsV0FBTyxZQUFZLFFBQVEsSUFBSSxNQUFNO0FBQUE7QUFTbEMsK0JBQTZCO0FBQ2hDLFdBQU8sS0FBSztBQUFBO0FBUVQsd0JBQXNCO0FBQ3pCLFdBQU8sWUFBWTtBQUFBO0FBUWhCLHdCQUFzQjtBQUN6QixXQUFPLFlBQVk7QUFBQTtBQVFoQiw0QkFBMEI7QUFDN0IsV0FBTyxZQUFZO0FBQUE7QUFRaEIsOEJBQTRCO0FBQy9CLFdBQU8sWUFBWTtBQUFBO0FBUWhCLDRCQUEwQjtBQUM3QixXQUFPLFlBQVk7QUFBQTtBQVFoQiw4QkFBNEI7QUFDL0IsV0FBTyxZQUFZO0FBQUE7QUFVaEIseUJBQXVCLE1BQU07QUFDaEMsUUFBSSxPQUFPLEtBQUssVUFBVTtBQUMxQixXQUFPLFlBQVksUUFBUTtBQUFBOzs7QUN4TC9CO0FBQUE7QUFBQTtBQUFBO0FBS08sMEJBQXdCLEtBQUs7QUFDbEMsV0FBTyxZQUFZLFFBQVE7QUFBQTs7O0FDWXRCLGtCQUFnQjtBQUNuQixXQUFPLFlBQVk7QUFBQTtBQUl2QixTQUFPLFVBQVU7QUFBQSxPQUNWO0FBQUEsT0FDQTtBQUFBLE9BQ0E7QUFBQSxJQUNIO0FBQUEsSUFDQTtBQUFBLElBQ0E7QUFBQSxJQUNBO0FBQUEsSUFDQTtBQUFBLElBQ0E7QUFBQTtBQUlKLFNBQU8sUUFBUTtBQUFBLElBQ1g7QUFBQSxJQUNBO0FBQUEsSUFDQTtBQUFBLElBQ0E7QUFBQSxJQUNBO0FBQUEsSUFDQSxPQUFPO0FBQUEsTUFDSCxzQkFBc0I7QUFBQSxNQUN0QixnQ0FBZ0M7QUFBQTtBQUFBO0FBS3hDLFNBQU8sTUFBTSxZQUFZLE9BQU87QUFDaEMsU0FBTyxPQUFPLE1BQU07QUFLcEIsTUFBSSxNQUFXO0FBQ1gsV0FBTyxPQUFPO0FBQUE7QUFLbEIsU0FBTyxpQkFBaUIsYUFBYSxDQUFDLE1BQU07QUFDeEMsUUFBSSxpQkFBaUIsRUFBRTtBQUN2QixXQUFPLGtCQUFrQixNQUFNO0FBQzNCLFVBQUksZUFBZSxhQUFhLHVCQUF1QjtBQUNuRDtBQUFBLGlCQUNPLGVBQWUsYUFBYSxvQkFBb0I7QUFDdkQsWUFBSSxPQUFPLE1BQU0sTUFBTSxzQkFBc0I7QUFFekMsY0FBSSxFQUFFLFVBQVUsRUFBRSxPQUFPLGVBQWUsRUFBRSxVQUFVLEVBQUUsT0FBTyxjQUFjO0FBQ3ZFO0FBQUE7QUFBQTtBQUdSLGVBQU8sWUFBWTtBQUNuQixVQUFFO0FBQ0Y7QUFBQTtBQUVKLHVCQUFpQixlQUFlO0FBQUE7QUFBQTtBQUt4QyxTQUFPLGlCQUFpQixlQUFlLFNBQVUsR0FBRztBQUNoRCxRQUFJLE9BQU8sTUFBTSxNQUFNLGdDQUFnQztBQUNuRCxRQUFFO0FBQUE7QUFBQTsiLAogICJuYW1lcyI6IFtdCn0K diff --git a/v2/internal/frontend/runtime/runtime_prod_desktop.go b/v2/internal/frontend/runtime/runtime_prod_desktop.go index 7336f0102..feba8a847 100644 --- a/v2/internal/frontend/runtime/runtime_prod_desktop.go +++ b/v2/internal/frontend/runtime/runtime_prod_desktop.go @@ -1,4 +1,4 @@ -//go:build production && !debug +//go:build production && desktop package runtime diff --git a/v2/internal/frontend/runtime/runtime_prod_desktop.js b/v2/internal/frontend/runtime/runtime_prod_desktop.js index 3d38924f7..75a7b6924 100644 --- a/v2/internal/frontend/runtime/runtime_prod_desktop.js +++ b/v2/internal/frontend/runtime/runtime_prod_desktop.js @@ -1 +1 @@ -(()=>{var j=Object.defineProperty;var p=(e,t)=>{for(var n in t)j(e,n,{get:t[n],enumerable:!0})};var b={};p(b,{LogDebug:()=>$,LogError:()=>Q,LogFatal:()=>_,LogInfo:()=>Y,LogLevel:()=>K,LogPrint:()=>X,LogTrace:()=>J,LogWarning:()=>q,SetLogLevel:()=>Z});function u(e,t){window.WailsInvoke("L"+e+t)}function J(e){u("T",e)}function X(e){u("P",e)}function $(e){u("D",e)}function Y(e){u("I",e)}function q(e){u("W",e)}function Q(e){u("E",e)}function _(e){u("F",e)}function Z(e){u("S",e)}var K={TRACE:1,DEBUG:2,INFO:3,WARNING:4,ERROR:5};var y=class{constructor(t,n,o){this.eventName=t,this.maxCallbacks=o||-1,this.Callback=i=>(n.apply(null,i),this.maxCallbacks===-1?!1:(this.maxCallbacks-=1,this.maxCallbacks===0))}},w={};function v(e,t,n){w[e]=w[e]||[];let o=new y(e,t,n);return w[e].push(o),()=>ee(o)}function W(e,t){return v(e,t,-1)}function A(e,t){return v(e,t,1)}function P(e){let t=e.name,n=w[t]?.slice()||[];if(n.length){for(let o=n.length-1;o>=0;o-=1){let i=n[o],r=e.data;i.Callback(r)&&n.splice(o,1)}n.length===0?g(t):w[t]=n}}function F(e){let t;try{t=JSON.parse(e)}catch{let o="Invalid JSON passed to Notify: "+e;throw new Error(o)}P(t)}function R(e){let t={name:e,data:[].slice.apply(arguments).slice(1)};P(t),window.WailsInvoke("EE"+JSON.stringify(t))}function g(e){delete w[e],window.WailsInvoke("EX"+e)}function x(e,...t){g(e),t.length>0&&t.forEach(n=>{g(n)})}function M(){Object.keys(w).forEach(t=>{g(t)})}function ee(e){let t=e.eventName;w[t]!==void 0&&(w[t]=w[t].filter(n=>n!==e),w[t].length===0&&g(t))}var c={};function te(){var e=new Uint32Array(1);return window.crypto.getRandomValues(e)[0]}function ne(){return Math.random()*9007199254740991}var D;window.crypto?D=te:D=ne;function a(e,t,n){return n==null&&(n=0),new Promise(function(o,i){var r;do r=e+"-"+D();while(c[r]);var l;n>0&&(l=setTimeout(function(){i(Error("Call to "+e+" timed out. Request ID: "+r))},n)),c[r]={timeoutHandle:l,reject:i,resolve:o};try{let d={name:e,args:t,callbackID:r};window.WailsInvoke("C"+JSON.stringify(d))}catch(d){console.error(d)}})}window.ObfuscatedCall=(e,t,n)=>(n==null&&(n=0),new Promise(function(o,i){var r;do r=e+"-"+D();while(c[r]);var l;n>0&&(l=setTimeout(function(){i(Error("Call to method "+e+" timed out. Request ID: "+r))},n)),c[r]={timeoutHandle:l,reject:i,resolve:o};try{let d={id:e,args:t,callbackID:r};window.WailsInvoke("c"+JSON.stringify(d))}catch(d){console.error(d)}}));function z(e){let t;try{t=JSON.parse(e)}catch(i){let r=`Invalid JSON passed to callback: ${i.message}. Message: ${e}`;throw runtime.LogDebug(r),new Error(r)}let n=t.callbackid,o=c[n];if(!o){let i=`Callback '${n}' not registered!!!`;throw console.error(i),new Error(i)}clearTimeout(o.timeoutHandle),delete c[n],t.error?o.reject(t.error):o.resolve(t.result)}window.go={};function B(e){try{e=JSON.parse(e)}catch(t){console.error(t)}window.go=window.go||{},Object.keys(e).forEach(t=>{window.go[t]=window.go[t]||{},Object.keys(e[t]).forEach(n=>{window.go[t][n]=window.go[t][n]||{},Object.keys(e[t][n]).forEach(o=>{window.go[t][n][o]=function(){let i=0;function r(){let l=[].slice.call(arguments);return a([t,n,o].join("."),l,i)}return r.setTimeout=function(l){i=l},r.getTimeout=function(){return i},r}()})})})}var T={};p(T,{WindowCenter:()=>ae,WindowFullscreen:()=>de,WindowGetPosition:()=>xe,WindowGetSize:()=>pe,WindowHide:()=>De,WindowIsFullscreen:()=>ue,WindowIsMaximised:()=>Te,WindowIsMinimised:()=>Ce,WindowIsNormal:()=>Ie,WindowMaximise:()=>Ee,WindowMinimise:()=>Se,WindowReload:()=>oe,WindowReloadApp:()=>ie,WindowSetAlwaysOnTop:()=>ve,WindowSetBackgroundColour:()=>Oe,WindowSetDarkTheme:()=>le,WindowSetLightTheme:()=>se,WindowSetMaxSize:()=>ge,WindowSetMinSize:()=>me,WindowSetPosition:()=>We,WindowSetSize:()=>ce,WindowSetSystemDefaultTheme:()=>re,WindowSetTitle:()=>we,WindowShow:()=>he,WindowToggleMaximise:()=>be,WindowUnfullscreen:()=>fe,WindowUnmaximise:()=>ye,WindowUnminimise:()=>ke});function oe(){window.location.reload()}function ie(){window.WailsInvoke("WR")}function re(){window.WailsInvoke("WASDT")}function se(){window.WailsInvoke("WALT")}function le(){window.WailsInvoke("WADT")}function ae(){window.WailsInvoke("Wc")}function we(e){window.WailsInvoke("WT"+e)}function de(){window.WailsInvoke("WF")}function fe(){window.WailsInvoke("Wf")}function ue(){return a(":wails:WindowIsFullscreen")}function ce(e,t){window.WailsInvoke("Ws:"+e+":"+t)}function pe(){return a(":wails:WindowGetSize")}function ge(e,t){window.WailsInvoke("WZ:"+e+":"+t)}function me(e,t){window.WailsInvoke("Wz:"+e+":"+t)}function ve(e){window.WailsInvoke("WATP:"+(e?"1":"0"))}function We(e,t){window.WailsInvoke("Wp:"+e+":"+t)}function xe(){return a(":wails:WindowGetPos")}function De(){window.WailsInvoke("WH")}function he(){window.WailsInvoke("WS")}function Ee(){window.WailsInvoke("WM")}function be(){window.WailsInvoke("Wt")}function ye(){window.WailsInvoke("WU")}function Te(){return a(":wails:WindowIsMaximised")}function Se(){window.WailsInvoke("Wm")}function ke(){window.WailsInvoke("Wu")}function Ce(){return a(":wails:WindowIsMinimised")}function Ie(){return a(":wails:WindowIsNormal")}function Oe(e,t,n,o){let i=JSON.stringify({r:e||0,g:t||0,b:n||0,a:o||255});window.WailsInvoke("Wr:"+i)}var S={};p(S,{ScreenGetAll:()=>Le});function Le(){return a(":wails:ScreenGetAll")}var k={};p(k,{BrowserOpenURL:()=>Ae});function Ae(e){window.WailsInvoke("BO:"+e)}var C={};p(C,{ClipboardGetText:()=>Fe,ClipboardSetText:()=>Pe});function Pe(e){return a(":wails:ClipboardSetText",[e])}function Fe(){return a(":wails:ClipboardGetText")}var I={};p(I,{CanResolveFilePaths:()=>V,OnFileDrop:()=>Me,OnFileDropOff:()=>ze,ResolveFilePaths:()=>Re});var s={registered:!1,defaultUseDropTarget:!0,useDropTarget:!0,nextDeactivate:null,nextDeactivateTimeout:null},m="wails-drop-target-active";function h(e){let t=e.getPropertyValue(window.wails.flags.cssDropProperty).trim();return t?t===window.wails.flags.cssDropValue:!1}function G(e){if(!e.dataTransfer.types.includes("Files")||(e.preventDefault(),e.dataTransfer.dropEffect="copy",!window.wails.flags.enableWailsDragAndDrop)||!s.useDropTarget)return;let n=e.target;if(s.nextDeactivate&&s.nextDeactivate(),!n||!h(getComputedStyle(n)))return;let o=n;for(;o;)h(getComputedStyle(o))&&o.classList.add(m),o=o.parentElement}function H(e){if(!!e.dataTransfer.types.includes("Files")&&(e.preventDefault(),!!window.wails.flags.enableWailsDragAndDrop&&!!s.useDropTarget)){if(!e.target||!h(getComputedStyle(e.target)))return null;s.nextDeactivate&&s.nextDeactivate(),s.nextDeactivate=()=>{Array.from(document.getElementsByClassName(m)).forEach(n=>n.classList.remove(m)),s.nextDeactivate=null,s.nextDeactivateTimeout&&(clearTimeout(s.nextDeactivateTimeout),s.nextDeactivateTimeout=null)},s.nextDeactivateTimeout=setTimeout(()=>{s.nextDeactivate&&s.nextDeactivate()},50)}}function U(e){if(!!e.dataTransfer.types.includes("Files")&&(e.preventDefault(),!!window.wails.flags.enableWailsDragAndDrop)){if(V()){let n=[];e.dataTransfer.items?n=[...e.dataTransfer.items].map((o,i)=>{if(o.kind==="file")return o.getAsFile()}):n=[...e.dataTransfer.files],window.runtime.ResolveFilePaths(e.x,e.y,n)}!s.useDropTarget||(s.nextDeactivate&&s.nextDeactivate(),Array.from(document.getElementsByClassName(m)).forEach(n=>n.classList.remove(m)))}}function V(){return window.chrome?.webview?.postMessageWithAdditionalObjects!=null}function Re(e,t,n){window.chrome?.webview?.postMessageWithAdditionalObjects&&chrome.webview.postMessageWithAdditionalObjects(`file:drop:${e}:${t}`,n)}function Me(e,t){if(typeof e!="function"){console.error("DragAndDropCallback is not a function");return}if(s.registered)return;s.registered=!0;let n=typeof t;s.useDropTarget=n==="undefined"||n!=="boolean"?s.defaultUseDropTarget:t,window.addEventListener("dragover",G),window.addEventListener("dragleave",H),window.addEventListener("drop",U);let o=e;s.useDropTarget&&(o=function(i,r,l){let d=document.elementFromPoint(i,r);if(!d||!h(getComputedStyle(d)))return null;e(i,r,l)}),W("wails:file-drop",o)}function ze(){window.removeEventListener("dragover",G),window.removeEventListener("dragleave",H),window.removeEventListener("drop",U),x("wails:file-drop"),s.registered=!1}function N(e){let t=e.target;switch(window.getComputedStyle(t).getPropertyValue("--default-contextmenu").trim()){case"show":return;case"hide":e.preventDefault();return;default:if(t.isContentEditable)return;let i=window.getSelection(),r=i.toString().length>0;if(r)for(let l=0;l{if(window.wails.flags.resizeEdge){window.WailsInvoke("resize:"+window.wails.flags.resizeEdge),e.preventDefault();return}if(Ne(e)){if(window.wails.flags.disableScrollbarDrag&&(e.offsetX>e.target.clientWidth||e.offsetY>e.target.clientHeight))return;window.wails.flags.deferDragToMouseMove?window.wails.flags.shouldDrag=!0:(e.preventDefault(),window.WailsInvoke("drag"));return}else window.wails.flags.shouldDrag=!1});window.addEventListener("mouseup",()=>{window.wails.flags.shouldDrag=!1});function f(e){document.documentElement.style.cursor=e||window.wails.flags.defaultCursor,window.wails.flags.resizeEdge=e}window.addEventListener("mousemove",function(e){if(window.wails.flags.shouldDrag&&(window.wails.flags.shouldDrag=!1,(e.buttons!==void 0?e.buttons:e.which)>0)){window.WailsInvoke("drag");return}if(!window.wails.flags.enableResize)return;window.wails.flags.defaultCursor==null&&(window.wails.flags.defaultCursor=document.documentElement.style.cursor),window.outerWidth-e.clientX{var x=Object.defineProperty;var h=n=>x(n,"__esModule",{value:!0});var u=(n,o)=>{h(n);for(var e in o)x(n,e,{get:o[e],enumerable:!0})};var W={};u(W,{LogDebug:()=>C,LogError:()=>J,LogFatal:()=>F,LogInfo:()=>B,LogLevel:()=>U,LogPrint:()=>R,LogTrace:()=>D,LogWarning:()=>T,SetLogLevel:()=>G});function l(n,o){window.WailsInvoke("L"+n+o)}function D(n){l("T",n)}function R(n){l("P",n)}function C(n){l("D",n)}function B(n){l("I",n)}function T(n){l("W",n)}function J(n){l("E",n)}function F(n){l("F",n)}function G(n){l("S",n)}var U={TRACE:1,DEBUG:2,INFO:3,WARNING:4,ERROR:5};var E=class{constructor(o,e){e=e||-1,this.Callback=t=>(o.apply(null,t),e===-1?!1:(e-=1,e===0))}},s={};function d(n,o,e){s[n]=s[n]||[];let t=new E(o,e);s[n].push(t)}function I(n,o){d(n,o,-1)}function k(n,o){d(n,o,1)}function S(n){let o=n.name;if(s[o]){let e=s[o].slice();for(let t=0;t0&&(w=setTimeout(function(){r(Error("Call to "+n+" timed out. Request ID: "+i))},e)),a[i]={timeoutHandle:w,reject:r,resolve:t};try{let f={name:n,args:o,callbackID:i};window.WailsInvoke("C"+JSON.stringify(f))}catch(f){console.error(f)}})}function L(n){var o;try{o=JSON.parse(n)}catch(r){let i=`Invalid JSON passed to callback: ${r.message}. Message: ${n}`;throw wails.LogDebug(i),new Error(i)}var e=o.callbackid,t=a[e];if(!t){let r=`Callback '${e}' not registered!!!`;throw console.error(r),new Error(r)}clearTimeout(t.timeoutHandle),delete a[e],o.error?t.reject(o.error):t.resolve(o.result)}window.go={};function O(n){try{n=JSON.parse(n)}catch(o){console.error(o)}window.go=window.go||{},Object.keys(n).forEach(o=>{window.go[o]=window.go[o]||{},Object.keys(n[o]).forEach(e=>{window.go[o][e]=window.go[o][e]||{},Object.keys(n[o][e]).forEach(t=>{window.go[o][e][t]=function(){let r=0;function i(){let w=[].slice.call(arguments);return c([o,e,t].join("."),w,r)}return i.setTimeout=function(w){r=w},i.getTimeout=function(){return r},i}()})})})}var v={};u(v,{WindowCenter:()=>M,WindowFullscreen:()=>j,WindowGetPosition:()=>Y,WindowGetSize:()=>V,WindowHide:()=>Z,WindowMaximise:()=>_,WindowMinimise:()=>on,WindowReload:()=>H,WindowSetMaxSize:()=>X,WindowSetMinSize:()=>q,WindowSetPosition:()=>N,WindowSetRGBA:()=>tn,WindowSetSize:()=>Q,WindowSetTitle:()=>P,WindowShow:()=>K,WindowUnFullscreen:()=>$,WindowUnmaximise:()=>nn,WindowUnminimise:()=>en});function H(){window.location.reload()}function M(){window.WailsInvoke("Wc")}function P(n){window.WailsInvoke("WT"+n)}function j(){window.WailsInvoke("WF")}function $(){window.WailsInvoke("Wf")}function Q(n,o){window.WailsInvoke("Ws:"+n+":"+o)}function V(){return c(":wails:WindowGetSize")}function X(n,o){window.WailsInvoke("WZ:"+n+":"+o)}function q(n,o){window.WailsInvoke("Wz:"+n+":"+o)}function N(n,o){window.WailsInvoke("Wp:"+n+":"+o)}function Y(){return c(":wails:WindowGetPos")}function Z(){window.WailsInvoke("WH")}function K(){window.WailsInvoke("WS")}function _(){window.WailsInvoke("WM")}function nn(){window.WailsInvoke("WU")}function on(){window.WailsInvoke("Wm")}function en(){window.WailsInvoke("Wu")}function tn(n){let o=JSON.stringify(n);window.WailsInvoke("Wr:"+o)}var g={};u(g,{BrowserOpenURL:()=>rn});function rn(n){window.WailsInvoke("BO:"+n)}function sn(){window.WailsInvoke("Q")}window.runtime={...W,...v,...g,EventsOn:I,EventsOnce:k,EventsOnMultiple:d,EventsEmit:b,EventsOff:y,Quit:sn};window.wails={Callback:L,EventsNotify:m,SetBindings:O,eventListeners:s,callbacks:a,flags:{disableScrollbarDrag:!1,disableWailsDefaultContextMenu:!1}};window.wails.SetBindings(window.wailsbindings);delete window.wails.SetBindings;window.addEventListener("mousedown",n=>{let o=n.target;for(;o!=null&&!o.hasAttribute("data-wails-no-drag");){if(o.hasAttribute("data-wails-drag")){if(window.wails.flags.disableScrollbarDrag&&(n.offsetX>n.target.clientWidth||n.offsetY>n.target.clientHeight))break;window.WailsInvoke("drag"),n.preventDefault();break}o=o.parentElement}});window.addEventListener("contextmenu",function(n){window.wails.flags.disableWailsDefaultContextMenu&&n.preventDefault()});})(); diff --git a/v2/internal/frontend/runtime/vite.config.ts b/v2/internal/frontend/runtime/vite.config.ts deleted file mode 100644 index eb0831c65..000000000 --- a/v2/internal/frontend/runtime/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vitest/config' - -export default defineConfig({ - test: { - environment: 'happy-dom', - }, -}) \ No newline at end of file diff --git a/v2/internal/frontend/runtime/wrapper/README.md b/v2/internal/frontend/runtime/wrapper/README.md new file mode 100644 index 000000000..a743cffbb --- /dev/null +++ b/v2/internal/frontend/runtime/wrapper/README.md @@ -0,0 +1,4 @@ +# Wails Runtime + +This module is the Javascript runtime library for the [Wails](https://wails.app) framework. It is intended to be +installed as part of a [Wails](https://wails.app) project, not a standalone module. diff --git a/v2/internal/frontend/runtime/wrapper/browser.js b/v2/internal/frontend/runtime/wrapper/browser.js new file mode 100644 index 000000000..f1854820b --- /dev/null +++ b/v2/internal/frontend/runtime/wrapper/browser.js @@ -0,0 +1,8 @@ +/** + * @description: Use the system default browser to open the url + * @param {string} url + * @return {void} + */ +export function BrowserOpenURL(url) { + window.runtime.BrowserOpenURL(url); +} \ No newline at end of file diff --git a/v2/internal/frontend/runtime/wrapper/events.js b/v2/internal/frontend/runtime/wrapper/events.js new file mode 100644 index 000000000..623dad51a --- /dev/null +++ b/v2/internal/frontend/runtime/wrapper/events.js @@ -0,0 +1,58 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The electron alternative for Go +(c) Lea Anthony 2019-present +*/ + +/* jshint esversion: 9 */ + + +/** + * Registers an event listener that will be invoked `maxCallbacks` times before being destroyed + * + * @export + * @param {string} eventName + * @param {function} callback + * @param {number} maxCallbacks + */ +export function EventsOnMultiple(eventName, callback, maxCallbacks) { + window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks); +} + +/** + * Registers an event listener that will be invoked every time the event is emitted + * + * @export + * @param {string} eventName + * @param {function} callback + */ +export function EventsOn(eventName, callback) { + OnMultiple(eventName, callback, -1); +} + +/** + * Registers an event listener that will be invoked once then destroyed + * + * @export + * @param {string} eventName + * @param {function} callback + */ +export function EventsOnce(eventName, callback) { + OnMultiple(eventName, callback, 1); +} + + +/** + * Emit an event with the given name and data + * + * @export + * @param {string} eventName + */ +export function EventsEmit(eventName) { + let args = [eventName].slice.call(arguments); + return window.runtime.EventsEmit.apply(null, args); +} diff --git a/v2/internal/frontend/runtime/wrapper/log.js b/v2/internal/frontend/runtime/wrapper/log.js new file mode 100644 index 000000000..977abf5f4 --- /dev/null +++ b/v2/internal/frontend/runtime/wrapper/log.js @@ -0,0 +1,72 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The electron alternative for Go +(c) Lea Anthony 2019-present +*/ + +/* jshint esversion: 6 */ + + +/** + * Log the given trace message with the backend + * + * @export + * @param {string} message + */ +export function LogTrace(message) { + window.runtime.LogTrace(message); +} + +/** + * Log the given debug message with the backend + * + * @export + * @param {string} message + */ +export function LogDebug(message) { + window.runtime.LogDebug(message); +} + +/** + * Log the given info message with the backend + * + * @export + * @param {string} message + */ +export function LogInfo(message) { + window.runtime.LogInfo(message); +} + +/** + * Log the given warning message with the backend + * + * @export + * @param {string} message + */ +export function LogWarning(message) { + window.runtime.LogWarning(message); +} + +/** + * Log the given error message with the backend + * + * @export + * @param {string} message + */ +export function LogError(message) { + window.runtime.LogError(message); +} + +/** + * Log the given fatal message with the backend + * + * @export + * @param {string} message + */ +export function LogFatal(message) { + window.runtime.LogFatal(message); +} diff --git a/v2/internal/frontend/runtime/wrapper/main.js b/v2/internal/frontend/runtime/wrapper/main.js new file mode 100644 index 000000000..8be95ac4f --- /dev/null +++ b/v2/internal/frontend/runtime/wrapper/main.js @@ -0,0 +1,28 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The electron alternative for Go +(c) Lea Anthony 2019-present +*/ +/* jshint esversion: 9 */ + +import * as Log from "./log"; +import * as Events from './events'; +import * as Window from './window'; +import * as Browser from './browser'; + +export function Quit() { + window.runtime.Quit(); +} + + +export default { + ...Log, + ...Events, + ...Window, + ...Browser, + Quit +}; \ No newline at end of file diff --git a/v2/internal/frontend/runtime/wrapper/package-lock.json b/v2/internal/frontend/runtime/wrapper/package-lock.json new file mode 100644 index 000000000..058e19cf3 --- /dev/null +++ b/v2/internal/frontend/runtime/wrapper/package-lock.json @@ -0,0 +1,13 @@ +{ + "name": "@wailsapp/runtime", + "version": "2.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "@wailsapp/runtime", + "version": "2.0.0", + "license": "MIT" + } + } +} diff --git a/v2/internal/frontend/runtime/wrapper/runtime.d.ts b/v2/internal/frontend/runtime/wrapper/runtime.d.ts index 4445dac21..233a67a96 100644 --- a/v2/internal/frontend/runtime/wrapper/runtime.d.ts +++ b/v2/internal/frontend/runtime/wrapper/runtime.d.ts @@ -1,249 +1,87 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export interface Position { +interface Position { x: number; y: number; } -export interface Size { +interface Size { w: number; h: number; } -export interface Screen { - isCurrent: boolean; - isPrimary: boolean; - width : number - height : number +interface RGBA { + r: number; + g: number; + b: number; + a: number; } -// Environment information such as platform, buildtype, ... -export interface EnvironmentInfo { - buildType: string; - platform: string; - arch: string; + +interface runtime { + EventsEmit(eventName: string, data?: any): void; + + EventsOn(eventName: string, callback: (data?: any) => void): void; + + EventsOnMultiple(eventName: string, callback: (data?: any) => void, maxCallbacks: number): void; + + EventsOnce(eventName: string, callback: (data?: any) => void): void; + + LogTrace(message: string): void; + + LogDebug(message: string): void; + + LogError(message: string): void; + + LogFatal(message: string): void; + + LogInfo(message: string): void; + + LogWarning(message: string): void; + + WindowReload(): void; + + WindowCenter(): void; + + WindowSetTitle(title: string): void; + + WindowFullscreen(): void; + + WindowUnFullscreen(): void; + + WindowSetSize(width: number, height: number): Promise; + + WindowGetSize(): Promise; + + WindowSetMaxSize(width: number, height: number): void; + + WindowSetMinSize(width: number, height: number): void; + + WindowSetPosition(x: number, y: number): void; + + WindowGetPosition(): Promise; + + WindowHide(): void; + + WindowShow(): void; + + WindowMaximise(): void; + + WindowUnmaximise(): void; + + WindowMinimise(): void; + + WindowUnminimise(): void; + + WindowSetRGBA(rgba: RGBA): void; + + BrowserOpenURL(url: string): void; + + Quit(): void; } -// [EventsEmit](https://wails.io/docs/reference/runtime/events#eventsemit) -// emits the given event. Optional data may be passed with the event. -// This will trigger any event listeners. -export function EventsEmit(eventName: string, ...data: any): void; +declare global { + interface Window { + runtime: runtime; + } +} -// [EventsOn](https://wails.io/docs/reference/runtime/events#eventson) sets up a listener for the given event name. -export function EventsOn(eventName: string, callback: (...data: any) => void): () => void; - -// [EventsOnMultiple](https://wails.io/docs/reference/runtime/events#eventsonmultiple) -// sets up a listener for the given event name, but will only trigger a given number times. -export function EventsOnMultiple(eventName: string, callback: (...data: any) => void, maxCallbacks: number): () => void; - -// [EventsOnce](https://wails.io/docs/reference/runtime/events#eventsonce) -// sets up a listener for the given event name, but will only trigger once. -export function EventsOnce(eventName: string, callback: (...data: any) => void): () => void; - -// [EventsOff](https://wails.io/docs/reference/runtime/events#eventsoff) -// unregisters the listener for the given event name. -export function EventsOff(eventName: string, ...additionalEventNames: string[]): void; - -// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) -// unregisters all listeners. -export function EventsOffAll(): void; - -// [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) -// logs the given message as a raw message -export function LogPrint(message: string): void; - -// [LogTrace](https://wails.io/docs/reference/runtime/log#logtrace) -// logs the given message at the `trace` log level. -export function LogTrace(message: string): void; - -// [LogDebug](https://wails.io/docs/reference/runtime/log#logdebug) -// logs the given message at the `debug` log level. -export function LogDebug(message: string): void; - -// [LogError](https://wails.io/docs/reference/runtime/log#logerror) -// logs the given message at the `error` log level. -export function LogError(message: string): void; - -// [LogFatal](https://wails.io/docs/reference/runtime/log#logfatal) -// logs the given message at the `fatal` log level. -// The application will quit after calling this method. -export function LogFatal(message: string): void; - -// [LogInfo](https://wails.io/docs/reference/runtime/log#loginfo) -// logs the given message at the `info` log level. -export function LogInfo(message: string): void; - -// [LogWarning](https://wails.io/docs/reference/runtime/log#logwarning) -// logs the given message at the `warning` log level. -export function LogWarning(message: string): void; - -// [WindowReload](https://wails.io/docs/reference/runtime/window#windowreload) -// Forces a reload by the main application as well as connected browsers. -export function WindowReload(): void; - -// [WindowReloadApp](https://wails.io/docs/reference/runtime/window#windowreloadapp) -// Reloads the application frontend. -export function WindowReloadApp(): void; - -// [WindowSetAlwaysOnTop](https://wails.io/docs/reference/runtime/window#windowsetalwaysontop) -// Sets the window AlwaysOnTop or not on top. -export function WindowSetAlwaysOnTop(b: boolean): void; - -// [WindowSetSystemDefaultTheme](https://wails.io/docs/next/reference/runtime/window#windowsetsystemdefaulttheme) -// *Windows only* -// Sets window theme to system default (dark/light). -export function WindowSetSystemDefaultTheme(): void; - -// [WindowSetLightTheme](https://wails.io/docs/next/reference/runtime/window#windowsetlighttheme) -// *Windows only* -// Sets window to light theme. -export function WindowSetLightTheme(): void; - -// [WindowSetDarkTheme](https://wails.io/docs/next/reference/runtime/window#windowsetdarktheme) -// *Windows only* -// Sets window to dark theme. -export function WindowSetDarkTheme(): void; - -// [WindowCenter](https://wails.io/docs/reference/runtime/window#windowcenter) -// Centers the window on the monitor the window is currently on. -export function WindowCenter(): void; - -// [WindowSetTitle](https://wails.io/docs/reference/runtime/window#windowsettitle) -// Sets the text in the window title bar. -export function WindowSetTitle(title: string): void; - -// [WindowFullscreen](https://wails.io/docs/reference/runtime/window#windowfullscreen) -// Makes the window full screen. -export function WindowFullscreen(): void; - -// [WindowUnfullscreen](https://wails.io/docs/reference/runtime/window#windowunfullscreen) -// Restores the previous window dimensions and position prior to full screen. -export function WindowUnfullscreen(): void; - -// [WindowIsFullscreen](https://wails.io/docs/reference/runtime/window#windowisfullscreen) -// Returns the state of the window, i.e. whether the window is in full screen mode or not. -export function WindowIsFullscreen(): Promise; - -// [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize) -// Sets the width and height of the window. -export function WindowSetSize(width: number, height: number): void; - -// [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize) -// Gets the width and height of the window. -export function WindowGetSize(): Promise; - -// [WindowSetMaxSize](https://wails.io/docs/reference/runtime/window#windowsetmaxsize) -// Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMaxSize(width: number, height: number): void; - -// [WindowSetMinSize](https://wails.io/docs/reference/runtime/window#windowsetminsize) -// Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMinSize(width: number, height: number): void; - -// [WindowSetPosition](https://wails.io/docs/reference/runtime/window#windowsetposition) -// Sets the window position relative to the monitor the window is currently on. -export function WindowSetPosition(x: number, y: number): void; - -// [WindowGetPosition](https://wails.io/docs/reference/runtime/window#windowgetposition) -// Gets the window position relative to the monitor the window is currently on. -export function WindowGetPosition(): Promise; - -// [WindowHide](https://wails.io/docs/reference/runtime/window#windowhide) -// Hides the window. -export function WindowHide(): void; - -// [WindowShow](https://wails.io/docs/reference/runtime/window#windowshow) -// Shows the window, if it is currently hidden. -export function WindowShow(): void; - -// [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise) -// Maximises the window to fill the screen. -export function WindowMaximise(): void; - -// [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise) -// Toggles between Maximised and UnMaximised. -export function WindowToggleMaximise(): void; - -// [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise) -// Restores the window to the dimensions and position prior to maximising. -export function WindowUnmaximise(): void; - -// [WindowIsMaximised](https://wails.io/docs/reference/runtime/window#windowismaximised) -// Returns the state of the window, i.e. whether the window is maximised or not. -export function WindowIsMaximised(): Promise; - -// [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise) -// Minimises the window. -export function WindowMinimise(): void; - -// [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise) -// Restores the window to the dimensions and position prior to minimising. -export function WindowUnminimise(): void; - -// [WindowIsMinimised](https://wails.io/docs/reference/runtime/window#windowisminimised) -// Returns the state of the window, i.e. whether the window is minimised or not. -export function WindowIsMinimised(): Promise; - -// [WindowIsNormal](https://wails.io/docs/reference/runtime/window#windowisnormal) -// Returns the state of the window, i.e. whether the window is normal or not. -export function WindowIsNormal(): Promise; - -// [WindowSetBackgroundColour](https://wails.io/docs/reference/runtime/window#windowsetbackgroundcolour) -// Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels. -export function WindowSetBackgroundColour(R: number, G: number, B: number, A: number): void; - -// [ScreenGetAll](https://wails.io/docs/reference/runtime/window#screengetall) -// Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system. -export function ScreenGetAll(): Promise; - -// [BrowserOpenURL](https://wails.io/docs/reference/runtime/browser#browseropenurl) -// Opens the given URL in the system browser. -export function BrowserOpenURL(url: string): void; - -// [Environment](https://wails.io/docs/reference/runtime/intro#environment) -// Returns information about the environment -export function Environment(): Promise; - -// [Quit](https://wails.io/docs/reference/runtime/intro#quit) -// Quits the application. -export function Quit(): void; - -// [Hide](https://wails.io/docs/reference/runtime/intro#hide) -// Hides the application. -export function Hide(): void; - -// [Show](https://wails.io/docs/reference/runtime/intro#show) -// Shows the application. -export function Show(): void; - -// [ClipboardGetText](https://wails.io/docs/reference/runtime/clipboard#clipboardgettext) -// Returns the current text stored on clipboard -export function ClipboardGetText(): Promise; - -// [ClipboardSetText](https://wails.io/docs/reference/runtime/clipboard#clipboardsettext) -// Sets a text on the clipboard -export function ClipboardSetText(text: string): Promise; - -// [OnFileDrop](https://wails.io/docs/reference/runtime/draganddrop#onfiledrop) -// OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings. -export function OnFileDrop(callback: (x: number, y: number ,paths: string[]) => void, useDropTarget: boolean) :void - -// [OnFileDropOff](https://wails.io/docs/reference/runtime/draganddrop#dragandddropoff) -// OnFileDropOff removes the drag and drop listeners and handlers. -export function OnFileDropOff() :void - -// Check if the file path resolver is available -export function CanResolveFilePaths(): boolean; - -// Resolves file paths for an array of files -export function ResolveFilePaths(files: File[]): void \ No newline at end of file +export { }; diff --git a/v2/internal/frontend/runtime/wrapper/runtime.js b/v2/internal/frontend/runtime/wrapper/runtime.js index 7cb89d750..8a2b098a7 100644 --- a/v2/internal/frontend/runtime/wrapper/runtime.js +++ b/v2/internal/frontend/runtime/wrapper/runtime.js @@ -1,242 +1 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export function LogPrint(message) { - window.runtime.LogPrint(message); -} - -export function LogTrace(message) { - window.runtime.LogTrace(message); -} - -export function LogDebug(message) { - window.runtime.LogDebug(message); -} - -export function LogInfo(message) { - window.runtime.LogInfo(message); -} - -export function LogWarning(message) { - window.runtime.LogWarning(message); -} - -export function LogError(message) { - window.runtime.LogError(message); -} - -export function LogFatal(message) { - window.runtime.LogFatal(message); -} - -export function EventsOnMultiple(eventName, callback, maxCallbacks) { - return window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks); -} - -export function EventsOn(eventName, callback) { - return EventsOnMultiple(eventName, callback, -1); -} - -export function EventsOff(eventName, ...additionalEventNames) { - return window.runtime.EventsOff(eventName, ...additionalEventNames); -} - -export function EventsOffAll() { - return window.runtime.EventsOffAll(); -} - -export function EventsOnce(eventName, callback) { - return EventsOnMultiple(eventName, callback, 1); -} - -export function EventsEmit(eventName) { - let args = [eventName].slice.call(arguments); - return window.runtime.EventsEmit.apply(null, args); -} - -export function WindowReload() { - window.runtime.WindowReload(); -} - -export function WindowReloadApp() { - window.runtime.WindowReloadApp(); -} - -export function WindowSetAlwaysOnTop(b) { - window.runtime.WindowSetAlwaysOnTop(b); -} - -export function WindowSetSystemDefaultTheme() { - window.runtime.WindowSetSystemDefaultTheme(); -} - -export function WindowSetLightTheme() { - window.runtime.WindowSetLightTheme(); -} - -export function WindowSetDarkTheme() { - window.runtime.WindowSetDarkTheme(); -} - -export function WindowCenter() { - window.runtime.WindowCenter(); -} - -export function WindowSetTitle(title) { - window.runtime.WindowSetTitle(title); -} - -export function WindowFullscreen() { - window.runtime.WindowFullscreen(); -} - -export function WindowUnfullscreen() { - window.runtime.WindowUnfullscreen(); -} - -export function WindowIsFullscreen() { - return window.runtime.WindowIsFullscreen(); -} - -export function WindowGetSize() { - return window.runtime.WindowGetSize(); -} - -export function WindowSetSize(width, height) { - window.runtime.WindowSetSize(width, height); -} - -export function WindowSetMaxSize(width, height) { - window.runtime.WindowSetMaxSize(width, height); -} - -export function WindowSetMinSize(width, height) { - window.runtime.WindowSetMinSize(width, height); -} - -export function WindowSetPosition(x, y) { - window.runtime.WindowSetPosition(x, y); -} - -export function WindowGetPosition() { - return window.runtime.WindowGetPosition(); -} - -export function WindowHide() { - window.runtime.WindowHide(); -} - -export function WindowShow() { - window.runtime.WindowShow(); -} - -export function WindowMaximise() { - window.runtime.WindowMaximise(); -} - -export function WindowToggleMaximise() { - window.runtime.WindowToggleMaximise(); -} - -export function WindowUnmaximise() { - window.runtime.WindowUnmaximise(); -} - -export function WindowIsMaximised() { - return window.runtime.WindowIsMaximised(); -} - -export function WindowMinimise() { - window.runtime.WindowMinimise(); -} - -export function WindowUnminimise() { - window.runtime.WindowUnminimise(); -} - -export function WindowSetBackgroundColour(R, G, B, A) { - window.runtime.WindowSetBackgroundColour(R, G, B, A); -} - -export function ScreenGetAll() { - return window.runtime.ScreenGetAll(); -} - -export function WindowIsMinimised() { - return window.runtime.WindowIsMinimised(); -} - -export function WindowIsNormal() { - return window.runtime.WindowIsNormal(); -} - -export function BrowserOpenURL(url) { - window.runtime.BrowserOpenURL(url); -} - -export function Environment() { - return window.runtime.Environment(); -} - -export function Quit() { - window.runtime.Quit(); -} - -export function Hide() { - window.runtime.Hide(); -} - -export function Show() { - window.runtime.Show(); -} - -export function ClipboardGetText() { - return window.runtime.ClipboardGetText(); -} - -export function ClipboardSetText(text) { - return window.runtime.ClipboardSetText(text); -} - -/** - * Callback for OnFileDrop returns a slice of file path strings when a drop is finished. - * - * @export - * @callback OnFileDropCallback - * @param {number} x - x coordinate of the drop - * @param {number} y - y coordinate of the drop - * @param {string[]} paths - A list of file paths. - */ - -/** - * OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings. - * - * @export - * @param {OnFileDropCallback} callback - Callback for OnFileDrop returns a slice of file path strings when a drop is finished. - * @param {boolean} [useDropTarget=true] - Only call the callback when the drop finished on an element that has the drop target style. (--wails-drop-target) - */ -export function OnFileDrop(callback, useDropTarget) { - return window.runtime.OnFileDrop(callback, useDropTarget); -} - -/** - * OnFileDropOff removes the drag and drop listeners and handlers. - */ -export function OnFileDropOff() { - return window.runtime.OnFileDropOff(); -} - -export function CanResolveFilePaths() { - return window.runtime.CanResolveFilePaths(); -} - -export function ResolveFilePaths(files) { - return window.runtime.ResolveFilePaths(files); -} \ No newline at end of file +(()=>{var d=Object.defineProperty;var m=n=>d(n,"__esModule",{value:!0});var t=(n,i)=>{m(n);for(var o in i)d(n,o,{get:i[o],enumerable:!0})};var e={};t(e,{LogDebug:()=>c,LogError:()=>x,LogFatal:()=>s,LogInfo:()=>W,LogTrace:()=>p,LogWarning:()=>f});function p(n){window.runtime.LogTrace(n)}function c(n){window.runtime.LogDebug(n)}function W(n){window.runtime.LogInfo(n)}function f(n){window.runtime.LogWarning(n)}function x(n){window.runtime.LogError(n)}function s(n){window.runtime.LogFatal(n)}var w={};t(w,{EventsEmit:()=>g,EventsOn:()=>a,EventsOnMultiple:()=>l,EventsOnce:()=>S});function l(n,i,o){window.runtime.EventsOnMultiple(n,i,o)}function a(n,i){OnMultiple(n,i,-1)}function S(n,i){OnMultiple(n,i,1)}function g(n){let i=[n].slice.call(arguments);return window.runtime.EventsEmit.apply(null,i)}var r={};t(r,{WindowCenter:()=>M,WindowFullscreen:()=>v,WindowGetPosition:()=>B,WindowGetSize:()=>O,WindowHide:()=>P,WindowMaximise:()=>b,WindowMinimise:()=>A,WindowReload:()=>L,WindowSetMaxSize:()=>F,WindowSetMinSize:()=>G,WindowSetPosition:()=>R,WindowSetRGBA:()=>D,WindowSetSize:()=>U,WindowSetTitle:()=>E,WindowShow:()=>T,WindowUnFullscreen:()=>z,WindowUnmaximise:()=>h,WindowUnminimise:()=>C});function L(){window.runtime.WindowReload()}function M(){window.runtime.WindowCenter()}function E(n){window.runtime.WindowSetTitle(n)}function v(){window.runtime.WindowFullscreen()}function z(){window.runtime.WindowUnFullscreen()}function O(){window.runtime.WindowGetSize()}function U(n,i){window.runtime.WindowSetSize(n,i)}function F(n,i){window.runtime.WindowSetMaxSize(n,i)}function G(n,i){window.runtime.WindowSetMinSize(n,i)}function R(n,i){window.runtime.WindowSetPosition(n,i)}function B(){window.runtime.WindowGetPosition()}function P(){window.runtime.WindowHide()}function T(){window.runtime.WindowShow()}function b(){window.runtime.WindowMaximise()}function h(){window.runtime.WindowUnmaximise()}function A(){window.runtime.WindowMinimise()}function C(){window.runtime.WindowUnminimise()}function D(n){window.runtime.WindowSetRGBA(n)}var u={};t(u,{BrowserOpenURL:()=>H});function H(n){window.runtime.BrowserOpenURL(n)}function I(){window.runtime.Quit()}var y={...e,...w,...r,...u,Quit:I};})(); diff --git a/v2/internal/frontend/runtime/wrapper/window.js b/v2/internal/frontend/runtime/wrapper/window.js new file mode 100644 index 000000000..2ef54e3ac --- /dev/null +++ b/v2/internal/frontend/runtime/wrapper/window.js @@ -0,0 +1,187 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The electron alternative for Go +(c) Lea Anthony 2019-present +*/ + +/* jshint esversion: 9 */ + +/** + * Reloads the Window + * + * @export + */ +export function WindowReload() { + window.runtime.WindowReload(); +} + +/** + * Place the window in the center of the screen + * + * @export + */ +export function WindowCenter() { + window.runtime.WindowCenter(); +} + +/** + * Sets the window title + * + * @param {string} title + * @export + */ +export function WindowSetTitle(title) { + window.runtime.WindowSetTitle(title); +} + +/** + * Makes the window go fullscreen + * + * @export + */ +export function WindowFullscreen() { + window.runtime.WindowFullscreen(); +} + +/** + * Reverts the window from fullscreen + * + * @export + */ +export function WindowUnFullscreen() { + window.runtime.WindowUnFullscreen(); +} + +/** + * Get the Size of the window + * + * @export + * @return {Promise<{w: number, h: number}>} The size of the window + + */ +export function WindowGetSize() { + window.runtime.WindowGetSize(); +} + + +/** + * Set the Size of the window + * + * @export + * @param {number} width + * @param {number} height + */ +export function WindowSetSize(width, height) { + window.runtime.WindowSetSize(width, height); +} + +/** + * Set the maximum size of the window + * + * @export + * @param {number} width + * @param {number} height + */ +export function WindowSetMaxSize(width, height) { + window.runtime.WindowSetMaxSize(width, height); +} + +/** + * Set the minimum size of the window + * + * @export + * @param {number} width + * @param {number} height + */ +export function WindowSetMinSize(width, height) { + window.runtime.WindowSetMinSize(width, height); +} + +/** + * Set the Position of the window + * + * @export + * @param {number} x + * @param {number} y + */ +export function WindowSetPosition(x, y) { + window.runtime.WindowSetPosition(x, y); +} + +/** + * Get the Position of the window + * + * @export + * @return {Promise<{x: number, y: number}>} The position of the window + */ +export function WindowGetPosition() { + window.runtime.WindowGetPosition(); +} + +/** + * Hide the Window + * + * @export + */ +export function WindowHide() { + window.runtime.WindowHide(); +} + +/** + * Show the Window + * + * @export + */ +export function WindowShow() { + window.runtime.WindowShow(); +} + +/** + * Maximise the Window + * + * @export + */ +export function WindowMaximise() { + window.runtime.WindowMaximise(); +} + +/** + * Unmaximise the Window + * + * @export + */ +export function WindowUnmaximise() { + window.runtime.WindowUnmaximise(); +} + +/** + * Minimise the Window + * + * @export + */ +export function WindowMinimise() { + window.runtime.WindowMinimise(); +} + +/** + * Unminimise the Window + * + * @export + */ +export function WindowUnminimise() { + window.runtime.WindowUnminimise(); +} + +/** + * Sets the background colour of the window + * + * @export + * @param {RGBA} RGBA background colour + */ +export function WindowSetRGBA(RGBA) { + window.runtime.WindowSetRGBA(RGBA); +} diff --git a/v2/internal/frontend/utils/urlValidator.go b/v2/internal/frontend/utils/urlValidator.go deleted file mode 100644 index 76ba216ce..000000000 --- a/v2/internal/frontend/utils/urlValidator.go +++ /dev/null @@ -1,58 +0,0 @@ -package utils - -import ( - "errors" - "fmt" - "net/url" - "regexp" - "strings" -) - -func ValidateAndSanitizeURL(rawURL string) (string, error) { - // Check for null bytes (can cause truncation issues in some systems) - if strings.Contains(rawURL, "\x00") { - return "", errors.New("null bytes not allowed in URL") - } - - // Parse URL first - this handles most malformed URLs - parsedURL, err := url.Parse(rawURL) - if err != nil { - return "", fmt.Errorf("invalid URL format: %v", err) - } - - scheme := strings.ToLower(parsedURL.Scheme) - - if scheme == "javascript" || scheme == "data" || scheme == "file" || scheme == "ftp" || scheme == "" { - return "", errors.New("scheme not allowed") - } - - // Ensure there's actually a host for http/https URLs - if (scheme == "http" || scheme == "https") && parsedURL.Host == "" { - return "", fmt.Errorf("missing host for %s URL", scheme) - } - - sanitizedURL := parsedURL.String() - - // Check for control characters that might cause issues - // (but allow legitimate URL characters like &, ;, etc.) - for i, r := range sanitizedURL { - // Block control characters except tab, but allow other printable chars - if r < 32 && r != 9 { // 9 is tab, which might be legitimate - return "", fmt.Errorf("control character at position %d not allowed", i) - } - } - - // Shell metacharacter check - shellDangerous := `[;\|` + "`" + `$\\<>*{}\[\]()~! \t\n\r]` - if matched, _ := regexp.MatchString(shellDangerous, sanitizedURL); matched { - return "", errors.New("shell metacharacters not allowed") - } - - // Unicode danger check - unicodeDangerous := "[\u0000-\u001F\u007F\u00A0\u1680\u2000-\u200F\u2028-\u202F\u205F\u2060\u3000\uFEFF]" - if matched, _ := regexp.MatchString(unicodeDangerous, sanitizedURL); matched { - return "", errors.New("unicode dangerous characters not allowed") - } - - return sanitizedURL, nil -} diff --git a/v2/internal/frontend/utils/urlValidator_test.go b/v2/internal/frontend/utils/urlValidator_test.go deleted file mode 100644 index b385ccec1..000000000 --- a/v2/internal/frontend/utils/urlValidator_test.go +++ /dev/null @@ -1,207 +0,0 @@ -package utils_test - -import ( - "strings" - "testing" - - "github.com/wailsapp/wails/v2/internal/frontend/utils" -) - -// Test cases for ValidateAndOpenURL -func TestValidateURL(t *testing.T) { - testCases := []struct { - name string - url string - shouldErr bool - errMsg string - expected string - }{ - // Valid URLs - { - name: "valid https URL", - url: "https://www.example.com", - shouldErr: false, - expected: "https://www.example.com", - }, - { - name: "valid http URL", - url: "http://example.com", - shouldErr: false, - expected: "http://example.com", - }, - { - name: "URL with query parameters", - url: "https://example.com/search?q=cats&dogs", - shouldErr: false, - expected: "https://example.com/search?q=cats&dogs", - }, - { - name: "URL with port", - url: "https://example.com:8080/path", - shouldErr: false, - expected: "https://example.com:8080/path", - }, - { - name: "URL with fragment", - url: "https://example.com/page#section", - shouldErr: false, - expected: "https://example.com/page#section", - }, - { - name: "urlencode params", - url: "http://google.com/ ----browser-subprocess-path=C:\\\\Users\\\\Public\\\\test.bat", - shouldErr: false, - expected: "http://google.com/%20----browser-subprocess-path=C:%5C%5CUsers%5C%5CPublic%5C%5Ctest.bat", - }, - - // Invalid schemes - { - name: "javascript scheme", - url: "javascript:alert('xss')", - shouldErr: true, - errMsg: "scheme not allowed", - }, - { - name: "data scheme", - url: "data:text/html,", - shouldErr: true, - errMsg: "scheme not allowed", - }, - { - name: "file scheme", - url: "file:///etc/passwd", - shouldErr: true, - errMsg: "scheme not allowed", - }, - { - name: "ftp scheme", - url: "ftp://files.example.com/file.txt", - shouldErr: true, - errMsg: "scheme not allowed", - }, - - // Malformed URLs - { - name: "not a URL", - url: "not-a-url", - shouldErr: true, - errMsg: "scheme not allowed", // will have empty scheme - }, - { - name: "missing scheme", - url: "example.com", - shouldErr: true, - errMsg: "scheme not allowed", - }, - { - name: "malformed URL", - url: "https://", - shouldErr: true, - errMsg: "missing host", - }, - { - name: "empty host", - url: "http:///path", - shouldErr: true, - errMsg: "missing host", - }, - - // Security issues - { - name: "null byte in URL", - url: "https://example.com\x00/hidden", - shouldErr: true, - errMsg: "null bytes not allowed", - }, - { - name: "control characters", - url: "https://example.com\n/path", - shouldErr: true, - errMsg: "control character", - }, - { - name: "carriage return", - url: "https://example.com\r/path", - shouldErr: true, - errMsg: "control character", - }, - { - name: "URL with tab character", - url: "https://example.com/path?q=hello\tworld", - shouldErr: true, - errMsg: "control character", - }, - { - name: "URL with path parameters", - url: "https://example.com/path;param=value", - shouldErr: true, - errMsg: "shell metacharacters not allowed", - }, - { - name: "URL with special characters in query", - url: "https://example.com/search?q=hello world&filter=price>100", - shouldErr: true, - errMsg: "shell metacharacters not allowed", - }, - { - name: "URL with special characters in query and params", - url: "https://example.com/search?q=hello ----browser-subprocess-path=C:\\\\Users\\\\Public\\\\test.bat", - shouldErr: true, - errMsg: "shell metacharacters not allowed", - }, - { - name: "URL with dollar sign in query", - url: "https://example.com/search?price=$100", - shouldErr: true, - errMsg: "shell metacharacters not allowed", - }, - { - name: "URL with parentheses", - url: "https://example.com/file(1).html", - shouldErr: true, - errMsg: "shell metacharacters not allowed", - }, - { - name: "URL with unicode", - url: "https://example.com/search?q=hello\u2001foo", - shouldErr: true, - errMsg: "unicode dangerous characters not allowed", - }, - - // Edge cases - { - name: "international domain", - url: "https://例え.テスト/path", - shouldErr: false, - expected: "https://%E4%BE%8B%E3%81%88.%E3%83%86%E3%82%B9%E3%83%88/path", - }, - { - name: "URL with pipe character", - url: "https://example.com/user/123|admin", - shouldErr: false, - expected: "https://example.com/user/123%7Cadmin", - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - // We'll test only the validation part to avoid actually opening URLs - sanitized, err := utils.ValidateAndSanitizeURL(tc.url) - - if tc.shouldErr { - if err == nil { - t.Errorf("expected error for URL %q, but got none", tc.url) - } else if tc.errMsg != "" && !strings.Contains(err.Error(), tc.errMsg) { - t.Errorf("expected error containing %q, got %q", tc.errMsg, err.Error()) - } - } else { - if err != nil { - t.Errorf("expected no error for URL %q, but got: %v", tc.url, err) - } - if sanitized != tc.expected { - t.Errorf("unexpected sanitized URL for %q: expected %q, got %q", tc.url, tc.expected, sanitized) - } - } - }) - } -} diff --git a/v2/internal/fs/fs.go b/v2/internal/fs/fs.go index 5662c020c..9bb192209 100644 --- a/v2/internal/fs/fs.go +++ b/v2/internal/fs/fs.go @@ -2,19 +2,24 @@ package fs import ( "crypto/md5" - "encoding/hex" "fmt" "io" - "io/fs" + "io/ioutil" "os" "path/filepath" "runtime" - "strings" "unsafe" "github.com/leaanthony/slicer" ) +// LocalDirectory gets the caller's file directory +// Equivalent to node's __DIRNAME +func LocalDirectory() string { + _, thisFile, _, _ := runtime.Caller(1) + return filepath.Dir(thisFile) +} + // RelativeToCwd returns an absolute path based on the cwd // and the given relative path func RelativeToCwd(relativePath string) (string, error) { @@ -28,14 +33,14 @@ func RelativeToCwd(relativePath string) (string, error) { // Mkdir will create the given directory func Mkdir(dirname string) error { - return os.Mkdir(dirname, 0o755) + return os.Mkdir(dirname, 0755) } // MkDirs creates the given nested directories. // Returns error on failure func MkDirs(fullPath string, mode ...os.FileMode) error { var perms os.FileMode - perms = 0o755 + perms = 0755 if len(mode) == 1 { perms = mode[0] } @@ -112,7 +117,7 @@ func RelativePath(relativepath string, optionalpaths ...string) string { // I'm allowing this for 1 reason only: It's fatal if the path // supplied is wrong as it's only used internally in Wails. If we get // that path wrong, we should know about it immediately. The other reason is - // that it cuts down a ton of unnecessary error handling. + // that it cuts down a ton of unnecassary error handling. panic(err) } return result @@ -121,7 +126,7 @@ func RelativePath(relativepath string, optionalpaths ...string) string { // MustLoadString attempts to load a string and will abort with a fatal message if // something goes wrong func MustLoadString(filename string) string { - data, err := os.ReadFile(filename) + data, err := ioutil.ReadFile(filename) if err != nil { fmt.Printf("FATAL: Unable to load file '%s': %s\n", filename, err.Error()) os.Exit(1) @@ -142,7 +147,7 @@ func MD5File(filename string) (string, error) { return "", err } - return hex.EncodeToString(h.Sum(nil)), nil + return fmt.Sprintf("%x", h.Sum(nil)), nil } // MustMD5File will call MD5File and abort the program on error @@ -158,7 +163,7 @@ func MustMD5File(filename string) string { // MustWriteString will attempt to write the given data to the given filename // It will abort the program in the event of a failure func MustWriteString(filename string, data string) { - err := os.WriteFile(filename, []byte(data), 0o755) + err := ioutil.WriteFile(filename, []byte(data), 0755) if err != nil { fatal("Unable to write file", filename, ":", err.Error()) os.Exit(1) @@ -195,6 +200,7 @@ func GetSubdirectories(rootDir string) (*slicer.StringSlicer, error) { } func DirIsEmpty(dir string) (bool, error) { + // CREDIT: https://stackoverflow.com/a/30708914/8325411 f, err := os.Open(dir) if err != nil { @@ -238,7 +244,7 @@ func CopyDir(src string, dst string) (err error) { return } - entries, err := os.ReadDir(src) + entries, err := ioutil.ReadDir(src) if err != nil { return } @@ -254,7 +260,7 @@ func CopyDir(src string, dst string) (err error) { } } else { // Skip symlinks. - if entry.Type()&os.ModeSymlink != 0 { + if entry.Mode()&os.ModeSymlink != 0 { continue } @@ -268,22 +274,13 @@ func CopyDir(src string, dst string) (err error) { return } -// SetPermissions recursively sets file permissions on a directory -func SetPermissions(dir string, perm os.FileMode) error { - return filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - return os.Chmod(path, perm) - }) -} - // CopyDirExtended recursively copies a directory tree, attempting to preserve permissions. // Source directory must exist, destination directory must *not* exist. It ignores any files or // directories that are given through the ignore parameter. // Symlinks are ignored and skipped. // Credit: https://gist.github.com/r0l1/92462b38df26839a3ca324697c8cba04 func CopyDirExtended(src string, dst string, ignore []string) (err error) { + ignoreList := slicer.String(ignore) src = filepath.Clean(src) dst = filepath.Clean(dst) @@ -309,7 +306,7 @@ func CopyDirExtended(src string, dst string, ignore []string) (err error) { return } - entries, err := os.ReadDir(src) + entries, err := ioutil.ReadDir(src) if err != nil { return } @@ -328,7 +325,7 @@ func CopyDirExtended(src string, dst string, ignore []string) (err error) { } } else { // Skip symlinks. - if entry.Type()&os.ModeSymlink != 0 { + if entry.Mode()&os.ModeSymlink != 0 { continue } @@ -342,61 +339,59 @@ func CopyDirExtended(src string, dst string, ignore []string) (err error) { return } -func FindPathToFile(fsys fs.FS, file string) (string, error) { - stat, _ := fs.Stat(fsys, file) - if stat != nil { - return ".", nil +// MoveDirExtended recursively moves a directory tree, attempting to preserve permissions. +// Source directory must exist, destination directory must *not* exist. It ignores any files or +// directories that are given through the ignore parameter. +// Symlinks are ignored and skipped. +func MoveDirExtended(src string, dst string, ignore []string) (err error) { + + ignoreList := slicer.String(ignore) + src = filepath.Clean(src) + dst = filepath.Clean(dst) + + si, err := os.Stat(src) + if err != nil { + return err } - var indexFiles slicer.StringSlicer - err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error { + if !si.IsDir() { + return fmt.Errorf("source is not a directory") + } + + _, err = os.Stat(dst) + if err != nil && !os.IsNotExist(err) { + return + } + if err == nil { + return fmt.Errorf("destination already exists") + } + + err = MkDirs(dst) + if err != nil { + return + } + + entries, err := ioutil.ReadDir(src) + if err != nil { + return + } + + for _, entry := range entries { + if ignoreList.Contains(entry.Name()) { + continue + } + srcPath := filepath.Join(src, entry.Name()) + dstPath := filepath.Join(dst, entry.Name()) + + // Skip symlinks. + if entry.Mode()&os.ModeSymlink != 0 { + continue + } + + err := os.Rename(srcPath, dstPath) if err != nil { return err } - if strings.HasSuffix(path, file) { - indexFiles.Add(path) - } - return nil - }) - if err != nil { - return "", err } - if indexFiles.Length() > 1 { - selected := indexFiles.AsSlice()[0] - for _, f := range indexFiles.AsSlice() { - if len(f) < len(selected) { - selected = f - } - } - path, _ := filepath.Split(selected) - return path, nil - } - if indexFiles.Length() > 0 { - path, _ := filepath.Split(indexFiles.AsSlice()[0]) - return path, nil - } - return "", fmt.Errorf("%s: %w", file, os.ErrNotExist) -} - -// FindFileInParents searches for a file in the current directory and all parent directories. -// Returns the absolute path to the file if found, otherwise an empty string -func FindFileInParents(path string, filename string) string { - // Check for bad paths - if _, err := os.Stat(path); err != nil { - return "" - } - - var pathToFile string - for { - pathToFile = filepath.Join(path, filename) - if _, err := os.Stat(pathToFile); err == nil { - break - } - parent := filepath.Dir(path) - if parent == path { - return "" - } - path = parent - } - return pathToFile + return } diff --git a/v2/internal/fs/fs_test.go b/v2/internal/fs/fs_test.go index efc4929e6..2cc524123 100644 --- a/v2/internal/fs/fs_test.go +++ b/v2/internal/fs/fs_test.go @@ -1,7 +1,6 @@ package fs import ( - "github.com/samber/lo" "os" "path/filepath" "testing" @@ -11,80 +10,22 @@ import ( func TestRelativePath(t *testing.T) { - i := is.New(t) + is := is.New(t) cwd, err := os.Getwd() - i.Equal(err, nil) + is.Equal(err, nil) // Check current directory actual := RelativePath(".") - i.Equal(actual, cwd) + is.Equal(actual, cwd) // Check 2 parameters actual = RelativePath("..", "fs") - i.Equal(actual, cwd) + is.Equal(actual, cwd) // Check 3 parameters including filename actual = RelativePath("..", "fs", "fs.go") expected := filepath.Join(cwd, "fs.go") - i.Equal(actual, expected) + is.Equal(actual, expected) } - -func Test_FindFileInParents(t *testing.T) { - tests := []struct { - name string - setup func() (startDir string, configDir string) - wantErr bool - }{ - { - name: "should error when no wails.json file is found in local or parent dirs", - setup: func() (string, string) { - tempDir := os.TempDir() - testDir := lo.Must(os.MkdirTemp(tempDir, "projectPath")) - _ = os.MkdirAll(testDir, 0755) - return testDir, "" - }, - wantErr: true, - }, - { - name: "should find wails.json in local path", - setup: func() (string, string) { - tempDir := os.TempDir() - testDir := lo.Must(os.MkdirTemp(tempDir, "projectPath")) - _ = os.MkdirAll(testDir, 0755) - configFile := filepath.Join(testDir, "wails.json") - _ = os.WriteFile(configFile, []byte("{}"), 0755) - return testDir, configFile - }, - wantErr: false, - }, - { - name: "should find wails.json in parent path", - setup: func() (string, string) { - tempDir := os.TempDir() - testDir := lo.Must(os.MkdirTemp(tempDir, "projectPath")) - _ = os.MkdirAll(testDir, 0755) - parentDir := filepath.Dir(testDir) - configFile := filepath.Join(parentDir, "wails.json") - _ = os.WriteFile(configFile, []byte("{}"), 0755) - return testDir, configFile - }, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - path, expectedPath := tt.setup() - defer func() { - if expectedPath != "" { - _ = os.Remove(expectedPath) - } - }() - got := FindFileInParents(path, "wails.json") - if got != expectedPath { - t.Errorf("FindFileInParents() got = %v, want %v", got, expectedPath) - } - }) - } -} diff --git a/v2/internal/github/github.go b/v2/internal/github/github.go index 2aa5e1432..e91b296e1 100644 --- a/v2/internal/github/github.go +++ b/v2/internal/github/github.go @@ -3,62 +3,16 @@ package github import ( "encoding/json" "fmt" - "github.com/charmbracelet/glamour/styles" - "io" + "io/ioutil" "net/http" - "net/url" - "runtime" "sort" "strings" - - "github.com/charmbracelet/glamour" ) -func GetReleaseNotes(tagVersion string, noColour bool) string { - resp, err := http.Get("https://api.github.com/repos/wailsapp/wails/releases/tags/" + url.PathEscape(tagVersion)) - if err != nil { - return "Unable to retrieve release notes. Please check your network connection" - } - body, err := io.ReadAll(resp.Body) - if err != nil { - return "Unable to retrieve release notes. Please check your network connection" - } - - data := map[string]interface{}{} - err = json.Unmarshal(body, &data) - if err != nil { - return "Unable to retrieve release notes. Please check your network connection" - } - - if data["body"] == nil { - return "No release notes found" - } - - result := "# Release Notes for " + tagVersion + "\n" + data["body"].(string) - var renderer *glamour.TermRenderer - - var termRendererOpts []glamour.TermRendererOption - - if runtime.GOOS == "windows" || noColour { - termRendererOpts = append(termRendererOpts, glamour.WithStyles(styles.NoTTYStyleConfig)) - } else { - termRendererOpts = append(termRendererOpts, glamour.WithAutoStyle()) - } - - renderer, err = glamour.NewTermRenderer(termRendererOpts...) - if err != nil { - return result - } - result, err = renderer.Render(result) - if err != nil { - return err.Error() - } - return result -} - // GetVersionTags gets the list of tags on the Wails repo // It returns a list of sorted tags in descending order func GetVersionTags() ([]*SemanticVersion, error) { + result := []*SemanticVersion{} var err error @@ -66,7 +20,7 @@ func GetVersionTags() ([]*SemanticVersion, error) { if err != nil { return result, err } - body, err := io.ReadAll(resp.Body) + body, err := ioutil.ReadAll(resp.Body) if err != nil { return result, err } @@ -98,6 +52,7 @@ func GetVersionTags() ([]*SemanticVersion, error) { // GetLatestStableRelease gets the latest stable release on GitHub func GetLatestStableRelease() (result *SemanticVersion, err error) { + tags, err := GetVersionTags() if err != nil { return nil, err @@ -114,6 +69,7 @@ func GetLatestStableRelease() (result *SemanticVersion, err error) { // GetLatestPreRelease gets the latest prerelease on GitHub func GetLatestPreRelease() (result *SemanticVersion, err error) { + tags, err := GetVersionTags() if err != nil { return nil, err diff --git a/v2/internal/github/semver_test.go b/v2/internal/github/semver_test.go index f748a57a0..4f8f9a693 100644 --- a/v2/internal/github/semver_test.go +++ b/v2/internal/github/semver_test.go @@ -29,15 +29,4 @@ func TestSemanticVersion_IsGreaterThan(t *testing.T) { result, err = v2.IsGreaterThan(beta1) is2.NoErr(err) is2.True(result) - - beta44, err := NewSemanticVersion("v2.0.0-beta.44.2") - is2.NoErr(err) - - rc1, err := NewSemanticVersion("v2.0.0-rc.1") - is2.NoErr(err) - - result, err = rc1.IsGreaterThan(beta44) - is2.NoErr(err) - is2.True(result) - } diff --git a/v2/internal/go-common-file-dialog/LICENSE b/v2/internal/go-common-file-dialog/LICENSE deleted file mode 100644 index 508b6978e..000000000 --- a/v2/internal/go-common-file-dialog/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2019 Harry Phillips - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/v2/internal/go-common-file-dialog/README.md b/v2/internal/go-common-file-dialog/README.md deleted file mode 100644 index 1cb5902d1..000000000 --- a/v2/internal/go-common-file-dialog/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# Common File Dialog bindings for Golang - -[Project Home](https://github.com/harry1453/go-common-file-dialog) - -This library contains bindings for Windows Vista and -newer's [Common File Dialogs](https://docs.microsoft.com/en-us/windows/win32/shell/common-file-dialog), which is the -standard system dialog for selecting files or folders to open or save. - -The Common File Dialogs have to be accessed via -the [COM Interface](https://en.wikipedia.org/wiki/Component_Object_Model), normally via C++ or via bindings (like in C#) -. - -This library contains bindings for Golang. **It does not require CGO**, and contains empty stubs for non-windows -platforms (so is safe to compile and run on platforms other than windows, but will just return errors at runtime). - -This can be very useful if you want to quickly get a file selector in your Golang application. The `cfdutil` package -contains utility functions with a single call to open and configure a dialog, and then get the result from it. Examples -for this are in [`_examples/usingutil`](_examples/usingutil). Or, if you want finer control over the dialog's operation, -you can use the base package. Examples for this are in [`_examples/notusingutil`](_examples/notusingutil). - -This library is available under the MIT license. - -Currently supported features: - -* Open File Dialog (to open a single file) -* Open Multiple Files Dialog (to open multiple files) -* Open Folder Dialog -* Save File Dialog -* Dialog "roles" to allow Windows to remember different "last locations" for different types of dialog -* Set dialog Title, Default Folder and Initial Folder -* Set dialog File Filters diff --git a/v2/internal/go-common-file-dialog/cfd/CommonFileDialog.go b/v2/internal/go-common-file-dialog/cfd/CommonFileDialog.go deleted file mode 100644 index 58e97aa4e..000000000 --- a/v2/internal/go-common-file-dialog/cfd/CommonFileDialog.go +++ /dev/null @@ -1,72 +0,0 @@ -// Cross-platform. - -// Common File Dialogs -package cfd - -type Dialog interface { - // Show the dialog to the user. - // Blocks until the user has closed the dialog. - Show() error - // Sets the dialog's parent window. Use 0 to set the dialog to have no parent window. - SetParentWindowHandle(hwnd uintptr) - // Show the dialog to the user. - // Blocks until the user has closed the dialog and returns their selection. - // Returns an error if the user cancelled the dialog. - // Do not use for the Open Multiple Files dialog. Use ShowAndGetResults instead. - ShowAndGetResult() (string, error) - // Sets the title of the dialog window. - SetTitle(title string) error - // Sets the "role" of the dialog. This is used to derive the dialog's GUID, which the - // OS will use to differentiate it from dialogs that are intended for other purposes. - // This means that, for example, a dialog with role "Import" will have a different - // previous location that it will open to than a dialog with role "Open". Can be any string. - SetRole(role string) error - // Sets the folder used as a default if there is not a recently used folder value available - SetDefaultFolder(defaultFolder string) error - // Sets the folder that the dialog always opens to. - // If this is set, it will override the "default folder" behaviour and the dialog will always open to this folder. - SetFolder(folder string) error - // Gets the selected file or folder path, as an absolute path eg. "C:\Folder\file.txt" - // Do not use for the Open Multiple Files dialog. Use GetResults instead. - GetResult() (string, error) - // Sets the file name, I.E. the contents of the file name text box. - // For Select Folder Dialog, sets folder name. - SetFileName(fileName string) error - // Release the resources allocated to this Dialog. - // Should be called when the dialog is finished with. - Release() error -} - -type FileDialog interface { - Dialog - // Set the list of file filters that the user can select. - SetFileFilters(fileFilter []FileFilter) error - // Set the selected item from the list of file filters (set using SetFileFilters) by its index. Defaults to 0 (the first item in the list) if not called. - SetSelectedFileFilterIndex(index uint) error - // Sets the default extension applied when a user does not provide one as part of the file name. - // If the user selects a different file filter, the default extension will be automatically updated to match the new file filter. - // For Open / Open Multiple File Dialog, this only has an effect when the user specifies a file name with no extension and a file with the default extension exists. - // For Save File Dialog, this extension will be used whenever a user does not specify an extension. - SetDefaultExtension(defaultExtension string) error -} - -type OpenFileDialog interface { - FileDialog -} - -type OpenMultipleFilesDialog interface { - FileDialog - // Show the dialog to the user. - // Blocks until the user has closed the dialog and returns the selected files. - ShowAndGetResults() ([]string, error) - // Gets the selected file paths, as absolute paths eg. "C:\Folder\file.txt" - GetResults() ([]string, error) -} - -type SelectFolderDialog interface { - Dialog -} - -type SaveFileDialog interface { // TODO Properties - FileDialog -} diff --git a/v2/internal/go-common-file-dialog/cfd/CommonFileDialog_nonWindows.go b/v2/internal/go-common-file-dialog/cfd/CommonFileDialog_nonWindows.go deleted file mode 100644 index 3ab969850..000000000 --- a/v2/internal/go-common-file-dialog/cfd/CommonFileDialog_nonWindows.go +++ /dev/null @@ -1,28 +0,0 @@ -//go:build !windows -// +build !windows - -package cfd - -import "fmt" - -var unsupportedError = fmt.Errorf("common file dialogs are only available on windows") - -// TODO doc -func NewOpenFileDialog(config DialogConfig) (OpenFileDialog, error) { - return nil, unsupportedError -} - -// TODO doc -func NewOpenMultipleFilesDialog(config DialogConfig) (OpenMultipleFilesDialog, error) { - return nil, unsupportedError -} - -// TODO doc -func NewSelectFolderDialog(config DialogConfig) (SelectFolderDialog, error) { - return nil, unsupportedError -} - -// TODO doc -func NewSaveFileDialog(config DialogConfig) (SaveFileDialog, error) { - return nil, unsupportedError -} diff --git a/v2/internal/go-common-file-dialog/cfd/CommonFileDialog_windows.go b/v2/internal/go-common-file-dialog/cfd/CommonFileDialog_windows.go deleted file mode 100644 index 69f46118e..000000000 --- a/v2/internal/go-common-file-dialog/cfd/CommonFileDialog_windows.go +++ /dev/null @@ -1,79 +0,0 @@ -//go:build windows -// +build windows - -package cfd - -import "github.com/go-ole/go-ole" - -func initialize() { - // Swallow error - _ = ole.CoInitializeEx(0, ole.COINIT_APARTMENTTHREADED|ole.COINIT_DISABLE_OLE1DDE) -} - -// TODO doc -func NewOpenFileDialog(config DialogConfig) (OpenFileDialog, error) { - initialize() - - openDialog, err := newIFileOpenDialog() - if err != nil { - return nil, err - } - err = config.apply(openDialog) - if err != nil { - return nil, err - } - return openDialog, nil -} - -// TODO doc -func NewOpenMultipleFilesDialog(config DialogConfig) (OpenMultipleFilesDialog, error) { - initialize() - - openDialog, err := newIFileOpenDialog() - if err != nil { - return nil, err - } - err = config.apply(openDialog) - if err != nil { - return nil, err - } - err = openDialog.setIsMultiselect(true) - if err != nil { - return nil, err - } - return openDialog, nil -} - -// TODO doc -func NewSelectFolderDialog(config DialogConfig) (SelectFolderDialog, error) { - initialize() - - openDialog, err := newIFileOpenDialog() - if err != nil { - return nil, err - } - err = config.apply(openDialog) - if err != nil { - return nil, err - } - err = openDialog.setPickFolders(true) - if err != nil { - return nil, err - } - return openDialog, nil -} - -// TODO doc -func NewSaveFileDialog(config DialogConfig) (SaveFileDialog, error) { - initialize() - - saveDialog, err := newIFileSaveDialog() - if err != nil { - return nil, err - } - err = config.apply(saveDialog) - if err != nil { - return nil, err - } - return saveDialog, nil -} diff --git a/v2/internal/go-common-file-dialog/cfd/DialogConfig.go b/v2/internal/go-common-file-dialog/cfd/DialogConfig.go deleted file mode 100644 index 9e06fb503..000000000 --- a/v2/internal/go-common-file-dialog/cfd/DialogConfig.go +++ /dev/null @@ -1,141 +0,0 @@ -// Cross-platform. - -package cfd - -import ( - "fmt" - "os" - "reflect" -) - -type FileFilter struct { - // The display name of the filter (That is shown to the user) - DisplayName string - // The filter pattern. Eg. "*.txt;*.png" to select all txt and png files, "*.*" to select any files, etc. - Pattern string -} - -// Never obfuscate the FileFilter type. -var _ = reflect.TypeOf(FileFilter{}) - -type DialogConfig struct { - // The title of the dialog - Title string - // The role of the dialog. This is used to derive the dialog's GUID, which the - // OS will use to differentiate it from dialogs that are intended for other purposes. - // This means that, for example, a dialog with role "Import" will have a different - // previous location that it will open to than a dialog with role "Open". Can be any string. - Role string - // The default folder - the folder that is used the first time the user opens it - // (after the first time their last used location is used). - DefaultFolder string - // The initial folder - the folder that the dialog always opens to if not empty. - // If this is not empty, it will override the "default folder" behaviour and - // the dialog will always open to this folder. - Folder string - // The file filters that restrict which types of files the dialog is able to choose. - // Ignored by Select Folder Dialog. - FileFilters []FileFilter - // Sets the initially selected file filter. This is an index of FileFilters. - // Ignored by Select Folder Dialog. - SelectedFileFilterIndex uint - // The initial name of the file (I.E. the text in the file name text box) when the user opens the dialog. - // For the Select Folder Dialog, this sets the initial folder name. - FileName string - // The default extension applied when a user does not provide one as part of the file name. - // If the user selects a different file filter, the default extension will be automatically updated to match the new file filter. - // For Open / Open Multiple File Dialog, this only has an effect when the user specifies a file name with no extension and a file with the default extension exists. - // For Save File Dialog, this extension will be used whenever a user does not specify an extension. - // Ignored by Select Folder Dialog. - DefaultExtension string - // ParentWindowHandle is the handle (HWND) to the parent window of the dialog. - // If left as 0 / nil, the dialog will have no parent window. - ParentWindowHandle uintptr -} - -var defaultFilters = []FileFilter{ - { - DisplayName: "All Files (*.*)", - Pattern: "*.*", - }, -} - -func (config *DialogConfig) apply(dialog Dialog) (err error) { - if config.Title != "" { - err = dialog.SetTitle(config.Title) - if err != nil { - return - } - } - - if config.Role != "" { - err = dialog.SetRole(config.Role) - if err != nil { - return - } - } - - if config.Folder != "" { - _, err = os.Stat(config.Folder) - if err != nil { - return - } - err = dialog.SetFolder(config.Folder) - if err != nil { - return - } - } - - if config.DefaultFolder != "" { - _, err = os.Stat(config.DefaultFolder) - if err != nil { - return - } - err = dialog.SetDefaultFolder(config.DefaultFolder) - if err != nil { - return - } - } - - if config.FileName != "" { - err = dialog.SetFileName(config.FileName) - if err != nil { - return - } - } - - dialog.SetParentWindowHandle(config.ParentWindowHandle) - - if dialog, ok := dialog.(FileDialog); ok { - var fileFilters []FileFilter - if config.FileFilters != nil && len(config.FileFilters) > 0 { - fileFilters = config.FileFilters - } else { - fileFilters = defaultFilters - } - err = dialog.SetFileFilters(fileFilters) - if err != nil { - return - } - - if config.SelectedFileFilterIndex != 0 { - if config.SelectedFileFilterIndex > uint(len(fileFilters)) { - err = fmt.Errorf("selected file filter index out of range") - return - } - err = dialog.SetSelectedFileFilterIndex(config.SelectedFileFilterIndex) - if err != nil { - return - } - } - - if config.DefaultExtension != "" { - err = dialog.SetDefaultExtension(config.DefaultExtension) - if err != nil { - return - } - } - } - - return -} diff --git a/v2/internal/go-common-file-dialog/cfd/errors.go b/v2/internal/go-common-file-dialog/cfd/errors.go deleted file mode 100644 index 4ca3300b9..000000000 --- a/v2/internal/go-common-file-dialog/cfd/errors.go +++ /dev/null @@ -1,9 +0,0 @@ -package cfd - -import "errors" - -var ( - ErrCancelled = errors.New("cancelled by user") - ErrInvalidGUID = errors.New("guid cannot be nil") - ErrEmptyFilters = errors.New("must specify at least one filter") -) diff --git a/v2/internal/go-common-file-dialog/cfd/iFileOpenDialog.go b/v2/internal/go-common-file-dialog/cfd/iFileOpenDialog.go deleted file mode 100644 index b1be23fcf..000000000 --- a/v2/internal/go-common-file-dialog/cfd/iFileOpenDialog.go +++ /dev/null @@ -1,200 +0,0 @@ -//go:build windows -// +build windows - -package cfd - -import ( - "github.com/go-ole/go-ole" - "github.com/google/uuid" - "syscall" - "unsafe" -) - -var ( - fileOpenDialogCLSID = ole.NewGUID("{DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7}") - fileOpenDialogIID = ole.NewGUID("{d57c7288-d4ad-4768-be02-9d969532d960}") -) - -type iFileOpenDialog struct { - vtbl *iFileOpenDialogVtbl - parentWindowHandle uintptr -} - -type iFileOpenDialogVtbl struct { - iFileDialogVtbl - - GetResults uintptr // func (ppenum **IShellItemArray) HRESULT - GetSelectedItems uintptr -} - -func newIFileOpenDialog() (*iFileOpenDialog, error) { - if unknown, err := ole.CreateInstance(fileOpenDialogCLSID, fileOpenDialogIID); err == nil { - return (*iFileOpenDialog)(unsafe.Pointer(unknown)), nil - } else { - return nil, err - } -} - -func (fileOpenDialog *iFileOpenDialog) Show() error { - return fileOpenDialog.vtbl.show(unsafe.Pointer(fileOpenDialog), fileOpenDialog.parentWindowHandle) -} - -func (fileOpenDialog *iFileOpenDialog) SetParentWindowHandle(hwnd uintptr) { - fileOpenDialog.parentWindowHandle = hwnd -} - -func (fileOpenDialog *iFileOpenDialog) ShowAndGetResult() (string, error) { - isMultiselect, err := fileOpenDialog.isMultiselect() - if err != nil { - return "", err - } - if isMultiselect { - // We should panic as this error is caused by the developer using the library - panic("use ShowAndGetResults for open multiple files dialog") - } - if err := fileOpenDialog.Show(); err != nil { - return "", err - } - return fileOpenDialog.GetResult() -} - -func (fileOpenDialog *iFileOpenDialog) ShowAndGetResults() ([]string, error) { - isMultiselect, err := fileOpenDialog.isMultiselect() - if err != nil { - return nil, err - } - if !isMultiselect { - // We should panic as this error is caused by the developer using the library - panic("use ShowAndGetResult for open single file dialog") - } - if err := fileOpenDialog.Show(); err != nil { - return nil, err - } - return fileOpenDialog.GetResults() -} - -func (fileOpenDialog *iFileOpenDialog) SetTitle(title string) error { - return fileOpenDialog.vtbl.setTitle(unsafe.Pointer(fileOpenDialog), title) -} - -func (fileOpenDialog *iFileOpenDialog) GetResult() (string, error) { - isMultiselect, err := fileOpenDialog.isMultiselect() - if err != nil { - return "", err - } - if isMultiselect { - // We should panic as this error is caused by the developer using the library - panic("use GetResults for open multiple files dialog") - } - return fileOpenDialog.vtbl.getResultString(unsafe.Pointer(fileOpenDialog)) -} - -func (fileOpenDialog *iFileOpenDialog) Release() error { - return fileOpenDialog.vtbl.release(unsafe.Pointer(fileOpenDialog)) -} - -func (fileOpenDialog *iFileOpenDialog) SetDefaultFolder(defaultFolderPath string) error { - return fileOpenDialog.vtbl.setDefaultFolder(unsafe.Pointer(fileOpenDialog), defaultFolderPath) -} - -func (fileOpenDialog *iFileOpenDialog) SetFolder(defaultFolderPath string) error { - return fileOpenDialog.vtbl.setFolder(unsafe.Pointer(fileOpenDialog), defaultFolderPath) -} - -func (fileOpenDialog *iFileOpenDialog) SetFileFilters(filter []FileFilter) error { - return fileOpenDialog.vtbl.setFileTypes(unsafe.Pointer(fileOpenDialog), filter) -} - -func (fileOpenDialog *iFileOpenDialog) SetRole(role string) error { - return fileOpenDialog.vtbl.setClientGuid(unsafe.Pointer(fileOpenDialog), StringToUUID(role)) -} - -// This should only be callable when the user asks for a multi select because -// otherwise they will be given the Dialog interface which does not expose this function. -func (fileOpenDialog *iFileOpenDialog) GetResults() ([]string, error) { - isMultiselect, err := fileOpenDialog.isMultiselect() - if err != nil { - return nil, err - } - if !isMultiselect { - // We should panic as this error is caused by the developer using the library - panic("use GetResult for open single file dialog") - } - return fileOpenDialog.vtbl.getResultsStrings(unsafe.Pointer(fileOpenDialog)) -} - -func (fileOpenDialog *iFileOpenDialog) SetDefaultExtension(defaultExtension string) error { - return fileOpenDialog.vtbl.setDefaultExtension(unsafe.Pointer(fileOpenDialog), defaultExtension) -} - -func (fileOpenDialog *iFileOpenDialog) SetFileName(initialFileName string) error { - return fileOpenDialog.vtbl.setFileName(unsafe.Pointer(fileOpenDialog), initialFileName) -} - -func (fileOpenDialog *iFileOpenDialog) SetSelectedFileFilterIndex(index uint) error { - return fileOpenDialog.vtbl.setSelectedFileFilterIndex(unsafe.Pointer(fileOpenDialog), index) -} - -func (fileOpenDialog *iFileOpenDialog) setPickFolders(pickFolders bool) error { - const FosPickfolders = 0x20 - if pickFolders { - return fileOpenDialog.vtbl.addOption(unsafe.Pointer(fileOpenDialog), FosPickfolders) - } else { - return fileOpenDialog.vtbl.removeOption(unsafe.Pointer(fileOpenDialog), FosPickfolders) - } -} - -const FosAllowMultiselect = 0x200 - -func (fileOpenDialog *iFileOpenDialog) isMultiselect() (bool, error) { - options, err := fileOpenDialog.vtbl.getOptions(unsafe.Pointer(fileOpenDialog)) - if err != nil { - return false, err - } - return options&FosAllowMultiselect != 0, nil -} - -func (fileOpenDialog *iFileOpenDialog) setIsMultiselect(isMultiselect bool) error { - if isMultiselect { - return fileOpenDialog.vtbl.addOption(unsafe.Pointer(fileOpenDialog), FosAllowMultiselect) - } else { - return fileOpenDialog.vtbl.removeOption(unsafe.Pointer(fileOpenDialog), FosAllowMultiselect) - } -} - -func (vtbl *iFileOpenDialogVtbl) getResults(objPtr unsafe.Pointer) (*iShellItemArray, error) { - var shellItemArray *iShellItemArray - ret, _, _ := syscall.SyscallN(vtbl.GetResults, - uintptr(objPtr), - uintptr(unsafe.Pointer(&shellItemArray)), - 0) - return shellItemArray, hresultToError(ret) -} - -func (vtbl *iFileOpenDialogVtbl) getResultsStrings(objPtr unsafe.Pointer) ([]string, error) { - shellItemArray, err := vtbl.getResults(objPtr) - if err != nil { - return nil, err - } - if shellItemArray == nil { - return nil, ErrCancelled - } - defer shellItemArray.vtbl.release(unsafe.Pointer(shellItemArray)) - count, err := shellItemArray.vtbl.getCount(unsafe.Pointer(shellItemArray)) - if err != nil { - return nil, err - } - var results []string - for i := uintptr(0); i < count; i++ { - newItem, err := shellItemArray.vtbl.getItemAt(unsafe.Pointer(shellItemArray), i) - if err != nil { - return nil, err - } - results = append(results, newItem) - } - return results, nil -} - -func StringToUUID(str string) *ole.GUID { - return ole.NewGUID(uuid.NewSHA1(uuid.Nil, []byte(str)).String()) -} diff --git a/v2/internal/go-common-file-dialog/cfd/iFileSaveDialog.go b/v2/internal/go-common-file-dialog/cfd/iFileSaveDialog.go deleted file mode 100644 index ddee7b246..000000000 --- a/v2/internal/go-common-file-dialog/cfd/iFileSaveDialog.go +++ /dev/null @@ -1,92 +0,0 @@ -//go:build windows -// +build windows - -package cfd - -import ( - "github.com/go-ole/go-ole" - "unsafe" -) - -var ( - saveFileDialogCLSID = ole.NewGUID("{C0B4E2F3-BA21-4773-8DBA-335EC946EB8B}") - saveFileDialogIID = ole.NewGUID("{84bccd23-5fde-4cdb-aea4-af64b83d78ab}") -) - -type iFileSaveDialog struct { - vtbl *iFileSaveDialogVtbl - parentWindowHandle uintptr -} - -type iFileSaveDialogVtbl struct { - iFileDialogVtbl - - SetSaveAsItem uintptr - SetProperties uintptr - SetCollectedProperties uintptr - GetProperties uintptr - ApplyProperties uintptr -} - -func newIFileSaveDialog() (*iFileSaveDialog, error) { - if unknown, err := ole.CreateInstance(saveFileDialogCLSID, saveFileDialogIID); err == nil { - return (*iFileSaveDialog)(unsafe.Pointer(unknown)), nil - } else { - return nil, err - } -} - -func (fileSaveDialog *iFileSaveDialog) Show() error { - return fileSaveDialog.vtbl.show(unsafe.Pointer(fileSaveDialog), fileSaveDialog.parentWindowHandle) -} - -func (fileSaveDialog *iFileSaveDialog) SetParentWindowHandle(hwnd uintptr) { - fileSaveDialog.parentWindowHandle = hwnd -} - -func (fileSaveDialog *iFileSaveDialog) ShowAndGetResult() (string, error) { - if err := fileSaveDialog.Show(); err != nil { - return "", err - } - return fileSaveDialog.GetResult() -} - -func (fileSaveDialog *iFileSaveDialog) SetTitle(title string) error { - return fileSaveDialog.vtbl.setTitle(unsafe.Pointer(fileSaveDialog), title) -} - -func (fileSaveDialog *iFileSaveDialog) GetResult() (string, error) { - return fileSaveDialog.vtbl.getResultString(unsafe.Pointer(fileSaveDialog)) -} - -func (fileSaveDialog *iFileSaveDialog) Release() error { - return fileSaveDialog.vtbl.release(unsafe.Pointer(fileSaveDialog)) -} - -func (fileSaveDialog *iFileSaveDialog) SetDefaultFolder(defaultFolderPath string) error { - return fileSaveDialog.vtbl.setDefaultFolder(unsafe.Pointer(fileSaveDialog), defaultFolderPath) -} - -func (fileSaveDialog *iFileSaveDialog) SetFolder(defaultFolderPath string) error { - return fileSaveDialog.vtbl.setFolder(unsafe.Pointer(fileSaveDialog), defaultFolderPath) -} - -func (fileSaveDialog *iFileSaveDialog) SetFileFilters(filter []FileFilter) error { - return fileSaveDialog.vtbl.setFileTypes(unsafe.Pointer(fileSaveDialog), filter) -} - -func (fileSaveDialog *iFileSaveDialog) SetRole(role string) error { - return fileSaveDialog.vtbl.setClientGuid(unsafe.Pointer(fileSaveDialog), StringToUUID(role)) -} - -func (fileSaveDialog *iFileSaveDialog) SetDefaultExtension(defaultExtension string) error { - return fileSaveDialog.vtbl.setDefaultExtension(unsafe.Pointer(fileSaveDialog), defaultExtension) -} - -func (fileSaveDialog *iFileSaveDialog) SetFileName(initialFileName string) error { - return fileSaveDialog.vtbl.setFileName(unsafe.Pointer(fileSaveDialog), initialFileName) -} - -func (fileSaveDialog *iFileSaveDialog) SetSelectedFileFilterIndex(index uint) error { - return fileSaveDialog.vtbl.setSelectedFileFilterIndex(unsafe.Pointer(fileSaveDialog), index) -} diff --git a/v2/internal/go-common-file-dialog/cfd/iShellItem.go b/v2/internal/go-common-file-dialog/cfd/iShellItem.go deleted file mode 100644 index 080115345..000000000 --- a/v2/internal/go-common-file-dialog/cfd/iShellItem.go +++ /dev/null @@ -1,56 +0,0 @@ -//go:build windows -// +build windows - -package cfd - -import ( - "github.com/go-ole/go-ole" - "syscall" - "unsafe" -) - -var ( - procSHCreateItemFromParsingName = syscall.NewLazyDLL("Shell32.dll").NewProc("SHCreateItemFromParsingName") - iidShellItem = ole.NewGUID("43826d1e-e718-42ee-bc55-a1e261c37bfe") -) - -type iShellItem struct { - vtbl *iShellItemVtbl -} - -type iShellItemVtbl struct { - iUnknownVtbl - BindToHandler uintptr - GetParent uintptr - GetDisplayName uintptr // func (sigdnName SIGDN, ppszName *LPWSTR) HRESULT - GetAttributes uintptr - Compare uintptr -} - -func newIShellItem(path string) (*iShellItem, error) { - var shellItem *iShellItem - pathPtr := ole.SysAllocString(path) - defer func(v *int16) { - _ = ole.SysFreeString(v) - }(pathPtr) - - ret, _, _ := procSHCreateItemFromParsingName.Call( - uintptr(unsafe.Pointer(pathPtr)), - 0, - uintptr(unsafe.Pointer(iidShellItem)), - uintptr(unsafe.Pointer(&shellItem))) - return shellItem, hresultToError(ret) -} - -func (vtbl *iShellItemVtbl) getDisplayName(objPtr unsafe.Pointer) (string, error) { - var ptr *uint16 - ret, _, _ := syscall.SyscallN(vtbl.GetDisplayName, - uintptr(objPtr), - 0x80058000, // SIGDN_FILESYSPATH, - uintptr(unsafe.Pointer(&ptr))) - if err := hresultToError(ret); err != nil { - return "", err - } - defer ole.CoTaskMemFree(uintptr(unsafe.Pointer(ptr))) - return ole.LpOleStrToString(ptr), nil -} diff --git a/v2/internal/go-common-file-dialog/cfd/iShellItemArray.go b/v2/internal/go-common-file-dialog/cfd/iShellItemArray.go deleted file mode 100644 index c548160d1..000000000 --- a/v2/internal/go-common-file-dialog/cfd/iShellItemArray.go +++ /dev/null @@ -1,64 +0,0 @@ -//go:build windows -// +build windows - -package cfd - -import ( - "github.com/go-ole/go-ole" - "syscall" - "unsafe" -) - -const ( - iidShellItemArrayGUID = "{b63ea76d-1f85-456f-a19c-48159efa858b}" -) - -var ( - iidShellItemArray *ole.GUID -) - -func init() { - iidShellItemArray, _ = ole.IIDFromString(iidShellItemArrayGUID) -} - -type iShellItemArray struct { - vtbl *iShellItemArrayVtbl -} - -type iShellItemArrayVtbl struct { - iUnknownVtbl - BindToHandler uintptr - GetPropertyStore uintptr - GetPropertyDescriptionList uintptr - GetAttributes uintptr - GetCount uintptr // func (pdwNumItems *DWORD) HRESULT - GetItemAt uintptr // func (dwIndex DWORD, ppsi **IShellItem) HRESULT - EnumItems uintptr -} - -func (vtbl *iShellItemArrayVtbl) getCount(objPtr unsafe.Pointer) (uintptr, error) { - var count uintptr - ret, _, _ := syscall.SyscallN(vtbl.GetCount, - uintptr(objPtr), - uintptr(unsafe.Pointer(&count))) - if err := hresultToError(ret); err != nil { - return 0, err - } - return count, nil -} - -func (vtbl *iShellItemArrayVtbl) getItemAt(objPtr unsafe.Pointer, index uintptr) (string, error) { - var shellItem *iShellItem - ret, _, _ := syscall.SyscallN(vtbl.GetItemAt, - uintptr(objPtr), - index, - uintptr(unsafe.Pointer(&shellItem))) - if err := hresultToError(ret); err != nil { - return "", err - } - if shellItem == nil { - return "", ErrCancelled - } - defer shellItem.vtbl.release(unsafe.Pointer(shellItem)) - return shellItem.vtbl.getDisplayName(unsafe.Pointer(shellItem)) -} diff --git a/v2/internal/go-common-file-dialog/cfd/vtblCommon.go b/v2/internal/go-common-file-dialog/cfd/vtblCommon.go deleted file mode 100644 index 21015c27c..000000000 --- a/v2/internal/go-common-file-dialog/cfd/vtblCommon.go +++ /dev/null @@ -1,48 +0,0 @@ -//go:build windows -// +build windows - -package cfd - -type comDlgFilterSpec struct { - pszName *int16 - pszSpec *int16 -} - -type iUnknownVtbl struct { - QueryInterface uintptr - AddRef uintptr - Release uintptr -} - -type iModalWindowVtbl struct { - iUnknownVtbl - Show uintptr // func (hwndOwner HWND) HRESULT -} - -type iFileDialogVtbl struct { - iModalWindowVtbl - SetFileTypes uintptr // func (cFileTypes UINT, rgFilterSpec *COMDLG_FILTERSPEC) HRESULT - SetFileTypeIndex uintptr // func(iFileType UINT) HRESULT - GetFileTypeIndex uintptr - Advise uintptr - Unadvise uintptr - SetOptions uintptr // func (fos FILEOPENDIALOGOPTIONS) HRESULT - GetOptions uintptr // func (pfos *FILEOPENDIALOGOPTIONS) HRESULT - SetDefaultFolder uintptr // func (psi *IShellItem) HRESULT - SetFolder uintptr // func (psi *IShellItem) HRESULT - GetFolder uintptr - GetCurrentSelection uintptr - SetFileName uintptr // func (pszName LPCWSTR) HRESULT - GetFileName uintptr - SetTitle uintptr // func(pszTitle LPCWSTR) HRESULT - SetOkButtonLabel uintptr - SetFileNameLabel uintptr - GetResult uintptr // func (ppsi **IShellItem) HRESULT - AddPlace uintptr - SetDefaultExtension uintptr // func (pszDefaultExtension LPCWSTR) HRESULT - // This can only be used from a callback. - Close uintptr - SetClientGuid uintptr // func (guid REFGUID) HRESULT - ClearClientData uintptr - SetFilter uintptr -} diff --git a/v2/internal/go-common-file-dialog/cfd/vtblCommonFunc.go b/v2/internal/go-common-file-dialog/cfd/vtblCommonFunc.go deleted file mode 100644 index 581a7b25c..000000000 --- a/v2/internal/go-common-file-dialog/cfd/vtblCommonFunc.go +++ /dev/null @@ -1,224 +0,0 @@ -//go:build windows - -package cfd - -import ( - "github.com/go-ole/go-ole" - "strings" - "syscall" - "unsafe" -) - -func hresultToError(hr uintptr) error { - if hr < 0 { - return ole.NewError(hr) - } - return nil -} - -func (vtbl *iUnknownVtbl) release(objPtr unsafe.Pointer) error { - ret, _, _ := syscall.SyscallN(vtbl.Release, - uintptr(objPtr), - 0) - return hresultToError(ret) -} - -func (vtbl *iModalWindowVtbl) show(objPtr unsafe.Pointer, hwnd uintptr) error { - ret, _, _ := syscall.SyscallN(vtbl.Show, - uintptr(objPtr), - hwnd) - return hresultToError(ret) -} - -func (vtbl *iFileDialogVtbl) setFileTypes(objPtr unsafe.Pointer, filters []FileFilter) error { - cFileTypes := len(filters) - if cFileTypes < 0 { - return ErrEmptyFilters - } - comDlgFilterSpecs := make([]comDlgFilterSpec, cFileTypes) - for i := 0; i < cFileTypes; i++ { - filter := &filters[i] - comDlgFilterSpecs[i] = comDlgFilterSpec{ - pszName: ole.SysAllocString(filter.DisplayName), - pszSpec: ole.SysAllocString(filter.Pattern), - } - } - - // Ensure memory is freed after use - defer func() { - for _, spec := range comDlgFilterSpecs { - ole.SysFreeString(spec.pszName) - ole.SysFreeString(spec.pszSpec) - } - }() - - ret, _, _ := syscall.SyscallN(vtbl.SetFileTypes, - uintptr(objPtr), - uintptr(cFileTypes), - uintptr(unsafe.Pointer(&comDlgFilterSpecs[0]))) - return hresultToError(ret) -} - -// Options are: -// FOS_OVERWRITEPROMPT = 0x2, -// FOS_STRICTFILETYPES = 0x4, -// FOS_NOCHANGEDIR = 0x8, -// FOS_PICKFOLDERS = 0x20, -// FOS_FORCEFILESYSTEM = 0x40, -// FOS_ALLNONSTORAGEITEMS = 0x80, -// FOS_NOVALIDATE = 0x100, -// FOS_ALLOWMULTISELECT = 0x200, -// FOS_PATHMUSTEXIST = 0x800, -// FOS_FILEMUSTEXIST = 0x1000, -// FOS_CREATEPROMPT = 0x2000, -// FOS_SHAREAWARE = 0x4000, -// FOS_NOREADONLYRETURN = 0x8000, -// FOS_NOTESTFILECREATE = 0x10000, -// FOS_HIDEMRUPLACES = 0x20000, -// FOS_HIDEPINNEDPLACES = 0x40000, -// FOS_NODEREFERENCELINKS = 0x100000, -// FOS_OKBUTTONNEEDSINTERACTION = 0x200000, -// FOS_DONTADDTORECENT = 0x2000000, -// FOS_FORCESHOWHIDDEN = 0x10000000, -// FOS_DEFAULTNOMINIMODE = 0x20000000, -// FOS_FORCEPREVIEWPANEON = 0x40000000, -// FOS_SUPPORTSTREAMABLEITEMS = 0x80000000 -func (vtbl *iFileDialogVtbl) setOptions(objPtr unsafe.Pointer, options uint32) error { - ret, _, _ := syscall.SyscallN(vtbl.SetOptions, - uintptr(objPtr), - uintptr(options)) - return hresultToError(ret) -} - -func (vtbl *iFileDialogVtbl) getOptions(objPtr unsafe.Pointer) (uint32, error) { - var options uint32 - ret, _, _ := syscall.SyscallN(vtbl.GetOptions, - uintptr(objPtr), - uintptr(unsafe.Pointer(&options))) - return options, hresultToError(ret) -} - -func (vtbl *iFileDialogVtbl) addOption(objPtr unsafe.Pointer, option uint32) error { - if options, err := vtbl.getOptions(objPtr); err == nil { - return vtbl.setOptions(objPtr, options|option) - } else { - return err - } -} - -func (vtbl *iFileDialogVtbl) removeOption(objPtr unsafe.Pointer, option uint32) error { - if options, err := vtbl.getOptions(objPtr); err == nil { - return vtbl.setOptions(objPtr, options&^option) - } else { - return err - } -} - -func (vtbl *iFileDialogVtbl) setDefaultFolder(objPtr unsafe.Pointer, path string) error { - shellItem, err := newIShellItem(path) - if err != nil { - return err - } - defer shellItem.vtbl.release(unsafe.Pointer(shellItem)) - ret, _, _ := syscall.SyscallN(vtbl.SetDefaultFolder, - uintptr(objPtr), - uintptr(unsafe.Pointer(shellItem))) - return hresultToError(ret) -} - -func (vtbl *iFileDialogVtbl) setFolder(objPtr unsafe.Pointer, path string) error { - shellItem, err := newIShellItem(path) - if err != nil { - return err - } - defer shellItem.vtbl.release(unsafe.Pointer(shellItem)) - ret, _, _ := syscall.SyscallN(vtbl.SetFolder, - uintptr(objPtr), - uintptr(unsafe.Pointer(shellItem))) - return hresultToError(ret) -} - -func (vtbl *iFileDialogVtbl) setTitle(objPtr unsafe.Pointer, title string) error { - titlePtr := ole.SysAllocString(title) - defer ole.SysFreeString(titlePtr) // Ensure the string is freed - ret, _, _ := syscall.SyscallN(vtbl.SetTitle, - uintptr(objPtr), - uintptr(unsafe.Pointer(titlePtr))) - return hresultToError(ret) -} - -func (vtbl *iFileDialogVtbl) close(objPtr unsafe.Pointer) error { - ret, _, _ := syscall.SyscallN(vtbl.Close, - uintptr(objPtr)) - return hresultToError(ret) -} - -func (vtbl *iFileDialogVtbl) getResult(objPtr unsafe.Pointer) (*iShellItem, error) { - var shellItem *iShellItem - ret, _, _ := syscall.SyscallN(vtbl.GetResult, - uintptr(objPtr), - uintptr(unsafe.Pointer(&shellItem))) - return shellItem, hresultToError(ret) -} - -func (vtbl *iFileDialogVtbl) getResultString(objPtr unsafe.Pointer) (string, error) { - shellItem, err := vtbl.getResult(objPtr) - if err != nil { - return "", err - } - if shellItem == nil { - return "", ErrCancelled - } - defer shellItem.vtbl.release(unsafe.Pointer(shellItem)) - return shellItem.vtbl.getDisplayName(unsafe.Pointer(shellItem)) -} - -func (vtbl *iFileDialogVtbl) setClientGuid(objPtr unsafe.Pointer, guid *ole.GUID) error { - // Ensure the GUID is not nil - if guid == nil { - return ErrInvalidGUID - } - - // Call the SetClientGuid method - ret, _, _ := syscall.SyscallN(vtbl.SetClientGuid, - uintptr(objPtr), - uintptr(unsafe.Pointer(guid))) - - // Convert the HRESULT to a Go error - return hresultToError(ret) -} - -func (vtbl *iFileDialogVtbl) setDefaultExtension(objPtr unsafe.Pointer, defaultExtension string) error { - // Ensure the string is not empty before accessing the first character - if len(defaultExtension) > 0 && defaultExtension[0] == '.' { - defaultExtension = strings.TrimPrefix(defaultExtension, ".") - } - - // Allocate memory for the default extension string - defaultExtensionPtr := ole.SysAllocString(defaultExtension) - defer ole.SysFreeString(defaultExtensionPtr) // Ensure the string is freed - - // Call the SetDefaultExtension method - ret, _, _ := syscall.SyscallN(vtbl.SetDefaultExtension, - uintptr(objPtr), - uintptr(unsafe.Pointer(defaultExtensionPtr))) - - // Convert the HRESULT to a Go error - return hresultToError(ret) -} - -func (vtbl *iFileDialogVtbl) setFileName(objPtr unsafe.Pointer, fileName string) error { - fileNamePtr := ole.SysAllocString(fileName) - defer ole.SysFreeString(fileNamePtr) // Ensure the string is freed - ret, _, _ := syscall.SyscallN(vtbl.SetFileName, - uintptr(objPtr), - uintptr(unsafe.Pointer(fileNamePtr))) - return hresultToError(ret) -} - -func (vtbl *iFileDialogVtbl) setSelectedFileFilterIndex(objPtr unsafe.Pointer, index uint) error { - ret, _, _ := syscall.SyscallN(vtbl.SetFileTypeIndex, - uintptr(objPtr), - uintptr(index+1)) // SetFileTypeIndex counts from 1 - return hresultToError(ret) -} diff --git a/v2/internal/go-common-file-dialog/cfdutil/CFDUtil.go b/v2/internal/go-common-file-dialog/cfdutil/CFDUtil.go deleted file mode 100644 index bde52d743..000000000 --- a/v2/internal/go-common-file-dialog/cfdutil/CFDUtil.go +++ /dev/null @@ -1,45 +0,0 @@ -package cfdutil - -import ( - "github.com/wailsapp/wails/v2/internal/go-common-file-dialog/cfd" -) - -// TODO doc -func ShowOpenFileDialog(config cfd.DialogConfig) (string, error) { - dialog, err := cfd.NewOpenFileDialog(config) - if err != nil { - return "", err - } - defer dialog.Release() - return dialog.ShowAndGetResult() -} - -// TODO doc -func ShowOpenMultipleFilesDialog(config cfd.DialogConfig) ([]string, error) { - dialog, err := cfd.NewOpenMultipleFilesDialog(config) - if err != nil { - return nil, err - } - defer dialog.Release() - return dialog.ShowAndGetResults() -} - -// TODO doc -func ShowPickFolderDialog(config cfd.DialogConfig) (string, error) { - dialog, err := cfd.NewSelectFolderDialog(config) - if err != nil { - return "", err - } - defer dialog.Release() - return dialog.ShowAndGetResult() -} - -// TODO doc -func ShowSaveFileDialog(config cfd.DialogConfig) (string, error) { - dialog, err := cfd.NewSaveFileDialog(config) - if err != nil { - return "", err - } - defer dialog.Release() - return dialog.ShowAndGetResult() -} diff --git a/v2/internal/go-common-file-dialog/util/util.go b/v2/internal/go-common-file-dialog/util/util.go deleted file mode 100644 index 723fbedc0..000000000 --- a/v2/internal/go-common-file-dialog/util/util.go +++ /dev/null @@ -1,10 +0,0 @@ -package util - -import ( - "github.com/go-ole/go-ole" - "github.com/google/uuid" -) - -func StringToUUID(str string) *ole.GUID { - return ole.NewGUID(uuid.NewSHA1(uuid.Nil, []byte(str)).String()) -} diff --git a/v2/internal/go-common-file-dialog/util/util_test.go b/v2/internal/go-common-file-dialog/util/util_test.go deleted file mode 100644 index 2e8ffeb05..000000000 --- a/v2/internal/go-common-file-dialog/util/util_test.go +++ /dev/null @@ -1,14 +0,0 @@ -package util - -import ( - "github.com/go-ole/go-ole" - "testing" -) - -func TestStringToUUID(t *testing.T) { - generated := *StringToUUID("TestTestTest") - expected := *ole.NewGUID("7933985F-2C87-5A5B-A26E-5D0326829AC2") - if generated != expected { - t.Errorf("not equal. expected %s, found %s", expected.String(), generated.String()) - } -} diff --git a/v2/internal/gomod/gomod.go b/v2/internal/gomod/gomod.go index c38e60f0b..c043d1e8f 100644 --- a/v2/internal/gomod/gomod.go +++ b/v2/internal/gomod/gomod.go @@ -2,7 +2,6 @@ package gomod import ( "fmt" - "github.com/Masterminds/semver" "golang.org/x/mod/modfile" ) @@ -35,10 +34,6 @@ func GoModOutOfSync(goModData []byte, currentVersion string) (bool, error) { if err != nil { return false, err } - if gomodversion == nil { - return false, fmt.Errorf("Unable to find Wails in go.mod") - } - result, err := semver.NewVersion(currentVersion) if err != nil || result == nil { return false, fmt.Errorf("Unable to parse Wails version: %s", currentVersion) @@ -82,33 +77,3 @@ func UpdateGoModVersion(goModText []byte, currentVersion string) ([]byte, error) return file.Format() } - -func SyncGoVersion(goModText []byte, goVersion string) ([]byte, bool, error) { - file, err := modfile.Parse("", goModText, nil) - if err != nil { - return nil, false, err - } - - modVersion, err := semver.NewVersion(file.Go.Version) - if err != nil { - return nil, false, fmt.Errorf("Unable to parse Go version from go mod file: %s", err) - } - - targetVersion, err := semver.NewVersion(goVersion) - if err != nil { - return nil, false, fmt.Errorf("Unable to parse Go version: %s", targetVersion) - } - - if !targetVersion.GreaterThan(modVersion) { - return goModText, false, nil - } - - file.Go.Version = goVersion - file.Go.Syntax.Token[1] = goVersion - goModText, err = file.Format() - if err != nil { - return nil, false, err - } - - return goModText, true, nil -} diff --git a/v2/internal/gomod/gomod_data_unix.go b/v2/internal/gomod/gomod_data_unix.go deleted file mode 100644 index c6004f486..000000000 --- a/v2/internal/gomod/gomod_data_unix.go +++ /dev/null @@ -1,139 +0,0 @@ -//go:build darwin || linux - -package gomod - -const basic string = `module changeme - -go 1.17 - -require github.com/wailsapp/wails/v2 v2.0.0-beta.7 - -//replace github.com/wailsapp/wails/v2 v2.0.0-beta.7 => /home/lea/wails/v2 -` - -const basicUpdated string = `module changeme - -go 1.17 - -require github.com/wailsapp/wails/v2 v2.0.0-beta.20 - -//replace github.com/wailsapp/wails/v2 v2.0.0-beta.7 => /home/lea/wails/v2 -` - -const multilineRequire = `module changeme - -go 1.17 - -require ( - github.com/wailsapp/wails/v2 v2.0.0-beta.7 -) - -//replace github.com/wailsapp/wails/v2 v2.0.0-beta.7 => /home/lea/wails/v2 -` - -const multilineReplace = `module changeme - -go 1.17 - -require ( - github.com/wailsapp/wails/v2 v2.0.0-beta.7 -) - -replace github.com/wailsapp/wails/v2 v2.0.0-beta.7 => /home/lea/wails/v2 -` - -const multilineReplaceNoVersion = `module changeme - -go 1.17 - -require ( - github.com/wailsapp/wails/v2 v2.0.0-beta.7 -) - -replace github.com/wailsapp/wails/v2 => /home/lea/wails/v2 -` - -const multilineReplaceNoVersionBlock = `module changeme - -go 1.17 - -require ( - github.com/wailsapp/wails/v2 v2.0.0-beta.7 -) - -replace ( - github.com/wailsapp/wails/v2 => /home/lea/wails/v2 -) -` - -const multilineReplaceBlock = `module changeme - -go 1.17 - -require ( - github.com/wailsapp/wails/v2 v2.0.0-beta.7 -) - -replace ( - github.com/wailsapp/wails/v2 v2.0.0-beta.7 => /home/lea/wails/v2 -) -` - -const multilineRequireUpdated = `module changeme - -go 1.17 - -require ( - github.com/wailsapp/wails/v2 v2.0.0-beta.20 -) - -//replace github.com/wailsapp/wails/v2 v2.0.0-beta.7 => /home/lea/wails/v2 -` - -const multilineReplaceUpdated = `module changeme - -go 1.17 - -require ( - github.com/wailsapp/wails/v2 v2.0.0-beta.20 -) - -replace github.com/wailsapp/wails/v2 v2.0.0-beta.20 => /home/lea/wails/v2 -` - -const multilineReplaceNoVersionUpdated = `module changeme - -go 1.17 - -require ( - github.com/wailsapp/wails/v2 v2.0.0-beta.20 -) - -replace github.com/wailsapp/wails/v2 => /home/lea/wails/v2 -` - -const multilineReplaceNoVersionBlockUpdated = `module changeme - -go 1.17 - -require ( - github.com/wailsapp/wails/v2 v2.0.0-beta.20 -) - -replace ( - github.com/wailsapp/wails/v2 => /home/lea/wails/v2 -) -` - -const multilineReplaceBlockUpdated = `module changeme - -go 1.17 - -require ( - github.com/wailsapp/wails/v2 v2.0.0-beta.20 -) - -replace ( - github.com/wailsapp/wails/v2 v2.0.0-beta.20 => /home/lea/wails/v2 -) -` diff --git a/v2/internal/gomod/gomod_data_windows.go b/v2/internal/gomod/gomod_data_windows.go deleted file mode 100644 index 691129c78..000000000 --- a/v2/internal/gomod/gomod_data_windows.go +++ /dev/null @@ -1,135 +0,0 @@ -//go:build windows - -package gomod - -const basic string = `module changeme - -go 1.17 - -require github.com/wailsapp/wails/v2 v2.0.0-beta.7 - -//replace github.com/wailsapp/wails/v2 v2.0.0-beta.7 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2 -` -const basicUpdated string = `module changeme - -go 1.17 - -require github.com/wailsapp/wails/v2 v2.0.0-beta.20 - -//replace github.com/wailsapp/wails/v2 v2.0.0-beta.7 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2 -` - -const multilineRequire = `module changeme - -go 1.17 - -require ( - github.com/wailsapp/wails/v2 v2.0.0-beta.7 -) - -//replace github.com/wailsapp/wails/v2 v2.0.0-beta.7 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2 -` -const multilineReplace = `module changeme - -go 1.17 - -require ( - github.com/wailsapp/wails/v2 v2.0.0-beta.7 -) - -replace github.com/wailsapp/wails/v2 v2.0.0-beta.7 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2 -` - -const multilineReplaceNoVersion = `module changeme - -go 1.17 - -require ( - github.com/wailsapp/wails/v2 v2.0.0-beta.7 -) - -replace github.com/wailsapp/wails/v2 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2 -` - -const multilineReplaceNoVersionBlock = `module changeme - -go 1.17 - -require ( - github.com/wailsapp/wails/v2 v2.0.0-beta.7 -) - -replace ( - github.com/wailsapp/wails/v2 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2 -) -` - -const multilineReplaceBlock = `module changeme - -go 1.17 - -require ( - github.com/wailsapp/wails/v2 v2.0.0-beta.7 -) - -replace ( - github.com/wailsapp/wails/v2 v2.0.0-beta.7 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2 -) -` - -const multilineRequireUpdated = `module changeme - -go 1.17 - -require ( - github.com/wailsapp/wails/v2 v2.0.0-beta.20 -) - -//replace github.com/wailsapp/wails/v2 v2.0.0-beta.7 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2 -` - -const multilineReplaceUpdated = `module changeme - -go 1.17 - -require ( - github.com/wailsapp/wails/v2 v2.0.0-beta.20 -) - -replace github.com/wailsapp/wails/v2 v2.0.0-beta.20 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2 -` -const multilineReplaceNoVersionUpdated = `module changeme - -go 1.17 - -require ( - github.com/wailsapp/wails/v2 v2.0.0-beta.20 -) - -replace github.com/wailsapp/wails/v2 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2 -` -const multilineReplaceNoVersionBlockUpdated = `module changeme - -go 1.17 - -require ( - github.com/wailsapp/wails/v2 v2.0.0-beta.20 -) - -replace ( - github.com/wailsapp/wails/v2 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2 -) -` - -const multilineReplaceBlockUpdated = `module changeme - -go 1.17 - -require ( - github.com/wailsapp/wails/v2 v2.0.0-beta.20 -) - -replace ( - github.com/wailsapp/wails/v2 v2.0.0-beta.20 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2 -) -` diff --git a/v2/internal/gomod/gomod_test.go b/v2/internal/gomod/gomod_test.go index eeafd0f9a..7dc16fb34 100644 --- a/v2/internal/gomod/gomod_test.go +++ b/v2/internal/gomod/gomod_test.go @@ -1,13 +1,53 @@ package gomod import ( - "reflect" - "testing" - "github.com/Masterminds/semver" "github.com/matryer/is" + "reflect" + "testing" ) +const basic string = `module changeme + +go 1.17 + +require github.com/wailsapp/wails/v2 v2.0.0-beta.7 + +require ( + github.com/andybalholm/brotli v1.0.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect + github.com/gabriel-vasile/mimetype v1.3.1 // indirect + github.com/go-ole/go-ole v1.2.5 // indirect + github.com/gofiber/fiber/v2 v2.17.0 // indirect + github.com/gofiber/websocket/v2 v2.0.8 // indirect + github.com/google/uuid v1.1.2 // indirect + github.com/imdario/mergo v0.3.12 // indirect + github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect + github.com/klauspost/compress v1.12.2 // indirect + github.com/leaanthony/debme v1.2.1 // indirect + github.com/leaanthony/go-ansi-parser v1.0.1 // indirect + github.com/leaanthony/go-common-file-dialog v1.0.3 // indirect + github.com/leaanthony/go-webview2 v0.0.0-20211007092718-65d2f028ef2d // indirect + github.com/leaanthony/gosod v1.0.3 // indirect + github.com/leaanthony/slicer v1.5.0 // indirect + github.com/leaanthony/typescriptify-golang-structs v0.1.7 // indirect + github.com/leaanthony/webview2runtime v1.1.0 // indirect + github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 // indirect + github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect + github.com/tkrajina/go-reflector v0.5.5 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.28.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect + golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect +) + +//replace github.com/wailsapp/wails/v2 v2.0.0-beta.7 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2 +` + func TestGetWailsVersion(t *testing.T) { tests := []struct { name string @@ -31,6 +71,303 @@ func TestGetWailsVersion(t *testing.T) { } } +const basicUpdated string = `module changeme + +go 1.17 + +require github.com/wailsapp/wails/v2 v2.0.0-beta.15 + +require ( + github.com/andybalholm/brotli v1.0.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect + github.com/gabriel-vasile/mimetype v1.3.1 // indirect + github.com/go-ole/go-ole v1.2.5 // indirect + github.com/gofiber/fiber/v2 v2.17.0 // indirect + github.com/gofiber/websocket/v2 v2.0.8 // indirect + github.com/google/uuid v1.1.2 // indirect + github.com/imdario/mergo v0.3.12 // indirect + github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect + github.com/klauspost/compress v1.12.2 // indirect + github.com/leaanthony/debme v1.2.1 // indirect + github.com/leaanthony/go-ansi-parser v1.0.1 // indirect + github.com/leaanthony/go-common-file-dialog v1.0.3 // indirect + github.com/leaanthony/go-webview2 v0.0.0-20211007092718-65d2f028ef2d // indirect + github.com/leaanthony/gosod v1.0.3 // indirect + github.com/leaanthony/slicer v1.5.0 // indirect + github.com/leaanthony/typescriptify-golang-structs v0.1.7 // indirect + github.com/leaanthony/webview2runtime v1.1.0 // indirect + github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 // indirect + github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect + github.com/tkrajina/go-reflector v0.5.5 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.28.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect + golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect +) + +//replace github.com/wailsapp/wails/v2 v2.0.0-beta.7 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2 +` + +const multilineRequire = `module changeme + +go 1.17 + +require ( + github.com/wailsapp/wails/v2 v2.0.0-beta.7 +) +require ( + github.com/andybalholm/brotli v1.0.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect + github.com/gabriel-vasile/mimetype v1.3.1 // indirect + github.com/go-ole/go-ole v1.2.5 // indirect + github.com/gofiber/fiber/v2 v2.17.0 // indirect + github.com/gofiber/websocket/v2 v2.0.8 // indirect + github.com/google/uuid v1.1.2 // indirect + github.com/imdario/mergo v0.3.12 // indirect + github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect + github.com/klauspost/compress v1.12.2 // indirect + github.com/leaanthony/debme v1.2.1 // indirect + github.com/leaanthony/go-ansi-parser v1.0.1 // indirect + github.com/leaanthony/go-common-file-dialog v1.0.3 // indirect + github.com/leaanthony/go-webview2 v0.0.0-20211007092718-65d2f028ef2d // indirect + github.com/leaanthony/gosod v1.0.3 // indirect + github.com/leaanthony/slicer v1.5.0 // indirect + github.com/leaanthony/typescriptify-golang-structs v0.1.7 // indirect + github.com/leaanthony/webview2runtime v1.1.0 // indirect + github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 // indirect + github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect + github.com/tkrajina/go-reflector v0.5.5 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.28.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect + golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect +) + +//replace github.com/wailsapp/wails/v2 v2.0.0-beta.7 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2 +` +const multilineReplace = `module changeme + +go 1.17 + +require ( + github.com/wailsapp/wails/v2 v2.0.0-beta.7 +) +require ( + github.com/andybalholm/brotli v1.0.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect + github.com/gabriel-vasile/mimetype v1.3.1 // indirect + github.com/go-ole/go-ole v1.2.5 // indirect + github.com/gofiber/fiber/v2 v2.17.0 // indirect + github.com/gofiber/websocket/v2 v2.0.8 // indirect + github.com/google/uuid v1.1.2 // indirect + github.com/imdario/mergo v0.3.12 // indirect + github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect + github.com/klauspost/compress v1.12.2 // indirect + github.com/leaanthony/debme v1.2.1 // indirect + github.com/leaanthony/go-ansi-parser v1.0.1 // indirect + github.com/leaanthony/go-common-file-dialog v1.0.3 // indirect + github.com/leaanthony/go-webview2 v0.0.0-20211007092718-65d2f028ef2d // indirect + github.com/leaanthony/gosod v1.0.3 // indirect + github.com/leaanthony/slicer v1.5.0 // indirect + github.com/leaanthony/typescriptify-golang-structs v0.1.7 // indirect + github.com/leaanthony/webview2runtime v1.1.0 // indirect + github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 // indirect + github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect + github.com/tkrajina/go-reflector v0.5.5 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.28.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect + golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect +) + +replace github.com/wailsapp/wails/v2 v2.0.0-beta.7 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2 +` + +const multilineReplaceNoVersion = `module changeme + +go 1.17 + +require ( + github.com/wailsapp/wails/v2 v2.0.0-beta.7 +) +require ( + github.com/andybalholm/brotli v1.0.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect + github.com/gabriel-vasile/mimetype v1.3.1 // indirect + github.com/go-ole/go-ole v1.2.5 // indirect + github.com/gofiber/fiber/v2 v2.17.0 // indirect + github.com/gofiber/websocket/v2 v2.0.8 // indirect + github.com/google/uuid v1.1.2 // indirect + github.com/imdario/mergo v0.3.12 // indirect + github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect + github.com/klauspost/compress v1.12.2 // indirect + github.com/leaanthony/debme v1.2.1 // indirect + github.com/leaanthony/go-ansi-parser v1.0.1 // indirect + github.com/leaanthony/go-common-file-dialog v1.0.3 // indirect + github.com/leaanthony/go-webview2 v0.0.0-20211007092718-65d2f028ef2d // indirect + github.com/leaanthony/gosod v1.0.3 // indirect + github.com/leaanthony/slicer v1.5.0 // indirect + github.com/leaanthony/typescriptify-golang-structs v0.1.7 // indirect + github.com/leaanthony/webview2runtime v1.1.0 // indirect + github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 // indirect + github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect + github.com/tkrajina/go-reflector v0.5.5 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.28.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect + golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect +) + +replace github.com/wailsapp/wails/v2 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2 +` + +const multilineReplaceNoVersionBlock = `module changeme + +go 1.17 + +require ( + github.com/wailsapp/wails/v2 v2.0.0-beta.7 +) +require ( + github.com/andybalholm/brotli v1.0.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect + github.com/gabriel-vasile/mimetype v1.3.1 // indirect + github.com/go-ole/go-ole v1.2.5 // indirect + github.com/gofiber/fiber/v2 v2.17.0 // indirect + github.com/gofiber/websocket/v2 v2.0.8 // indirect + github.com/google/uuid v1.1.2 // indirect + github.com/imdario/mergo v0.3.12 // indirect + github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect + github.com/klauspost/compress v1.12.2 // indirect + github.com/leaanthony/debme v1.2.1 // indirect + github.com/leaanthony/go-ansi-parser v1.0.1 // indirect + github.com/leaanthony/go-common-file-dialog v1.0.3 // indirect + github.com/leaanthony/go-webview2 v0.0.0-20211007092718-65d2f028ef2d // indirect + github.com/leaanthony/gosod v1.0.3 // indirect + github.com/leaanthony/slicer v1.5.0 // indirect + github.com/leaanthony/typescriptify-golang-structs v0.1.7 // indirect + github.com/leaanthony/webview2runtime v1.1.0 // indirect + github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 // indirect + github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect + github.com/tkrajina/go-reflector v0.5.5 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.28.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect + golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect +) + +replace ( + github.com/wailsapp/wails/v2 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2 +) +` + +const multilineReplaceBlock = `module changeme + +go 1.17 + +require ( + github.com/wailsapp/wails/v2 v2.0.0-beta.7 +) +require ( + github.com/andybalholm/brotli v1.0.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect + github.com/gabriel-vasile/mimetype v1.3.1 // indirect + github.com/go-ole/go-ole v1.2.5 // indirect + github.com/gofiber/fiber/v2 v2.17.0 // indirect + github.com/gofiber/websocket/v2 v2.0.8 // indirect + github.com/google/uuid v1.1.2 // indirect + github.com/imdario/mergo v0.3.12 // indirect + github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect + github.com/klauspost/compress v1.12.2 // indirect + github.com/leaanthony/debme v1.2.1 // indirect + github.com/leaanthony/go-ansi-parser v1.0.1 // indirect + github.com/leaanthony/go-common-file-dialog v1.0.3 // indirect + github.com/leaanthony/go-webview2 v0.0.0-20211007092718-65d2f028ef2d // indirect + github.com/leaanthony/gosod v1.0.3 // indirect + github.com/leaanthony/slicer v1.5.0 // indirect + github.com/leaanthony/typescriptify-golang-structs v0.1.7 // indirect + github.com/leaanthony/webview2runtime v1.1.0 // indirect + github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 // indirect + github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect + github.com/tkrajina/go-reflector v0.5.5 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.28.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect + golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect +) + +replace ( + github.com/wailsapp/wails/v2 v2.0.0-beta.7 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2 +) +` + +const multilineRequireUpdated = `module changeme + +go 1.17 + +require ( + github.com/wailsapp/wails/v2 v2.0.0-beta.15 +) + +require ( + github.com/andybalholm/brotli v1.0.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect + github.com/gabriel-vasile/mimetype v1.3.1 // indirect + github.com/go-ole/go-ole v1.2.5 // indirect + github.com/gofiber/fiber/v2 v2.17.0 // indirect + github.com/gofiber/websocket/v2 v2.0.8 // indirect + github.com/google/uuid v1.1.2 // indirect + github.com/imdario/mergo v0.3.12 // indirect + github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect + github.com/klauspost/compress v1.12.2 // indirect + github.com/leaanthony/debme v1.2.1 // indirect + github.com/leaanthony/go-ansi-parser v1.0.1 // indirect + github.com/leaanthony/go-common-file-dialog v1.0.3 // indirect + github.com/leaanthony/go-webview2 v0.0.0-20211007092718-65d2f028ef2d // indirect + github.com/leaanthony/gosod v1.0.3 // indirect + github.com/leaanthony/slicer v1.5.0 // indirect + github.com/leaanthony/typescriptify-golang-structs v0.1.7 // indirect + github.com/leaanthony/webview2runtime v1.1.0 // indirect + github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 // indirect + github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect + github.com/tkrajina/go-reflector v0.5.5 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.28.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect + golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect +) + +//replace github.com/wailsapp/wails/v2 v2.0.0-beta.7 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2 +` + func TestUpdateGoModVersion(t *testing.T) { is2 := is.New(t) @@ -44,12 +381,12 @@ func TestUpdateGoModVersion(t *testing.T) { want []byte wantErr bool }{ - {"basic", args{[]byte(basic), "v2.0.0-beta.20"}, []byte(basicUpdated), false}, - {"basicmultiline", args{[]byte(multilineRequire), "v2.0.0-beta.20"}, []byte(multilineRequireUpdated), false}, - {"basicmultilinereplace", args{[]byte(multilineReplace), "v2.0.0-beta.20"}, []byte(multilineReplaceUpdated), false}, - {"basicmultilinereplaceblock", args{[]byte(multilineReplaceBlock), "v2.0.0-beta.20"}, []byte(multilineReplaceBlockUpdated), false}, - {"basicmultilinereplacenoversion", args{[]byte(multilineReplaceNoVersion), "v2.0.0-beta.20"}, []byte(multilineReplaceNoVersionUpdated), false}, - {"basicmultilinereplacenoversionblock", args{[]byte(multilineReplaceNoVersionBlock), "v2.0.0-beta.20"}, []byte(multilineReplaceNoVersionBlockUpdated), false}, + {"basic", args{[]byte(basic), "v2.0.0-beta.15"}, []byte(basicUpdated), false}, + {"basicmultiline", args{[]byte(multilineRequire), "v2.0.0-beta.15"}, []byte(multilineRequireUpdated), false}, + {"basicmultilinereplace", args{[]byte(multilineReplace), "v2.0.0-beta.15"}, []byte(multilineReplaceUpdated), false}, + {"basicmultilinereplaceblock", args{[]byte(multilineReplaceBlock), "v2.0.0-beta.15"}, []byte(multilineReplaceBlockUpdated), false}, + {"basicmultilinereplacenoversion", args{[]byte(multilineReplaceNoVersion), "v2.0.0-beta.15"}, []byte(multilineReplaceNoVersionUpdated), false}, + {"basicmultilinereplacenoversionblock", args{[]byte(multilineReplaceNoVersionBlock), "v2.0.0-beta.15"}, []byte(multilineReplaceNoVersionBlockUpdated), false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -58,7 +395,7 @@ func TestUpdateGoModVersion(t *testing.T) { t.Errorf("UpdateGoModVersion() error = %v, wantErr %v", err, tt.wantErr) return } - is2.Equal(string(got), string(tt.want)) + is2.Equal(got, tt.want) }) } } @@ -76,8 +413,8 @@ func TestGoModOutOfSync(t *testing.T) { want bool wantErr bool }{ - {"basic", args{[]byte(basic), "v2.0.0-beta.20"}, true, false}, - {"basicmultiline", args{[]byte(multilineRequire), "v2.0.0-beta.20"}, true, false}, + {"basic", args{[]byte(basic), "v2.0.0-beta.15"}, true, false}, + {"basicmultiline", args{[]byte(multilineRequire), "v2.0.0-beta.15"}, true, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -91,49 +428,176 @@ func TestGoModOutOfSync(t *testing.T) { } } -const basicGo118 string = `module changeme +const multilineReplaceUpdated = `module changeme -go 1.18 +go 1.17 -require github.com/wailsapp/wails/v2 v2.0.0-beta.7 +require ( + github.com/wailsapp/wails/v2 v2.0.0-beta.15 +) + +require ( + github.com/andybalholm/brotli v1.0.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect + github.com/gabriel-vasile/mimetype v1.3.1 // indirect + github.com/go-ole/go-ole v1.2.5 // indirect + github.com/gofiber/fiber/v2 v2.17.0 // indirect + github.com/gofiber/websocket/v2 v2.0.8 // indirect + github.com/google/uuid v1.1.2 // indirect + github.com/imdario/mergo v0.3.12 // indirect + github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect + github.com/klauspost/compress v1.12.2 // indirect + github.com/leaanthony/debme v1.2.1 // indirect + github.com/leaanthony/go-ansi-parser v1.0.1 // indirect + github.com/leaanthony/go-common-file-dialog v1.0.3 // indirect + github.com/leaanthony/go-webview2 v0.0.0-20211007092718-65d2f028ef2d // indirect + github.com/leaanthony/gosod v1.0.3 // indirect + github.com/leaanthony/slicer v1.5.0 // indirect + github.com/leaanthony/typescriptify-golang-structs v0.1.7 // indirect + github.com/leaanthony/webview2runtime v1.1.0 // indirect + github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 // indirect + github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect + github.com/tkrajina/go-reflector v0.5.5 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.28.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect + golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect +) + +replace github.com/wailsapp/wails/v2 v2.0.0-beta.15 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2 +` +const multilineReplaceNoVersionUpdated = `module changeme + +go 1.17 + +require ( + github.com/wailsapp/wails/v2 v2.0.0-beta.15 +) + +require ( + github.com/andybalholm/brotli v1.0.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect + github.com/gabriel-vasile/mimetype v1.3.1 // indirect + github.com/go-ole/go-ole v1.2.5 // indirect + github.com/gofiber/fiber/v2 v2.17.0 // indirect + github.com/gofiber/websocket/v2 v2.0.8 // indirect + github.com/google/uuid v1.1.2 // indirect + github.com/imdario/mergo v0.3.12 // indirect + github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect + github.com/klauspost/compress v1.12.2 // indirect + github.com/leaanthony/debme v1.2.1 // indirect + github.com/leaanthony/go-ansi-parser v1.0.1 // indirect + github.com/leaanthony/go-common-file-dialog v1.0.3 // indirect + github.com/leaanthony/go-webview2 v0.0.0-20211007092718-65d2f028ef2d // indirect + github.com/leaanthony/gosod v1.0.3 // indirect + github.com/leaanthony/slicer v1.5.0 // indirect + github.com/leaanthony/typescriptify-golang-structs v0.1.7 // indirect + github.com/leaanthony/webview2runtime v1.1.0 // indirect + github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 // indirect + github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect + github.com/tkrajina/go-reflector v0.5.5 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.28.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect + golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect +) + +replace github.com/wailsapp/wails/v2 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2 +` +const multilineReplaceNoVersionBlockUpdated = `module changeme + +go 1.17 + +require ( + github.com/wailsapp/wails/v2 v2.0.0-beta.15 +) + +require ( + github.com/andybalholm/brotli v1.0.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect + github.com/gabriel-vasile/mimetype v1.3.1 // indirect + github.com/go-ole/go-ole v1.2.5 // indirect + github.com/gofiber/fiber/v2 v2.17.0 // indirect + github.com/gofiber/websocket/v2 v2.0.8 // indirect + github.com/google/uuid v1.1.2 // indirect + github.com/imdario/mergo v0.3.12 // indirect + github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect + github.com/klauspost/compress v1.12.2 // indirect + github.com/leaanthony/debme v1.2.1 // indirect + github.com/leaanthony/go-ansi-parser v1.0.1 // indirect + github.com/leaanthony/go-common-file-dialog v1.0.3 // indirect + github.com/leaanthony/go-webview2 v0.0.0-20211007092718-65d2f028ef2d // indirect + github.com/leaanthony/gosod v1.0.3 // indirect + github.com/leaanthony/slicer v1.5.0 // indirect + github.com/leaanthony/typescriptify-golang-structs v0.1.7 // indirect + github.com/leaanthony/webview2runtime v1.1.0 // indirect + github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 // indirect + github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect + github.com/tkrajina/go-reflector v0.5.5 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.28.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect + golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect +) + +replace ( + github.com/wailsapp/wails/v2 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2 +) ` -const basicGo119 string = `module changeme +const multilineReplaceBlockUpdated = `module changeme -go 1.19 +go 1.17 -require github.com/wailsapp/wails/v2 v2.0.0-beta.7 +require ( + github.com/wailsapp/wails/v2 v2.0.0-beta.15 +) + +require ( + github.com/andybalholm/brotli v1.0.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect + github.com/gabriel-vasile/mimetype v1.3.1 // indirect + github.com/go-ole/go-ole v1.2.5 // indirect + github.com/gofiber/fiber/v2 v2.17.0 // indirect + github.com/gofiber/websocket/v2 v2.0.8 // indirect + github.com/google/uuid v1.1.2 // indirect + github.com/imdario/mergo v0.3.12 // indirect + github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect + github.com/klauspost/compress v1.12.2 // indirect + github.com/leaanthony/debme v1.2.1 // indirect + github.com/leaanthony/go-ansi-parser v1.0.1 // indirect + github.com/leaanthony/go-common-file-dialog v1.0.3 // indirect + github.com/leaanthony/go-webview2 v0.0.0-20211007092718-65d2f028ef2d // indirect + github.com/leaanthony/gosod v1.0.3 // indirect + github.com/leaanthony/slicer v1.5.0 // indirect + github.com/leaanthony/typescriptify-golang-structs v0.1.7 // indirect + github.com/leaanthony/webview2runtime v1.1.0 // indirect + github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 // indirect + github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect + github.com/tkrajina/go-reflector v0.5.5 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.28.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect + golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect +) + +replace ( + github.com/wailsapp/wails/v2 v2.0.0-beta.15 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2 +) ` - -func TestUpdateGoModGoVersion(t *testing.T) { - is2 := is.New(t) - - type args struct { - goModText []byte - currentVersion string - } - tests := []struct { - name string - args args - want []byte - updated bool - }{ - {"basic1.18", args{[]byte(basicGo118), "1.18"}, []byte(basicGo118), false}, - {"basic1.19", args{[]byte(basicGo119), "1.17"}, []byte(basicGo119), false}, - {"basic1.19", args{[]byte(basicGo119), "1.18"}, []byte(basicGo119), false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, updated, err := SyncGoVersion(tt.args.goModText, tt.args.currentVersion) - if err != nil { - t.Errorf("UpdateGoModVersion() error = %v", err) - return - } - if updated != tt.updated { - t.Errorf("UpdateGoModVersion() updated = %t, want = %t", updated, tt.updated) - return - } - is2.Equal(got, tt.want) - }) - } -} diff --git a/v2/internal/goversion/build_constraint.go b/v2/internal/goversion/build_constraint.go deleted file mode 100644 index 5e1b9fcf5..000000000 --- a/v2/internal/goversion/build_constraint.go +++ /dev/null @@ -1,10 +0,0 @@ -//go:build !go1.18 -// +build !go1.18 - -package goversion - -const MinGoVersionRequired = "You need Go " + MinRequirement + " or newer to compile this program" - -func init() { - MinGoVersionRequired -} diff --git a/v2/internal/goversion/min.go b/v2/internal/goversion/min.go deleted file mode 100644 index 8c057b3c2..000000000 --- a/v2/internal/goversion/min.go +++ /dev/null @@ -1,3 +0,0 @@ -package goversion - -const MinRequirement string = "1.20" diff --git a/v2/internal/html/asset.go b/v2/internal/html/asset.go new file mode 100644 index 000000000..4c41358f4 --- /dev/null +++ b/v2/internal/html/asset.go @@ -0,0 +1,128 @@ +package html + +import ( + "fmt" + "io/ioutil" + "log" + "net/url" + "path/filepath" + "regexp" + "strings" + "unsafe" + + "github.com/tdewolff/minify" + "github.com/tdewolff/minify/js" +) + +type assetTypes struct { + JS string + CSS string + FAVICON string + HTML string +} + +// AssetTypes is an enum for the asset type keys +var AssetTypes *assetTypes = &assetTypes{ + JS: "javascript", + CSS: "css", + FAVICON: "favicon", + HTML: "html", +} + +// Asset describes an asset type and its path +type Asset struct { + Type string + Path string + Data string +} + +// Load the asset from disk +func (a *Asset) Load(basedirectory string) error { + assetpath := filepath.Join(basedirectory, a.Path) + data, err := ioutil.ReadFile(assetpath) + if err != nil { + return err + } + a.Data = string(data) + return nil +} + +// AsString returns the data as a READ ONLY string +func (a *Asset) AsString() string { + return a.Data +} + +func (a *Asset) minifiedData() (string, error) { + switch a.Type { + case AssetTypes.HTML: + + // Escape HTML + var re = regexp.MustCompile(`[\s]+`) + result := re.ReplaceAllString(a.Data, ` `) + + // Inject wailsloader code + result = strings.Replace(result, ``, ``, 1) + + url := url.URL{Path: result} + urlString := strings.ReplaceAll(url.String(), "/", "%2f") + + // Save Data uRI string + return "data:text/html;charset=utf-8," + urlString, nil + + case AssetTypes.CSS: + + // Escape CSS data + var re = regexp.MustCompile(`\s{2,}`) + result := re.ReplaceAllString(a.Data, ``) + result = strings.ReplaceAll(result, "\n", "") + result = strings.ReplaceAll(result, "\r\n", "") + result = strings.ReplaceAll(result, "\n", "") + result = strings.ReplaceAll(result, "\t", "") + result = strings.ReplaceAll(result, `\`, `\\`) + result = strings.ReplaceAll(result, `"`, `\"`) + result = strings.ReplaceAll(result, `'`, `\'`) + result = strings.ReplaceAll(result, ` {`, `{`) + result = strings.ReplaceAll(result, `: `, `:`) + return fmt.Sprintf("window.wails._.InjectCSS(\"%s\");", result), nil + + case AssetTypes.JS: + m := minify.New() + m.AddFunc("application/javascript", js.Minify) + var err error + result, err := m.String("application/javascript", a.Data+";") + if err != nil { + return "", err + } + return result, nil + default: + return "", fmt.Errorf("minification for asset type %s not implemented", a.Type) + } +} + +// AsCHexData processes the asset data so it may be used by C +func (a *Asset) AsCHexData() string { + dataString, err := a.minifiedData() + if err != nil { + log.Fatal(err) + } + // Get byte data of the string + bytes := *(*[]byte)(unsafe.Pointer(&dataString)) + + // Create a strings builder + var cdata strings.Builder + + // Set buffer size to 4k + cdata.Grow(4096) + + // Convert each byte to hex + for _, b := range bytes { + cdata.WriteString(fmt.Sprintf("0x%x, ", b)) + } + + return cdata.String() +} + +// Dump will output the asset to the terminal +func (a *Asset) Dump() { + fmt.Printf("{ Type: %s, Path: %s, Data: %+v }\n", a.Type, a.Path, a.Data[:10]) +} diff --git a/v2/internal/html/asset_test.go b/v2/internal/html/asset_test.go new file mode 100644 index 000000000..f743b4ba9 --- /dev/null +++ b/v2/internal/html/asset_test.go @@ -0,0 +1,53 @@ +package html + +import "testing" + +func TestAsset_minifiedData(t *testing.T) { + type fields struct { + Type string + Path string + Data string + } + tests := []struct { + name string + fields fields + want string + wantErr bool + }{ + { + name: "multi-line tag", + fields: fields{ + Type: AssetTypes.HTML, + Path: "foo.html", + Data: "\n", + }, + want: "data:text/html;charset=utf-8,%3Clink%20rel=%22stylesheet%22%20href=%22src%2ffoo.css%22%20%3E%20", + }, + { + name: "multi-line tag no spaces", + fields: fields{ + Type: AssetTypes.HTML, + Path: "foo.html", + Data: "\n", + }, + want: "data:text/html;charset=utf-8,%3Clink%20rel=%22stylesheet%22%20href=%22src%2ffoo.css%22%20%3E%20", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := &Asset{ + Type: tt.fields.Type, + Path: tt.fields.Path, + Data: tt.fields.Data, + } + got, err := a.minifiedData() + if (err != nil) != tt.wantErr { + t.Errorf("Asset.minifiedData() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("Asset.minifiedData() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/v2/internal/html/assetbundle.go b/v2/internal/html/assetbundle.go new file mode 100644 index 000000000..6ec098c7e --- /dev/null +++ b/v2/internal/html/assetbundle.go @@ -0,0 +1,218 @@ +package html + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "path/filepath" + "strings" + + "github.com/leaanthony/slicer" + "github.com/wailsapp/wails/v2/internal/assetdb" + "golang.org/x/net/html" +) + +// AssetBundle is a collection of Assets +type AssetBundle struct { + assets []*Asset + basedirectory string +} + +// NewAssetBundle creates a new AssetBundle struct containing +// the given html and all the assets referenced by it +func NewAssetBundle(pathToHTML string) (*AssetBundle, error) { + + // Create result + result := &AssetBundle{ + basedirectory: filepath.Dir(pathToHTML), + } + + err := result.loadAssets(pathToHTML) + if err != nil { + return nil, err + } + + return result, nil +} + +// loadAssets processes the given html file and loads in +// all referenced assets +func (a *AssetBundle) loadAssets(pathToHTML string) error { + + // Save HTML + htmlAsset := &Asset{ + Type: AssetTypes.HTML, + Path: filepath.Base(pathToHTML), + } + err := htmlAsset.Load(a.basedirectory) + if err != nil { + return err + } + a.assets = append(a.assets, htmlAsset) + + return a.processHTML(htmlAsset.AsString()) +} + +// Credit to: https://drstearns.github.io/tutorials/tokenizing/ +func (a *AssetBundle) processHTML(htmldata string) error { + + // Tokenize the html + buf := bytes.NewBufferString(htmldata) + tokenizer := html.NewTokenizer(buf) + + paths := slicer.String() + + for { + //get the next token type + tokenType := tokenizer.Next() + + //if it's an error token, we either reached + //the end of the file, or the HTML was malformed + if tokenType == html.ErrorToken { + err := tokenizer.Err() + if err == io.EOF { + //end of the file, break out of the loop + break + } + //otherwise, there was an error tokenizing, + //which likely means the HTML was malformed. + //since this is a simple command-line utility, + //we can just use log.Fatalf() to report the error + //and exit the process with a non-zero status code + return tokenizer.Err() + } + + //process the token according to the token type... + if tokenType == html.StartTagToken || tokenType == html.SelfClosingTagToken { + //get the token + token := tokenizer.Token() + + //if the name of the element is "title" + if "link" == token.Data { + //the next token should be the page title + tokenType = tokenizer.Next() + //just make sure it's actually a text token + asset := &Asset{} + for _, attr := range token.Attr { + // Favicon + if attr.Key == "rel" && attr.Val == "icon" { + asset.Type = AssetTypes.FAVICON + } + if attr.Key == "href" { + asset.Path = attr.Val + } + // standard stylesheet + if attr.Key == "rel" && attr.Val == "stylesheet" { + asset.Type = AssetTypes.CSS + } + if attr.Key == "as" && attr.Val == "style" { + asset.Type = AssetTypes.CSS + } + if attr.Key == "as" && attr.Val == "script" { + asset.Type = AssetTypes.JS + } + if attr.Key == "rel" && attr.Val == "modulepreload" { + asset.Type = AssetTypes.JS + } + } + + // Ensure we don't include duplicates + if !paths.Contains(asset.Path) { + err := asset.Load(a.basedirectory) + if err != nil { + return err + } + a.assets = append(a.assets, asset) + paths.Add(asset.Path) + } + } + if "script" == token.Data { + tokenType = tokenizer.Next() + //just make sure it's actually a text token + asset := &Asset{Type: AssetTypes.JS} + for _, attr := range token.Attr { + if attr.Key == "src" { + asset.Path = attr.Val + break + } + } + if !paths.Contains(asset.Path) && asset.Path != "" { + err := asset.Load(a.basedirectory) + if err != nil { + return err + } + a.assets = append(a.assets, asset) + paths.Add(asset.Path) + } + } + } + } + + return nil +} + +// WriteToCFile dumps all the assets to C files in the given directory +func (a *AssetBundle) WriteToCFile(targetDir string) (string, error) { + + // Write out the assets.c file + var cdata strings.Builder + + // Write header + header := `// assets.h +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL. +// This file was auto-generated. DO NOT MODIFY. + +` + cdata.WriteString(header) + + // Loop over the Assets + var err error + assetVariables := slicer.String() + var variableName string + for index, asset := range a.assets { + // For desktop we ignore the favicon + if asset.Type == AssetTypes.FAVICON { + continue + } + variableName = fmt.Sprintf("%s%d", asset.Type, index) + assetCdata := fmt.Sprintf("const unsigned char %s[]={ %s0x00 };\n", variableName, asset.AsCHexData()) + cdata.WriteString(assetCdata) + assetVariables.Add(variableName) + } + + if assetVariables.Length() > 0 { + cdata.WriteString(fmt.Sprintf("\nconst unsigned char *assets[] = { %s, 0x00 };", assetVariables.Join(", "))) + } else { + cdata.WriteString("\nconst unsigned char *assets[] = { 0x00 };") + } + + // Save file + assetsFile := filepath.Join(targetDir, "assets.h") + err = ioutil.WriteFile(assetsFile, []byte(cdata.String()), 0600) + if err != nil { + return "", err + } + return assetsFile, nil +} + +// ConvertToAssetDB returns an assetdb.AssetDB initialized with +// the items in the AssetBundle +func (a *AssetBundle) ConvertToAssetDB() (*assetdb.AssetDB, error) { + theassetdb := assetdb.NewAssetDB() + + // Loop over the Assets + for _, asset := range a.assets { + theassetdb.AddAsset(asset.Path, []byte(asset.Data)) + } + + return theassetdb, nil +} + +// Dump will output the assets to the terminal +func (a *AssetBundle) Dump() { + println("Assets:") + for _, asset := range a.assets { + asset.Dump() + } +} diff --git a/v2/internal/html/assetbundle_test.go b/v2/internal/html/assetbundle_test.go new file mode 100644 index 000000000..d1009d7ac --- /dev/null +++ b/v2/internal/html/assetbundle_test.go @@ -0,0 +1,84 @@ +package html + +import ( + "testing" +) + +func TestNewAssetBundle(t *testing.T) { + tests := []struct { + name string + pathToHTML string + wantAssets []string + wantErr bool + }{ + { + name: "basic html", + pathToHTML: "testdata/basic.html", + wantAssets: []string{ + AssetTypes.HTML, + AssetTypes.FAVICON, + AssetTypes.JS, + AssetTypes.CSS, + }, + wantErr: false, + }, + { + name: "self closing tags", + pathToHTML: "testdata/self_closing.html", + wantAssets: []string{ + AssetTypes.HTML, + AssetTypes.FAVICON, + AssetTypes.JS, + AssetTypes.CSS, + }, + wantErr: false, + }, + { + name: "multi-line tags", + pathToHTML: "testdata/self_closing.html", + wantAssets: []string{ + AssetTypes.HTML, + AssetTypes.FAVICON, + AssetTypes.JS, + AssetTypes.CSS, + }, + wantErr: false, + }, + { + name: "inline javascript", + pathToHTML: "testdata/inline_javascript.html", + wantAssets: []string{ + AssetTypes.HTML, + AssetTypes.FAVICON, + AssetTypes.JS, + AssetTypes.CSS, + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := NewAssetBundle(tt.pathToHTML) + if (err != nil) != tt.wantErr { + t.Errorf("NewAssetBundle() error = %v, wantErr %v", err, tt.wantErr) + return + } + if len(got.assets) != len(tt.wantAssets) { + t.Errorf("NewAssetBundle() len(assets) = %d, want %d", + len(got.assets), len(tt.wantAssets)) + } + + for i := range tt.wantAssets { + if i >= len(got.assets) { + t.Errorf("NewAssetBundle() missing assets[%d].Type = %s", + i, tt.wantAssets[i]) + } else { + if got.assets[i].Type != tt.wantAssets[i] { + t.Errorf("NewAssetBundle() assets[%d].Type = %s, want %s", + i, got.assets[i].Type, tt.wantAssets[i]) + } + } + } + }) + } +} diff --git a/v2/internal/html/testdata/basic.html b/v2/internal/html/testdata/basic.html new file mode 100644 index 000000000..cdc3770b8 --- /dev/null +++ b/v2/internal/html/testdata/basic.html @@ -0,0 +1,14 @@ + + + + + + + + + Vite App + + +
+ + diff --git a/v2/internal/html/testdata/inline_javascript.html b/v2/internal/html/testdata/inline_javascript.html new file mode 100644 index 000000000..4f97b75a9 --- /dev/null +++ b/v2/internal/html/testdata/inline_javascript.html @@ -0,0 +1,15 @@ + + + + + + + + + Vite App + + + +
+ + diff --git a/v2/internal/html/testdata/multi_line.html b/v2/internal/html/testdata/multi_line.html new file mode 100644 index 000000000..20ac33691 --- /dev/null +++ b/v2/internal/html/testdata/multi_line.html @@ -0,0 +1,17 @@ + + + + + + + + + Vite App + + +
+ + diff --git a/v2/internal/html/testdata/self_closing.html b/v2/internal/html/testdata/self_closing.html new file mode 100644 index 000000000..b5ee9bb78 --- /dev/null +++ b/v2/internal/html/testdata/self_closing.html @@ -0,0 +1,14 @@ + + + + + + + + + Vite App + + +
+ + diff --git a/v2/internal/html/testdata/src/bundle.js b/v2/internal/html/testdata/src/bundle.js new file mode 100644 index 000000000..105067a39 --- /dev/null +++ b/v2/internal/html/testdata/src/bundle.js @@ -0,0 +1 @@ +window.alert("I am JS!"); diff --git a/v2/internal/html/testdata/src/favicon.svg b/v2/internal/html/testdata/src/favicon.svg new file mode 100644 index 000000000..21bc4e85c --- /dev/null +++ b/v2/internal/html/testdata/src/favicon.svg @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/v2/internal/html/testdata/src/style.css b/v2/internal/html/testdata/src/style.css new file mode 100644 index 000000000..f5bd542b8 --- /dev/null +++ b/v2/internal/html/testdata/src/style.css @@ -0,0 +1,3 @@ +.body { + background: blue; +} diff --git a/v2/internal/logger/custom_logger.go b/v2/internal/logger/custom_logger.go index 51e07c0fc..5e24aa093 100644 --- a/v2/internal/logger/custom_logger.go +++ b/v2/internal/logger/custom_logger.go @@ -86,6 +86,7 @@ func (l *customLogger) Warning(format string, args ...interface{}) { func (l *customLogger) Error(format string, args ...interface{}) { format = fmt.Sprintf("%s | %s", l.name, format) l.logger.Error(format, args...) + } // Fatal level logging. Works like Sprintf. diff --git a/v2/internal/logger/default_logger.go b/v2/internal/logger/default_logger.go index 5c72ae209..fe5c05387 100644 --- a/v2/internal/logger/default_logger.go +++ b/v2/internal/logger/default_logger.go @@ -84,6 +84,7 @@ func (l *Logger) Info(format string, args ...interface{}) { if l.logLevel <= logger.INFO { l.output.Info(fmt.Sprintf(format, args...)) } + } // Warning level logging. Works like Sprintf. @@ -98,6 +99,7 @@ func (l *Logger) Error(format string, args ...interface{}) { if l.logLevel <= logger.ERROR { l.output.Error(fmt.Sprintf(format, args...)) } + } // Fatal level logging. Works like Sprintf. diff --git a/v2/internal/menumanager/applicationmenu.go b/v2/internal/menumanager/applicationmenu.go index 4446a00cb..424834e53 100644 --- a/v2/internal/menumanager/applicationmenu.go +++ b/v2/internal/menumanager/applicationmenu.go @@ -3,6 +3,7 @@ package menumanager import "github.com/wailsapp/wails/v2/pkg/menu" func (m *Manager) SetApplicationMenu(applicationMenu *menu.Menu) error { + if applicationMenu == nil { return nil } @@ -37,6 +38,7 @@ func (m *Manager) UpdateApplicationMenu() (string, error) { } func (m *Manager) processApplicationMenu() error { + // Process the menu m.processedApplicationMenu = NewWailsMenu(m.applicationMenuItemMap, m.applicationMenu) m.processRadioGroups(m.processedApplicationMenu, m.applicationMenuItemMap) diff --git a/v2/internal/menumanager/contextmenu.go b/v2/internal/menumanager/contextmenu.go index f05bcdc49..e07cc2222 100644 --- a/v2/internal/menumanager/contextmenu.go +++ b/v2/internal/menumanager/contextmenu.go @@ -3,7 +3,6 @@ package menumanager import ( "encoding/json" "fmt" - "github.com/wailsapp/wails/v2/pkg/menu" ) @@ -23,6 +22,7 @@ func (t *ContextMenu) AsJSON() (string, error) { } func NewContextMenu(contextMenu *menu.ContextMenu) *ContextMenu { + result := &ContextMenu{ ID: contextMenu.ID, menu: contextMenu.Menu, @@ -36,6 +36,7 @@ func NewContextMenu(contextMenu *menu.ContextMenu) *ContextMenu { } func (m *Manager) AddContextMenu(contextMenu *menu.ContextMenu) { + newContextMenu := NewContextMenu(contextMenu) // Save the references diff --git a/v2/internal/menumanager/menuitemmap.go b/v2/internal/menumanager/menuitemmap.go index e4e291be6..790d5d06d 100644 --- a/v2/internal/menumanager/menuitemmap.go +++ b/v2/internal/menumanager/menuitemmap.go @@ -2,10 +2,8 @@ package menumanager import ( "fmt" - "strconv" - "sync" - "github.com/wailsapp/wails/v2/pkg/menu" + "sync" ) // MenuItemMap holds a mapping between menuIDs and menu items @@ -50,13 +48,14 @@ func (m *MenuItemMap) Dump() { // GenerateMenuID returns a unique string ID for a menu item func (m *MenuItemMap) generateMenuID() string { m.menuIDCounterMutex.Lock() - result := strconv.FormatInt(m.menuIDCounter, 10) + result := fmt.Sprintf("%d", m.menuIDCounter) m.menuIDCounter++ m.menuIDCounterMutex.Unlock() return result } func (m *MenuItemMap) processMenuItem(item *menu.MenuItem) { + if item.SubMenu != nil { for _, submenuitem := range item.SubMenu.Items { m.processMenuItem(submenuitem) diff --git a/v2/internal/menumanager/menumanager.go b/v2/internal/menumanager/menumanager.go index 0c6be0df2..ea7939415 100644 --- a/v2/internal/menumanager/menumanager.go +++ b/v2/internal/menumanager/menumanager.go @@ -2,11 +2,11 @@ package menumanager import ( "fmt" - "github.com/wailsapp/wails/v2/pkg/menu" ) type Manager struct { + // The application menu. applicationMenu *menu.Menu applicationMenuJSON string @@ -43,6 +43,7 @@ func (m *Manager) getMenuItemByID(menuMap *MenuItemMap, menuId string) *menu.Men } func (m *Manager) ProcessClick(menuID string, data string, menuType string, parentID string) error { + var menuItemMap *MenuItemMap switch menuType { @@ -92,7 +93,7 @@ func (m *Manager) ProcessClick(menuID string, data string, menuType string, pare // Create new Callback struct callbackData := &menu.CallbackData{ MenuItem: menuItem, - // ContextData: data, + //ContextData: data, } // Call back! diff --git a/v2/internal/menumanager/processedMenu.go b/v2/internal/menumanager/processedMenu.go index c87646ccb..2722f86cd 100644 --- a/v2/internal/menumanager/processedMenu.go +++ b/v2/internal/menumanager/processedMenu.go @@ -2,7 +2,6 @@ package menumanager import ( "encoding/json" - "github.com/wailsapp/wails/v2/pkg/menu" "github.com/wailsapp/wails/v2/pkg/menu/keys" ) @@ -12,7 +11,7 @@ type ProcessedMenuItem struct { // Label is what appears as the menu text Label string `json:",omitempty"` // Role is a predefined menu type - // Role menu.Role `json:",omitempty"` + //Role menu.Role `json:",omitempty"` // Accelerator holds a representation of a key binding Accelerator *keys.Accelerator `json:",omitempty"` // Type of MenuItem, EG: Checkbox, Text, Separator, Radio, Submenu @@ -23,8 +22,8 @@ type ProcessedMenuItem struct { Hidden bool `json:",omitempty"` // Checked indicates if the item is selected (used by Checkbox and Radio types only) Checked bool `json:",omitempty"` - // SubMenu contains a list of menu items that will be shown as a submenu - // SubMenu []*MenuItem `json:"SubMenu,omitempty"` + // Submenu contains a list of menu items that will be shown as a submenu + //SubMenu []*MenuItem `json:"SubMenu,omitempty"` SubMenu *ProcessedMenu `json:",omitempty"` /* // Colour @@ -48,6 +47,7 @@ type ProcessedMenuItem struct { } func NewProcessedMenuItem(menuItemMap *MenuItemMap, menuItem *menu.MenuItem) *ProcessedMenuItem { + ID := menuItemMap.menuItemToIDMap[menuItem] // Parse ANSI text @@ -63,21 +63,21 @@ func NewProcessedMenuItem(menuItemMap *MenuItemMap, menuItem *menu.MenuItem) *Pr result := &ProcessedMenuItem{ ID: ID, Label: menuItem.Label, - // Role: menuItem.Role, + //Role: menuItem.Role, Accelerator: menuItem.Accelerator, Type: menuItem.Type, Disabled: menuItem.Disabled, Hidden: menuItem.Hidden, Checked: menuItem.Checked, SubMenu: nil, - // BackgroundColour: menuItem.BackgroundColour, - // FontSize: menuItem.FontSize, - // FontName: menuItem.FontName, - // Image: menuItem.Image, - // MacTemplateImage: menuItem.MacTemplateImage, - // MacAlternate: menuItem.MacAlternate, - // Tooltip: menuItem.Tooltip, - // StyledLabel: styledLabel, + //RGBA: menuItem.RGBA, + //FontSize: menuItem.FontSize, + //FontName: menuItem.FontName, + //Image: menuItem.Image, + //MacTemplateImage: menuItem.MacTemplateImage, + //MacAlternate: menuItem.MacAlternate, + //Tooltip: menuItem.Tooltip, + //StyledLabel: styledLabel, } if menuItem.SubMenu != nil { @@ -92,6 +92,7 @@ type ProcessedMenu struct { } func NewProcessedMenu(menuItemMap *MenuItemMap, menu *menu.Menu) *ProcessedMenu { + result := &ProcessedMenu{} if menu != nil { for _, item := range menu.Items { @@ -130,6 +131,7 @@ func NewWailsMenu(menuItemMap *MenuItemMap, menu *menu.Menu) *WailsMenu { } func (w *WailsMenu) AsJSON() (string, error) { + menuAsJSON, err := json.Marshal(w) if err != nil { return "", err @@ -148,6 +150,7 @@ func (w *WailsMenu) processRadioGroups() { } func (w *WailsMenu) processMenuItem(item *ProcessedMenuItem) { + switch item.Type { // We need to recurse submenus @@ -169,6 +172,7 @@ func (w *WailsMenu) processMenuItem(item *ProcessedMenuItem) { } func (w *WailsMenu) finaliseRadioGroup() { + // If we were processing a radio group, fix up the references if len(w.currentRadioGroup) > 0 { diff --git a/v2/internal/menumanager/traymenu.go b/v2/internal/menumanager/traymenu.go index 5efc4a861..aed5b05ac 100644 --- a/v2/internal/menumanager/traymenu.go +++ b/v2/internal/menumanager/traymenu.go @@ -13,10 +13,8 @@ import ( "github.com/wailsapp/wails/v2/pkg/menu" ) -var ( - trayMenuID int - trayMenuIDMutex sync.Mutex -) +var trayMenuID int +var trayMenuIDMutex sync.Mutex func generateTrayID() string { var idStr string @@ -53,6 +51,7 @@ func (t *TrayMenu) AsJSON() (string, error) { } func NewTrayMenu(trayMenu *menu.TrayMenu) *TrayMenu { + // Parse ANSI text var styledLabel []*ansi.StyledText tempLabel := trayMenu.Label @@ -206,6 +205,7 @@ func (m *Manager) UpdateTrayMenuLabel(trayMenu *menu.TrayMenu) (string, error) { } return string(data), nil + } func (m *Manager) GetContextMenus() ([]string, error) { diff --git a/v2/internal/messagedispatcher/dispatchclient.go b/v2/internal/messagedispatcher/dispatchclient.go new file mode 100644 index 000000000..af693660c --- /dev/null +++ b/v2/internal/messagedispatcher/dispatchclient.go @@ -0,0 +1,89 @@ +package messagedispatcher + +import ( + "fmt" + "github.com/wailsapp/wails/v2/pkg/runtime" + + "github.com/wailsapp/wails/v2/internal/logger" + "github.com/wailsapp/wails/v2/internal/messagedispatcher/message" + "github.com/wailsapp/wails/v2/internal/servicebus" +) + +// Client defines what a frontend client can do +type Client interface { + Quit() + NotifyEvent(message string) + CallResult(message string) + OpenFileDialog(dialogOptions runtime.OpenDialogOptions, callbackID string) + OpenMultipleFilesDialog(dialogOptions runtime.OpenDialogOptions, callbackID string) + OpenDirectoryDialog(dialogOptions runtime.OpenDialogOptions, callbackID string) + SaveDialog(dialogOptions runtime.SaveDialogOptions, callbackID string) + MessageDialog(dialogOptions runtime.MessageDialogOptions, callbackID string) + WindowSetTitle(title string) + WindowShow() + WindowHide() + WindowCenter() + WindowMaximise() + WindowUnmaximise() + WindowMinimise() + WindowUnminimise() + WindowPosition(x int, y int) + WindowSize(width int, height int) + WindowSetMinSize(width int, height int) + WindowSetMaxSize(width int, height int) + WindowFullscreen() + WindowUnFullscreen() + WindowSetColour(colour int) + DarkModeEnabled(callbackID string) + SetApplicationMenu(menuJSON string) + SetTrayMenu(trayMenuJSON string) + UpdateTrayMenuLabel(JSON string) + UpdateContextMenu(contextMenuJSON string) + DeleteTrayMenuByID(id string) +} + +// DispatchClient is what the frontends use to interface with the +// dispatcher +type DispatchClient struct { + id string + logger logger.CustomLogger + + bus *servicebus.ServiceBus + + // Client + frontend Client +} + +func newDispatchClient(id string, frontend Client, logger logger.CustomLogger, bus *servicebus.ServiceBus) *DispatchClient { + + return &DispatchClient{ + id: id, + frontend: frontend, + logger: logger, + bus: bus, + } + +} + +// DispatchMessage is called by the front ends. It is passed +// an IPC message, translates it to a more concrete message +// type then publishes it on the service bus. +func (d *DispatchClient) DispatchMessage(incomingMessage string) { + + // Parse the message + d.logger.Trace(fmt.Sprintf("Received message: %+v", incomingMessage)) + parsedMessage, err := message.Parse(incomingMessage) + if err != nil { + d.logger.Error(err.Error()) + return + } + + // Save this client id + parsedMessage.ClientID = d.id + + d.logger.Trace("I got a parsedMessage: %+v", parsedMessage) + + // Publish the parsed message + d.bus.PublishForTarget(parsedMessage.Topic, parsedMessage.Data, d.id) + +} diff --git a/v2/internal/messagedispatcher/message/call.go b/v2/internal/messagedispatcher/message/call.go new file mode 100644 index 000000000..946e00a93 --- /dev/null +++ b/v2/internal/messagedispatcher/message/call.go @@ -0,0 +1,38 @@ +package message + +import ( + "encoding/json" + "fmt" +) + +type CallMessage struct { + Name string `json:"name"` + Args []json.RawMessage `json:"args"` + CallbackID string `json:"callbackID,omitempty"` +} + +// callMessageParser does what it says on the tin! +func callMessageParser(message string) (*parsedMessage, error) { + + // Sanity check: Call messages must be at least 3 bytes `C{}`` + if len(message) < 3 { + return nil, fmt.Errorf("call message was an invalid length") + } + + callMessage := new(CallMessage) + + m := message[1:] + + err := json.Unmarshal([]byte(m), callMessage) + if err != nil { + println(err.Error()) + return nil, err + } + + topic := "call:invoke" + + // Create a new parsed message struct + parsedMessage := &parsedMessage{Topic: topic, Data: callMessage} + + return parsedMessage, nil +} diff --git a/v2/internal/messagedispatcher/message/contextmenus.go b/v2/internal/messagedispatcher/message/contextmenus.go new file mode 100644 index 000000000..53acebd0e --- /dev/null +++ b/v2/internal/messagedispatcher/message/contextmenus.go @@ -0,0 +1,43 @@ +package message + +import ( + "fmt" + + "github.com/wailsapp/wails/v2/pkg/menu" +) + +// ContextMenusOnMessage is used to emit listener registration requests +// on the service bus +type ContextMenusOnMessage struct { + // MenuID is the id of the menu item we are interested in + MenuID string + // Callback is called when the menu is clicked + Callback func(*menu.MenuItem, string) +} + +// contextMenusMessageParser does what it says on the tin! +func contextMenusMessageParser(message string) (*parsedMessage, error) { + + // Sanity check: Menu messages must be at least 2 bytes + if len(message) < 3 { + return nil, fmt.Errorf("context menus message was an invalid length") + } + + var topic string + var data interface{} + + // Switch the message type + switch message[1] { + case 'C': + contextMenuData := message[2:] + topic = "contextmenus:clicked" + data = contextMenuData + default: + return nil, fmt.Errorf("invalid menu message: %s", message) + } + + // Create a new parsed message struct + parsedMessage := &parsedMessage{Topic: topic, Data: data} + + return parsedMessage, nil +} diff --git a/v2/internal/messagedispatcher/message/dialog.go b/v2/internal/messagedispatcher/message/dialog.go new file mode 100644 index 000000000..5fcc63d30 --- /dev/null +++ b/v2/internal/messagedispatcher/message/dialog.go @@ -0,0 +1,61 @@ +package message + +import ( + "encoding/json" + "fmt" + "strings" +) + +// dialogMessageParser does what it says on the tin! +func dialogMessageParser(message string) (*parsedMessage, error) { + + // Sanity check: Dialog messages must be at least 4 bytes + if len(message) < 4 { + return nil, fmt.Errorf("dialog message was an invalid length") + } + + var topic = "bad topic from dialogMessageParser" + var responseMessage *parsedMessage + + // Switch the event type (with or without data) + switch message[0] { + // Format of Dialog response messages: D|<[]string as json encoded string> + case 'D': + dialogType := message[1] + message = message[2:] + idx := strings.IndexByte(message, '|') + if idx < 0 { + return nil, fmt.Errorf("Invalid dialog response message format: %+v", message) + } + callbackID := message[:idx] + payloadData := message[idx+1:] + + switch dialogType { + case 'O': + topic = "dialog:openselected:" + callbackID + responseMessage = &parsedMessage{Topic: topic, Data: payloadData} + case 'D': + topic = "dialog:opendirectoryselected:" + callbackID + responseMessage = &parsedMessage{Topic: topic, Data: payloadData} + case '*': + var data []string + topic = "dialog:openmultipleselected:" + callbackID + err := json.Unmarshal([]byte(payloadData), &data) + if err != nil { + return nil, err + } + responseMessage = &parsedMessage{Topic: topic, Data: data} + case 'S': + topic = "dialog:saveselected:" + callbackID + responseMessage = &parsedMessage{Topic: topic, Data: payloadData} + case 'M': + topic = "dialog:messageselected:" + callbackID + responseMessage = &parsedMessage{Topic: topic, Data: payloadData} + } + + default: + return nil, fmt.Errorf("Invalid message to dialogMessageParser()") + } + + return responseMessage, nil +} diff --git a/v2/internal/messagedispatcher/message/event.go b/v2/internal/messagedispatcher/message/event.go new file mode 100644 index 000000000..dcb133e48 --- /dev/null +++ b/v2/internal/messagedispatcher/message/event.go @@ -0,0 +1,47 @@ +package message + +import ( + "encoding/json" + "fmt" +) + +type EventMessage struct { + Name string `json:"name"` + Data []interface{} `json:"data"` +} + +type OnEventMessage struct { + Name string + Callback func(optionalData ...interface{}) + Counter int +} + +// eventMessageParser does what it says on the tin! +func eventMessageParser(message string) (*parsedMessage, error) { + + // Sanity check: Event messages must be at least 2 bytes + if len(message) < 3 { + return nil, fmt.Errorf("event message was an invalid length") + } + + eventMessage := new(EventMessage) + direction := message[1] + + // Switch the event type (with or without data) + switch message[0] { + case 'E': + m := message[2:] + err := json.Unmarshal([]byte(m), eventMessage) + if err != nil { + println(err.Error()) + return nil, err + } + } + + topic := "event:emit:from:" + string(direction) + + // Create a new parsed message struct + parsedMessage := &parsedMessage{Topic: topic, Data: eventMessage} + + return parsedMessage, nil +} diff --git a/v2/internal/messagedispatcher/message/log.go b/v2/internal/messagedispatcher/message/log.go new file mode 100644 index 000000000..9b24fc5a1 --- /dev/null +++ b/v2/internal/messagedispatcher/message/log.go @@ -0,0 +1,36 @@ +package message + +import "fmt" + +var logMessageMap = map[byte]string{ + 'P': "log:print", + 'T': "log:trace", + 'D': "log:debug", + 'I': "log:info", + 'W': "log:warning", + 'E': "log:error", + 'F': "log:fatal", + 'S': "log:setlevel", +} + +// logMessageParser does what it says on the tin! +func logMessageParser(message string) (*parsedMessage, error) { + + // Sanity check: Log messages must be at least 2 bytes + if len(message) < 2 { + return nil, fmt.Errorf("log message was an invalid length") + } + + // Switch on the log type + messageTopic := logMessageMap[message[1]] + + // If the type is invalid, raise error + if messageTopic == "" { + return nil, fmt.Errorf("log message type '%c' invalid", message[1]) + } + + // Create a new parsed message struct + parsedMessage := &parsedMessage{Topic: messageTopic, Data: message[2:]} + + return parsedMessage, nil +} diff --git a/v2/internal/messagedispatcher/message/menu.go b/v2/internal/messagedispatcher/message/menu.go new file mode 100644 index 000000000..483865fb9 --- /dev/null +++ b/v2/internal/messagedispatcher/message/menu.go @@ -0,0 +1,51 @@ +package message + +import ( + "fmt" + + "github.com/wailsapp/wails/v2/pkg/menu" +) + +// MenuOnMessage is used to emit listener registration requests +// on the service bus +type MenuOnMessage struct { + // MenuID is the id of the menu item we are interested in + MenuID string + // Callback is called when the menu is clicked + Callback func(*menu.MenuItem) +} + +// menuMessageParser does what it says on the tin! +func menuMessageParser(message string) (*parsedMessage, error) { + + // Sanity check: Menu messages must be at least 2 bytes + if len(message) < 3 { + return nil, fmt.Errorf("event message was an invalid length") + } + + var topic string + var data interface{} + + // Switch the message type + switch message[1] { + case 'C': + callbackid := message[2:] + topic = "menu:clicked" + data = callbackid + case 'o': + callbackid := message[2:] + topic = "menu:ontrayopen" + data = callbackid + case 'c': + callbackid := message[2:] + topic = "menu:ontrayclose" + data = callbackid + default: + return nil, fmt.Errorf("invalid menu message: %s", message) + } + + // Create a new parsed message struct + parsedMessage := &parsedMessage{Topic: topic, Data: data} + + return parsedMessage, nil +} diff --git a/v2/internal/messagedispatcher/message/messageparser.go b/v2/internal/messagedispatcher/message/messageparser.go new file mode 100644 index 000000000..362070b0b --- /dev/null +++ b/v2/internal/messagedispatcher/message/messageparser.go @@ -0,0 +1,40 @@ +package message + +import "fmt" + +// Parse +type parsedMessage struct { + Topic string + ClientID string + Data interface{} +} + +// Map of different message parsers based on the header byte of the message +var messageParsers = map[byte]func(string) (*parsedMessage, error){ + 'L': logMessageParser, + 'R': runtimeMessageParser, + 'E': eventMessageParser, + 'C': callMessageParser, + 'W': windowMessageParser, + 'D': dialogMessageParser, + 'S': systemMessageParser, + 'M': menuMessageParser, + 'T': trayMessageParser, + 'X': contextMenusMessageParser, + 'U': urlMessageParser, +} + +// Parse will attempt to parse the given message +func Parse(message string) (*parsedMessage, error) { + + if len(message) == 0 { + return nil, fmt.Errorf("MessageParser received blank message") + } + + parseMethod := messageParsers[message[0]] + if parseMethod == nil { + return nil, fmt.Errorf("message type '%c' invalid", message[0]) + } + + return parseMethod(message) +} diff --git a/v2/internal/messagedispatcher/message/runtime.go b/v2/internal/messagedispatcher/message/runtime.go new file mode 100644 index 000000000..fc3a44258 --- /dev/null +++ b/v2/internal/messagedispatcher/message/runtime.go @@ -0,0 +1,37 @@ +package message + +import "fmt" + +// runtimeMessageParser does what it says on the tin! +func runtimeMessageParser(message string) (*parsedMessage, error) { + + // Sanity check: Log messages must be at least 2 bytes + if len(message) < 3 { + return nil, fmt.Errorf("runtime message was an invalid length") + } + + // Switch on the runtime module type + module := message[1] + switch module { + case 'B': + return processBrowserMessage(message) + } + + return nil, fmt.Errorf("unknown message: %s", message) +} + +// processBrowserMessage expects messages of the following format: +// RB +// O = Open +func processBrowserMessage(message string) (*parsedMessage, error) { + method := message[2] + switch method { + case 'O': + // Open URL + target := message[3:] + return &parsedMessage{Topic: "runtime:browser:open", Data: target}, nil + } + + return nil, fmt.Errorf("unknown browser message: %s", message) + +} diff --git a/v2/internal/messagedispatcher/message/system.go b/v2/internal/messagedispatcher/message/system.go new file mode 100644 index 000000000..1bda75140 --- /dev/null +++ b/v2/internal/messagedispatcher/message/system.go @@ -0,0 +1,50 @@ +package message + +import ( + "fmt" + "strings" +) + +// systemMessageParser does what it says on the tin! +func systemMessageParser(message string) (*parsedMessage, error) { + + // Sanity check: system messages must be at least 2 bytes + if len(message) < 2 { + return nil, fmt.Errorf("system message was an invalid length") + } + + var responseMessage *parsedMessage + + // Remove 'S' + message = message[1:] + + // Switch the event type (with or without data) + switch message[0] { + // Format of system response messages: S| + // DarkModeEnabled + case 'D': + if len(message) < 4 { + return nil, fmt.Errorf("system message was an invalid length") + } + message = message[1:] + idx := strings.IndexByte(message, '|') + if idx < 0 { + return nil, fmt.Errorf("Invalid system response message format") + } + callbackID := message[:idx] + payloadData := message[idx+1:] + + topic := "systemresponse:" + callbackID + responseMessage = &parsedMessage{Topic: topic, Data: payloadData == "T"} + + // This is our startup hook - the frontend is now ready + case 'S': + topic := "hooks:startup" + startupURL := message[1:] + responseMessage = &parsedMessage{Topic: topic, Data: startupURL} + default: + return nil, fmt.Errorf("Invalid message to systemMessageParser()") + } + + return responseMessage, nil +} diff --git a/v2/internal/messagedispatcher/message/tray.go b/v2/internal/messagedispatcher/message/tray.go new file mode 100644 index 000000000..ac1cde8ed --- /dev/null +++ b/v2/internal/messagedispatcher/message/tray.go @@ -0,0 +1,46 @@ +package message + +import ( + "fmt" + + "github.com/wailsapp/wails/v2/pkg/menu" +) + +// TrayOnMessage is used to emit listener registration requests +// on the service bus +type TrayOnMessage struct { + // MenuID is the id of the menu item we are interested in + MenuID string + // Callback is called when the menu is clicked + Callback func(*menu.MenuItem) +} + +// trayMessageParser does what it says on the tin! +func trayMessageParser(message string) (*parsedMessage, error) { + + // Sanity check: Menu messages must be at least 2 bytes + if len(message) < 3 { + return nil, fmt.Errorf("tray message was an invalid length") + } + + var topic string + var data interface{} + + // Switch the message type + switch message[1] { + case 'C': + callbackid := message[2:] + topic = "tray:clicked" + data = callbackid + case 'I': + topic = "trayfrontend:seticon" + data = message[2:] + default: + return nil, fmt.Errorf("invalid tray message: %s", message) + } + + // Create a new parsed message struct + parsedMessage := &parsedMessage{Topic: topic, Data: data} + + return parsedMessage, nil +} diff --git a/v2/internal/messagedispatcher/message/url.go b/v2/internal/messagedispatcher/message/url.go new file mode 100644 index 000000000..1bdc2f903 --- /dev/null +++ b/v2/internal/messagedispatcher/message/url.go @@ -0,0 +1,20 @@ +package message + +import "fmt" + +// urlMessageParser does what it says on the tin! +func urlMessageParser(message string) (*parsedMessage, error) { + + // Sanity check: URL messages must be at least 2 bytes + if len(message) < 2 { + return nil, fmt.Errorf("log message was an invalid length") + } + + // Switch on the log type + switch message[1] { + case 'C': + return &parsedMessage{Topic: "url:handler", Data: message[2:]}, nil + default: + return nil, fmt.Errorf("url message type '%c' invalid", message[1]) + } +} diff --git a/v2/internal/messagedispatcher/message/window.go b/v2/internal/messagedispatcher/message/window.go new file mode 100644 index 000000000..e31353fac --- /dev/null +++ b/v2/internal/messagedispatcher/message/window.go @@ -0,0 +1,91 @@ +package message + +import "fmt" + +// windowMessageParser does what it says on the tin! +func windowMessageParser(message string) (*parsedMessage, error) { + + // Sanity check: Window messages must be at least 2 bytes + if len(message) < 2 { + return nil, fmt.Errorf("window message was an invalid length") + } + + // Extract event type + windowEvent := message[1] + parsedMessage := &parsedMessage{} + + // Switch the windowEvent type + switch windowEvent { + + // Closed window + case 'C': + parsedMessage.Topic = "quit" + parsedMessage.Data = "Window Closed" + + // Center window + case 'c': + parsedMessage.Topic = "window:center" + parsedMessage.Data = "" + + // Hide window + case 'H': + parsedMessage.Topic = "window:hide" + parsedMessage.Data = "" + + // Show window + case 'S': + parsedMessage.Topic = "window:show" + parsedMessage.Data = "" + + // Position window + case 'p': + parsedMessage.Topic = "window:position:" + message[3:] + parsedMessage.Data = "" + + // Set window size + case 's': + parsedMessage.Topic = "window:size:" + message[3:] + parsedMessage.Data = "" + + // Maximise window + case 'M': + parsedMessage.Topic = "window:maximise" + parsedMessage.Data = "" + + // Unmaximise window + case 'U': + parsedMessage.Topic = "window:unmaximise" + parsedMessage.Data = "" + + // Minimise window + case 'm': + parsedMessage.Topic = "window:minimise" + parsedMessage.Data = "" + + // Unminimise window + case 'u': + parsedMessage.Topic = "window:unminimise" + parsedMessage.Data = "" + + // Fullscreen window + case 'F': + parsedMessage.Topic = "window:fullscreen" + parsedMessage.Data = "" + + // UnFullscreen window + case 'f': + parsedMessage.Topic = "window:unfullscreen" + parsedMessage.Data = "" + + // Set Title + case 'T': + parsedMessage.Topic = "window:settitle" + parsedMessage.Data = message[2:] + + // Unknown event type + default: + return nil, fmt.Errorf("unknown message: %s", message) + } + + return parsedMessage, nil +} diff --git a/v2/internal/messagedispatcher/messagedispatcher.go b/v2/internal/messagedispatcher/messagedispatcher.go new file mode 100644 index 000000000..55828b0da --- /dev/null +++ b/v2/internal/messagedispatcher/messagedispatcher.go @@ -0,0 +1,577 @@ +package messagedispatcher + +import ( + "context" + "encoding/json" + "github.com/wailsapp/wails/v2/pkg/runtime" + "strconv" + "strings" + "sync" + + "github.com/wailsapp/wails/v2/internal/crypto" + "github.com/wailsapp/wails/v2/internal/logger" + "github.com/wailsapp/wails/v2/internal/messagedispatcher/message" + "github.com/wailsapp/wails/v2/internal/servicebus" +) + +// Dispatcher translates messages received from the frontend +// and publishes them onto the service bus +type Dispatcher struct { + quitChannel <-chan *servicebus.Message + resultChannel <-chan *servicebus.Message + eventChannel <-chan *servicebus.Message + windowChannel <-chan *servicebus.Message + dialogChannel <-chan *servicebus.Message + systemChannel <-chan *servicebus.Message + menuChannel <-chan *servicebus.Message + + servicebus *servicebus.ServiceBus + logger logger.CustomLogger + + // Clients + clients map[string]*DispatchClient + lock sync.RWMutex + + // Context for cancellation + ctx context.Context + cancel context.CancelFunc + + // internal wait group + wg sync.WaitGroup +} + +// New dispatcher. Needs a service bus to send to. +func New(servicebus *servicebus.ServiceBus, logger *logger.Logger) (*Dispatcher, error) { + // Subscribe to call result messages + resultChannel, err := servicebus.Subscribe("call:result") + if err != nil { + return nil, err + } + + // Subscribe to event messages + eventChannel, err := servicebus.Subscribe("event:emit") + if err != nil { + return nil, err + } + + // Subscribe to quit messages + quitChannel, err := servicebus.Subscribe("quit") + if err != nil { + return nil, err + } + + // Subscribe to window messages + windowChannel, err := servicebus.Subscribe("window") + if err != nil { + return nil, err + } + + // Subscribe to dialog events + dialogChannel, err := servicebus.Subscribe("dialog:select") + if err != nil { + return nil, err + } + + systemChannel, err := servicebus.Subscribe("system:") + if err != nil { + return nil, err + } + + menuChannel, err := servicebus.Subscribe("menufrontend:") + if err != nil { + return nil, err + } + + // Create context + ctx, cancel := context.WithCancel(context.Background()) + + result := &Dispatcher{ + servicebus: servicebus, + eventChannel: eventChannel, + logger: logger.CustomLogger("Message Dispatcher"), + clients: make(map[string]*DispatchClient), + resultChannel: resultChannel, + quitChannel: quitChannel, + windowChannel: windowChannel, + dialogChannel: dialogChannel, + systemChannel: systemChannel, + menuChannel: menuChannel, + ctx: ctx, + cancel: cancel, + } + + return result, nil +} + +// Start the subsystem +func (d *Dispatcher) Start() error { + + d.logger.Trace("Starting") + + d.wg.Add(1) + + // Spin off a go routine + go func() { + defer d.logger.Trace("Shutdown") + for { + select { + case <-d.ctx.Done(): + d.wg.Done() + return + case <-d.quitChannel: + d.processQuit() + case resultMessage := <-d.resultChannel: + d.processCallResult(resultMessage) + case eventMessage := <-d.eventChannel: + d.processEvent(eventMessage) + case windowMessage := <-d.windowChannel: + d.processWindowMessage(windowMessage) + case dialogMessage := <-d.dialogChannel: + d.processDialogMessage(dialogMessage) + case systemMessage := <-d.systemChannel: + d.processSystemMessage(systemMessage) + case menuMessage := <-d.menuChannel: + d.processMenuMessage(menuMessage) + } + } + }() + + return nil +} + +func (d *Dispatcher) processQuit() { + d.lock.RLock() + defer d.lock.RUnlock() + for _, client := range d.clients { + client.frontend.Quit() + } +} + +// RegisterClient will register the given callback with the dispatcher +// and return a DispatchClient that the caller can use to send messages +func (d *Dispatcher) RegisterClient(client Client) *DispatchClient { + d.lock.Lock() + defer d.lock.Unlock() + + // Create ID + id := d.getUniqueID() + d.clients[id] = newDispatchClient(id, client, d.logger, d.servicebus) + + return d.clients[id] +} + +// RemoveClient will remove the registered client +func (d *Dispatcher) RemoveClient(dc *DispatchClient) { + d.lock.Lock() + defer d.lock.Unlock() + delete(d.clients, dc.id) +} + +func (d *Dispatcher) getUniqueID() string { + var uid string + for { + uid = crypto.RandomID() + + if d.clients[uid] == nil { + break + } + } + + return uid +} + +func (d *Dispatcher) processCallResult(result *servicebus.Message) { + target := result.Target() + + if target == "" { + // This is an error. Calls are 1:1! + d.logger.Fatal("No target for call result: %+v", result) + } + + d.lock.RLock() + client := d.clients[target] + d.lock.RUnlock() + if client == nil { + // This is fatal - unknown target! + d.logger.Fatal("Unknown target for call result: %+v", result) + return + } + + d.logger.Trace("Sending message to client %s: R%s", target, result.Data().(string)) + client.frontend.CallResult(result.Data().(string)) +} + +// processSystem +func (d *Dispatcher) processSystemMessage(result *servicebus.Message) { + + d.logger.Trace("Got system in message dispatcher: %+v", result) + + splitTopic := strings.Split(result.Topic(), ":") + command := splitTopic[1] + callbackID := splitTopic[2] + switch command { + case "isdarkmode": + d.lock.RLock() + for _, client := range d.clients { + client.frontend.DarkModeEnabled(callbackID) + break + } + d.lock.RUnlock() + + default: + d.logger.Error("Unknown system command: %s", command) + } +} + +// processEvent will +func (d *Dispatcher) processEvent(result *servicebus.Message) { + + d.logger.Trace("Got event in message dispatcher: %+v", result) + + splitTopic := strings.Split(result.Topic(), ":") + eventType := splitTopic[1] + switch eventType { + case "emit": + eventFrom := splitTopic[3] + if eventFrom == "g" { + // This was sent from Go - notify frontend + eventData := result.Data().(*message.EventMessage) + // Unpack event + payload, err := json.Marshal(eventData) + if err != nil { + d.logger.Error("Unable to marshal eventData: %s", err.Error()) + return + } + d.lock.RLock() + for _, client := range d.clients { + client.frontend.NotifyEvent(string(payload)) + } + d.lock.RUnlock() + } + default: + d.logger.Error("Unknown event type: %s", eventType) + } +} + +// processWindowMessage processes messages intended for the window +func (d *Dispatcher) processWindowMessage(result *servicebus.Message) { + d.lock.RLock() + defer d.lock.RUnlock() + splitTopic := strings.Split(result.Topic(), ":") + command := splitTopic[1] + switch command { + case "settitle": + title, ok := result.Data().(string) + if !ok { + d.logger.Error("Invalid title for 'window:settitle' : %#v", result.Data()) + return + } + // Notify clients + for _, client := range d.clients { + client.frontend.WindowSetTitle(title) + } + case "fullscreen": + // Notify clients + for _, client := range d.clients { + client.frontend.WindowFullscreen() + } + case "unfullscreen": + // Notify clients + for _, client := range d.clients { + client.frontend.WindowUnFullscreen() + } + case "setcolour": + colour, ok := result.Data().(int) + if !ok { + d.logger.Error("Invalid colour for 'window:setcolour' : %#v", result.Data()) + return + } + // Notify clients + for _, client := range d.clients { + client.frontend.WindowSetColour(colour) + } + case "show": + // Notify clients + for _, client := range d.clients { + client.frontend.WindowShow() + } + case "hide": + // Notify clients + for _, client := range d.clients { + client.frontend.WindowHide() + } + case "center": + // Notify clients + for _, client := range d.clients { + client.frontend.WindowCenter() + } + case "maximise": + // Notify clients + for _, client := range d.clients { + client.frontend.WindowMaximise() + } + case "unmaximise": + // Notify clients + for _, client := range d.clients { + client.frontend.WindowUnmaximise() + } + case "minimise": + // Notify clients + for _, client := range d.clients { + client.frontend.WindowMinimise() + } + case "unminimise": + // Notify clients + for _, client := range d.clients { + client.frontend.WindowUnminimise() + } + case "position": + // We need 2 arguments + if len(splitTopic) != 4 { + d.logger.Error("Invalid number of parameters for 'window:position' : %#v", result.Data()) + return + } + x, err1 := strconv.Atoi(splitTopic[2]) + y, err2 := strconv.Atoi(splitTopic[3]) + if err1 != nil || err2 != nil { + d.logger.Error("Invalid integer parameters for 'window:position' : %#v", result.Data()) + return + } + // Notify clients + for _, client := range d.clients { + client.frontend.WindowPosition(x, y) + } + case "size": + // We need 2 arguments + if len(splitTopic) != 4 { + d.logger.Error("Invalid number of parameters for 'window:size' : %#v", result.Data()) + return + } + w, err1 := strconv.Atoi(splitTopic[2]) + h, err2 := strconv.Atoi(splitTopic[3]) + if err1 != nil || err2 != nil { + d.logger.Error("Invalid integer parameters for 'window:size' : %#v", result.Data()) + return + } + // Notifh clients + for _, client := range d.clients { + client.frontend.WindowSize(w, h) + } + case "minsize": + // We need 2 arguments + if len(splitTopic) != 4 { + d.logger.Error("Invalid number of parameters for 'window:minsize' : %#v", result.Data()) + return + } + w, err1 := strconv.Atoi(splitTopic[2]) + h, err2 := strconv.Atoi(splitTopic[3]) + if err1 != nil || err2 != nil { + d.logger.Error("Invalid integer parameters for 'window:minsize' : %#v", result.Data()) + return + } + // Notifh clients + for _, client := range d.clients { + client.frontend.WindowSetMinSize(w, h) + } + case "maxsize": + // We need 2 arguments + if len(splitTopic) != 4 { + d.logger.Error("Invalid number of parameters for 'window:maxsize' : %#v", result.Data()) + return + } + w, err1 := strconv.Atoi(splitTopic[2]) + h, err2 := strconv.Atoi(splitTopic[3]) + if err1 != nil || err2 != nil { + d.logger.Error("Invalid integer parameters for 'window:maxsize' : %#v", result.Data()) + return + } + // Notifh clients + for _, client := range d.clients { + client.frontend.WindowSetMaxSize(w, h) + } + default: + d.logger.Error("Unknown window command: %s", command) + } + d.logger.Trace("Got window in message dispatcher: %+v", result) + +} + +// processDialogMessage processes dialog messages +func (d *Dispatcher) processDialogMessage(result *servicebus.Message) { + splitTopic := strings.Split(result.Topic(), ":") + if len(splitTopic) < 4 { + d.logger.Error("Invalid dialog message : %#v", result.Data()) + return + } + + command := splitTopic[1] + switch command { + case "select": + dialogType := splitTopic[2] + switch dialogType { + case "open": + dialogOptions, ok := result.Data().(runtime.OpenDialogOptions) + if !ok { + d.logger.Error("Invalid data for 'dialog:select:open' : %#v", result.Data()) + return + } + // This is hardcoded in the sender too + callbackID := splitTopic[3] + + // TODO: Work out what we mean in a multi window environment... + // For now we will just pick the first one + for _, client := range d.clients { + client.frontend.OpenFileDialog(dialogOptions, callbackID) + } + case "openmultiple": + dialogOptions, ok := result.Data().(runtime.OpenDialogOptions) + if !ok { + d.logger.Error("Invalid data for 'dialog:select:openmultiple' : %#v", result.Data()) + return + } + // This is hardcoded in the sender too + callbackID := splitTopic[3] + + // TODO: Work out what we mean in a multi window environment... + // For now we will just pick the first one + for _, client := range d.clients { + client.frontend.OpenMultipleFilesDialog(dialogOptions, callbackID) + } + case "directory": + dialogOptions, ok := result.Data().(runtime.OpenDialogOptions) + if !ok { + d.logger.Error("Invalid data for 'dialog:select:directory' : %#v", result.Data()) + return + } + // This is hardcoded in the sender too + callbackID := splitTopic[3] + + // TODO: Work out what we mean in a multi window environment... + // For now we will just pick the first one + for _, client := range d.clients { + client.frontend.OpenDirectoryDialog(dialogOptions, callbackID) + } + case "save": + dialogOptions, ok := result.Data().(runtime.SaveDialogOptions) + if !ok { + d.logger.Error("Invalid data for 'dialog:select:save' : %#v", result.Data()) + return + } + // This is hardcoded in the sender too + callbackID := splitTopic[3] + + // TODO: Work out what we mean in a multi window environment... + // For now we will just pick the first one + for _, client := range d.clients { + client.frontend.SaveDialog(dialogOptions, callbackID) + } + case "message": + dialogOptions, ok := result.Data().(runtime.MessageDialogOptions) + if !ok { + d.logger.Error("Invalid data for 'dialog:select:message' : %#v", result.Data()) + return + } + // This is hardcoded in the sender too + callbackID := splitTopic[3] + + // TODO: Work out what we mean in a multi window environment... + // For now we will just pick the first one + for _, client := range d.clients { + client.frontend.MessageDialog(dialogOptions, callbackID) + } + default: + d.logger.Error("Unknown dialog type: %s", dialogType) + } + + default: + d.logger.Error("Unknown dialog command: %s", command) + } + +} + +func (d *Dispatcher) processMenuMessage(result *servicebus.Message) { + splitTopic := strings.Split(result.Topic(), ":") + if len(splitTopic) < 2 { + d.logger.Error("Invalid menu message : %#v", result.Data()) + return + } + + command := splitTopic[1] + switch command { + case "updateappmenu": + + updatedMenu, ok := result.Data().(string) + if !ok { + d.logger.Error("Invalid data for 'menufrontend:updateappmenu' : %#v", + result.Data()) + return + } + + // TODO: Work out what we mean in a multi window environment... + // For now we will just pick the first one + for _, client := range d.clients { + client.frontend.SetApplicationMenu(updatedMenu) + } + + case "settraymenu": + trayMenuJSON, ok := result.Data().(string) + if !ok { + d.logger.Error("Invalid data for 'menufrontend:settraymenu' : %#v", + result.Data()) + return + } + + // TODO: Work out what we mean in a multi window environment... + // For now we will just pick the first one + for _, client := range d.clients { + client.frontend.SetTrayMenu(trayMenuJSON) + } + + case "updatecontextmenu": + updatedContextMenu, ok := result.Data().(string) + if !ok { + d.logger.Error("Invalid data for 'menufrontend:updatecontextmenu' : %#v", + result.Data()) + return + } + + // TODO: Work out what we mean in a multi window environment... + // For now we will just pick the first one + for _, client := range d.clients { + client.frontend.UpdateContextMenu(updatedContextMenu) + } + + case "updatetraymenulabel": + updatedTrayMenuLabel, ok := result.Data().(string) + if !ok { + d.logger.Error("Invalid data for 'menufrontend:updatetraymenulabel' : %#v", + result.Data()) + return + } + + // TODO: Work out what we mean in a multi window environment... + // For now we will just pick the first one + for _, client := range d.clients { + client.frontend.UpdateTrayMenuLabel(updatedTrayMenuLabel) + } + case "deletetraymenu": + traymenuid, ok := result.Data().(string) + if !ok { + d.logger.Error("Invalid data for 'menufrontend:updatetraymenulabel' : %#v", + result.Data()) + return + } + + for _, client := range d.clients { + client.frontend.DeleteTrayMenuByID(traymenuid) + } + + default: + d.logger.Error("Unknown menufrontend command: %s", command) + } +} + +func (d *Dispatcher) Close() { + d.cancel() + d.wg.Wait() +} diff --git a/v2/internal/parse/README.md b/v2/internal/parse/README.md new file mode 100644 index 000000000..5a40811a3 --- /dev/null +++ b/v2/internal/parse/README.md @@ -0,0 +1,10 @@ +# Parse + +Parse will attempt to parse your Wails project to perform a number of tasks: + * Verify that you have bound struct pointers + * Generate JS helper files/docs + +It currently checks bindings correctly if your code binds using one of the following methods: + * Literal Binding: `app.Bind(&MyStruct{})` + * Variable Binding: `app.Bind(m)` - m can be `m := &MyStruct{}` or `m := newMyStruct()` + * Function Binding: `app.Bind(newMyStruct())` diff --git a/v2/internal/parse/parse.go b/v2/internal/parse/parse.go new file mode 100644 index 000000000..0d897ff52 --- /dev/null +++ b/v2/internal/parse/parse.go @@ -0,0 +1,436 @@ +package main + +import ( + "fmt" + "go/ast" + "os" + "strings" + + "github.com/leaanthony/slicer" + "golang.org/x/tools/go/packages" +) + +var structCache = make(map[string]*ParsedStruct) +var boundStructs = make(map[string]*ParsedStruct) +var boundMethods = []string{} +var boundStructPointerLiterals = []string{} +var boundStructLiterals = slicer.StringSlicer{} +var boundVariables = slicer.StringSlicer{} +var app = "" +var structPointerFunctionDecls = make(map[string]string) +var structFunctionDecls = make(map[string]string) +var variableStructDecls = make(map[string]string) +var variableFunctionDecls = make(map[string]string) + +type Parameter struct { + Name string + Type string +} + +type ParsedMethod struct { + Struct string + Name string + Comments []string + Inputs []*Parameter + Returns []*Parameter +} + +type ParsedStruct struct { + Name string + Methods []*ParsedMethod +} + +type BoundStructs []*ParsedStruct + +func ParseProject(projectPath string) (BoundStructs, error) { + + cfg := &packages.Config{Mode: packages.NeedFiles | packages.NeedSyntax | packages.NeedTypesInfo} + pkgs, err := packages.Load(cfg, projectPath) + if err != nil { + _, _ = fmt.Fprintf(os.Stderr, "load: %v\n", err) + os.Exit(1) + } + if packages.PrintErrors(pkgs) > 0 { + os.Exit(1) + } + + // Iterate the packages + for _, pkg := range pkgs { + + // Iterate the files + for _, file := range pkg.Syntax { + + var wailsPkgVar = "" + + ast.Inspect(file, func(n ast.Node) bool { + switch x := n.(type) { + // Parse import declarations + case *ast.ImportSpec: + // Determine what wails has been imported as + if x.Path.Value == `"github.com/wailsapp/wails/v2"` { + wailsPkgVar = x.Name.Name + } + // Parse calls. We are looking for app.Bind() calls + case *ast.CallExpr: + f, ok := x.Fun.(*ast.SelectorExpr) + if ok { + n, ok := f.X.(*ast.Ident) + if ok { + //Check this is the Bind() call associated with the app variable + if n.Name == app && f.Sel.Name == "Bind" { + if len(x.Args) == 1 { + ce, ok := x.Args[0].(*ast.CallExpr) + if ok { + n, ok := ce.Fun.(*ast.Ident) + if ok { + // We found a bind method using a function call + // EG: app.Bind( newMyStruct() ) + boundMethods = append(boundMethods, n.Name) + } + } else { + // We also want to check for Bind( &MyStruct{} ) + ue, ok := x.Args[0].(*ast.UnaryExpr) + if ok { + if ue.Op.String() == "&" { + cl, ok := ue.X.(*ast.CompositeLit) + if ok { + t, ok := cl.Type.(*ast.Ident) + if ok { + // We have found Bind( &MyStruct{} ) + boundStructPointerLiterals = append(boundStructPointerLiterals, t.Name) + } + } + } + } else { + // Let's check when the user binds a struct, + // rather than a struct pointer: Bind( MyStruct{} ) + // We do this to provide better hints to the user + cl, ok := x.Args[0].(*ast.CompositeLit) + if ok { + t, ok := cl.Type.(*ast.Ident) + if ok { + boundStructLiterals.Add(t.Name) + } + } else { + // Also check for when we bind a variable + // myVariable := &MyStruct{} + // app.Bind( myVariable ) + i, ok := x.Args[0].(*ast.Ident) + if ok { + boundVariables.Add(i.Name) + } + } + } + } + } + } + } + } + + // We scan assignments for a number of reasons: + // * Determine the variable containing the main application + // * Determine the type of variables that get used in Bind() + // * Determine the type of variables that get created with var := &MyStruct{} + case *ast.AssignStmt: + for _, rhs := range x.Rhs { + ce, ok := rhs.(*ast.CallExpr) + if ok { + se, ok := ce.Fun.(*ast.SelectorExpr) + if ok { + i, ok := se.X.(*ast.Ident) + if ok { + // Have we found the wails package name? + if i.Name == wailsPkgVar { + // Check we are calling a function to create the app + if se.Sel.Name == "CreateApp" || se.Sel.Name == "CreateAppWithOptions" { + if len(x.Lhs) == 1 { + i, ok := x.Lhs[0].(*ast.Ident) + if ok { + // Found the app variable name + app = i.Name + } + } + } + } + } + } else { + // Check for function assignment + // a := newMyStruct() + fe, ok := ce.Fun.(*ast.Ident) + if ok { + if len(x.Lhs) == 1 { + i, ok := x.Lhs[0].(*ast.Ident) + if ok { + // Store the variable -> Function mapping + // so we can later resolve the type + variableFunctionDecls[i.Name] = fe.Name + } + } + } + } + } else { + // Check for literal assignment of struct + // EG: myvar := MyStruct{} + ue, ok := rhs.(*ast.UnaryExpr) + if ok { + cl, ok := ue.X.(*ast.CompositeLit) + if ok { + t, ok := cl.Type.(*ast.Ident) + if ok { + if len(x.Lhs) == 1 { + i, ok := x.Lhs[0].(*ast.Ident) + if ok { + variableStructDecls[i.Name] = t.Name + } + } + } + } + } + } + } + // We scan for functions to build up a list of function names + // for a number of reasons: + // * Determine which functions are struct methods that are bound + // * Determine + case *ast.FuncDecl: + if x.Recv != nil { + // This is a struct method + for _, field := range x.Recv.List { + se, ok := field.Type.(*ast.StarExpr) + if ok { + // This is a struct pointer method + i, ok := se.X.(*ast.Ident) + if ok { + // If we haven't already found this struct, + // Create a placeholder in the cache + parsedStruct := structCache[i.Name] + if parsedStruct == nil { + structCache[i.Name] = &ParsedStruct{ + Name: i.Name, + } + parsedStruct = structCache[i.Name] + } + + // If this method is Public + if string(x.Name.Name[0]) == strings.ToUpper((string(x.Name.Name[0]))) { + structMethod := &ParsedMethod{ + Struct: i.Name, + Name: x.Name.Name, + } + // Check if the method has comments. + // If so, save it with the parsed method + if x.Doc != nil { + for _, comment := range x.Doc.List { + stringComment := comment.Text + if strings.HasPrefix(stringComment, "//") { + stringComment = stringComment[2:] + } + structMethod.Comments = append(structMethod.Comments, strings.TrimSpace(stringComment)) + } + } + + // Save the input parameters + for _, inputField := range x.Type.Params.List { + t, ok := inputField.Type.(*ast.Ident) + if !ok { + continue + } + for _, name := range inputField.Names { + structMethod.Inputs = append(structMethod.Inputs, &Parameter{Name: name.Name, Type: t.Name}) + } + } + + // Save the output parameters + for _, outputField := range x.Type.Results.List { + t, ok := outputField.Type.(*ast.Ident) + if !ok { + continue + } + if len(outputField.Names) == 0 { + structMethod.Returns = append(structMethod.Returns, &Parameter{Type: t.Name}) + } else { + for _, name := range outputField.Names { + structMethod.Returns = append(structMethod.Returns, &Parameter{Name: name.Name, Type: t.Name}) + } + } + } + + // Append this method to the parsed struct + parsedStruct.Methods = append(parsedStruct.Methods, structMethod) + + } + } + } + } + } else { + // This is a function declaration + // We care about its name and return type + // This will allow us to resolve types later + functionName := x.Name.Name + + // Look for one that returns a single value + if x.Type != nil && x.Type.Results != nil && x.Type.Results.List != nil { + if len(x.Type.Results.List) == 1 { + // Check for *struct + t, ok := x.Type.Results.List[0].Type.(*ast.StarExpr) + if ok { + s, ok := t.X.(*ast.Ident) + if ok { + // println("*** Function", functionName, "found which returns: *"+s.Name) + structPointerFunctionDecls[functionName] = s.Name + } + } else { + // Check for functions that return a struct + // This is to help us provide hints if the user binds a struct + t, ok := x.Type.Results.List[0].Type.(*ast.Ident) + if ok { + // println("*** Function", functionName, "found which returns: "+t.Name) + structFunctionDecls[functionName] = t.Name + } + } + } + } + } + } + return true + }) + // spew.Dump(file) + } + } + + /***** Update bound structs ******/ + + // Resolve bound Methods + for _, method := range boundMethods { + s, ok := structPointerFunctionDecls[method] + if !ok { + s, ok = structFunctionDecls[method] + if !ok { + println("Fatal: Bind statement using", method, "but cannot find", method, "declaration") + } else { + println("Fatal: Cannot bind struct using method `" + method + "` because it returns a struct (" + s + "). Return a pointer to " + s + " instead.") + } + os.Exit(1) + } + structDefinition := structCache[s] + if structDefinition == nil { + println("Fatal: Bind statement using `"+method+"` but cannot find struct", s, "definition") + os.Exit(1) + } + boundStructs[s] = structDefinition + } + + // Resolve bound vars + for _, structLiteral := range boundStructPointerLiterals { + s, ok := structCache[structLiteral] + if !ok { + println("Fatal: Bind statement using", structLiteral, "but cannot find", structLiteral, "declaration") + os.Exit(1) + } + boundStructs[structLiteral] = s + } + + // Resolve bound variables + boundVariables.Each(func(variable string) { + v, ok := variableStructDecls[variable] + if !ok { + method, ok := variableFunctionDecls[variable] + if !ok { + println("Fatal: Bind statement using variable `" + variable + "` which does not resolve to a struct pointer") + os.Exit(1) + } + + // Resolve function name + v, ok = structPointerFunctionDecls[method] + if !ok { + v, ok = structFunctionDecls[method] + if !ok { + println("Fatal: Bind statement using", method, "but cannot find", method, "declaration") + } else { + println("Fatal: Cannot bind variable `" + variable + "` because it resolves to a struct (" + v + "). Return a pointer to " + v + " instead.") + } + os.Exit(1) + } + + } + + s, ok := structCache[v] + if !ok { + println("Fatal: Bind statement using variable `" + variable + "` which resolves to a `" + v + "` but cannot find its declaration") + os.Exit(1) + } + boundStructs[v] = s + + }) + + // Check for struct literals + boundStructLiterals.Each(func(structName string) { + println("Fatal: Cannot bind struct using struct literal `" + structName + "{}`. Create a pointer to " + structName + " instead.") + os.Exit(1) + }) + + // Check for bound variables + // boundVariables.Each(func(varName string) { + // println("Fatal: Cannot bind struct using struct literal `" + structName + "{}`. Create a pointer to " + structName + " instead.") + // }) + + // spew.Dump(boundStructs) + // os.Exit(0) + + // } + // Inspect the AST and print all identifiers and literals. + + println("export {") + + noOfStructs := len(boundStructs) + structCount := 0 + for _, s := range boundStructs { + structCount++ + println() + println(" " + s.Name + ": {") + println() + noOfMethods := len(s.Methods) + for methodCount, m := range s.Methods { + println(" /****************") + for _, comment := range m.Comments { + println(" *", comment) + } + if len(m.Comments) > 0 { + println(" *") + } + inputNames := "" + for _, input := range m.Inputs { + println(" * @param {"+input.Type+"}", input.Name) + inputNames += input.Name + ", " + } + print(" * @return Promise<") + for _, output := range m.Returns { + print(output.Type + "|") + } + println("Error>") + println(" *") + println(" ***/") + if len(inputNames) > 2 { + inputNames = inputNames[:len(inputNames)-2] + } + println(" ", m.Name+": function("+inputNames+") {") + println(" return window.go." + s.Name + "." + m.Name + "(" + inputNames + ");") + print(" }") + if methodCount < noOfMethods-1 { + print(",") + } + println() + println() + } + print(" }") + if structCount < noOfStructs-1 { + print(",") + } + println() + } + println() + println("}") + println() + + return nil, nil +} diff --git a/v2/internal/platform/menu/manager.go b/v2/internal/platform/menu/manager.go deleted file mode 100644 index 0ddbc9dde..000000000 --- a/v2/internal/platform/menu/manager.go +++ /dev/null @@ -1,147 +0,0 @@ -//go:build windows - -package menu - -import ( - "github.com/wailsapp/wails/v2/pkg/menu" -) - -// MenuManager manages the menus for the application -var MenuManager = NewManager() - -type radioGroup []*menu.MenuItem - -// Click updates the radio group state based on the item clicked -func (g *radioGroup) Click(item *menu.MenuItem) { - for _, radioGroupItem := range *g { - if radioGroupItem != item { - radioGroupItem.Checked = false - } - } -} - -type processedMenu struct { - - // the menu we processed - menu *menu.Menu - - // updateMenuItemCallback is called when the menu item needs to be updated in the UI - updateMenuItemCallback func(*menu.MenuItem) - - // items is a map of all menu items in this menu - items map[*menu.MenuItem]struct{} - - // radioGroups tracks which radiogroup a menu item belongs to - radioGroups map[*menu.MenuItem][]*radioGroup -} - -func newProcessedMenu(topLevelMenu *menu.Menu, updateMenuItemCallback func(*menu.MenuItem)) *processedMenu { - result := &processedMenu{ - updateMenuItemCallback: updateMenuItemCallback, - menu: topLevelMenu, - items: make(map[*menu.MenuItem]struct{}), - radioGroups: make(map[*menu.MenuItem][]*radioGroup), - } - result.process(topLevelMenu.Items) - return result -} - -func (p *processedMenu) process(items []*menu.MenuItem) { - var currentRadioGroup radioGroup - for index, item := range items { - // Save the reference to the top level menu for this item - p.items[item] = struct{}{} - - // If this is a radio item, add it to the radio group - if item.Type == menu.RadioType { - currentRadioGroup = append(currentRadioGroup, item) - } - - // If this is not a radio item, or we are processing the last item in the menu, - // then we need to add the current radio group to the map if it has items - if item.Type != menu.RadioType || index == len(items)-1 { - if len(currentRadioGroup) > 0 { - p.addRadioGroup(currentRadioGroup) - currentRadioGroup = nil - } - } - - // Process the submenu - if item.SubMenu != nil { - p.process(item.SubMenu.Items) - } - } -} - -func (p *processedMenu) processClick(item *menu.MenuItem) { - // If this item is not in our menu, then we can't process it - if _, ok := p.items[item]; !ok { - return - } - - // If this is a radio item, then we need to update the radio group - if item.Type == menu.RadioType { - // Get the radio groups for this item - radioGroups := p.radioGroups[item] - // Iterate each radio group this item belongs to and set the checked state - // of all items apart from the one that was clicked to false - for _, thisRadioGroup := range radioGroups { - thisRadioGroup.Click(item) - for _, thisRadioGroupItem := range *thisRadioGroup { - p.updateMenuItemCallback(thisRadioGroupItem) - } - } - } - - if item.Type == menu.CheckboxType { - p.updateMenuItemCallback(item) - } - -} - -func (p *processedMenu) addRadioGroup(r radioGroup) { - for _, item := range r { - p.radioGroups[item] = append(p.radioGroups[item], &r) - } -} - -type Manager struct { - menus map[*menu.Menu]*processedMenu -} - -func NewManager() *Manager { - return &Manager{ - menus: make(map[*menu.Menu]*processedMenu), - } -} - -func (m *Manager) AddMenu(menu *menu.Menu, updateMenuItemCallback func(*menu.MenuItem)) { - m.menus[menu] = newProcessedMenu(menu, updateMenuItemCallback) -} - -func (m *Manager) ProcessClick(item *menu.MenuItem) { - - // if menuitem is a checkbox, then we need to toggle the state - if item.Type == menu.CheckboxType { - item.Checked = !item.Checked - } - - // Set the radio item to checked - if item.Type == menu.RadioType { - item.Checked = true - } - - for _, thisMenu := range m.menus { - thisMenu.processClick(item) - } - - if item.Click != nil { - item.Click(&menu.CallbackData{ - MenuItem: item, - }) - } -} - -func (m *Manager) RemoveMenu(data *menu.Menu) { - delete(m.menus, data) -} diff --git a/v2/internal/platform/menu/manager_test.go b/v2/internal/platform/menu/manager_test.go deleted file mode 100644 index 9e014b3ee..000000000 --- a/v2/internal/platform/menu/manager_test.go +++ /dev/null @@ -1,297 +0,0 @@ -//go:build windows - -package menu_test - -import ( - "github.com/stretchr/testify/require" - platformMenu "github.com/wailsapp/wails/v2/internal/platform/menu" - "github.com/wailsapp/wails/v2/pkg/menu" - "testing" -) - -func TestManager_ProcessClick_Checkbox(t *testing.T) { - - checkbox := menu.Label("Checkbox").SetChecked(false) - menu1 := &menu.Menu{ - Items: []*menu.MenuItem{ - checkbox, - }, - } - menu2 := &menu.Menu{ - Items: []*menu.MenuItem{ - checkbox, - }, - } - menuWithNoCheckbox := &menu.Menu{ - Items: []*menu.MenuItem{ - menu.Label("No Checkbox"), - }, - } - clicked := false - - tests := []struct { - name string - inputs []*menu.Menu - startState bool - expectedState bool - expectedMenuUpdates map[*menu.Menu][]*menu.MenuItem - click func(*menu.CallbackData) - }{ - { - name: "should callback menu checkbox state when clicked (false -> true)", - inputs: []*menu.Menu{menu1}, - expectedMenuUpdates: map[*menu.Menu][]*menu.MenuItem{ - menu1: {checkbox}, - }, - startState: false, - expectedState: true, - }, - { - name: "should callback multiple menus when checkbox state when clicked (false -> true)", - inputs: []*menu.Menu{menu1, menu2}, - startState: false, - expectedState: true, - expectedMenuUpdates: map[*menu.Menu][]*menu.MenuItem{ - menu1: {checkbox}, - menu2: {checkbox}, - }, - }, - { - name: "should callback only for the menus that the checkbox is in (false -> true)", - inputs: []*menu.Menu{menu1, menuWithNoCheckbox}, - startState: false, - expectedState: true, - expectedMenuUpdates: map[*menu.Menu][]*menu.MenuItem{ - menu1: {checkbox}, - }, - }, - { - name: "should callback menu checkbox state when clicked (true->false)", - inputs: []*menu.Menu{menu1}, - expectedMenuUpdates: map[*menu.Menu][]*menu.MenuItem{ - menu1: {checkbox}, - }, - startState: true, - expectedState: false, - }, - { - name: "should callback multiple menus when checkbox state when clicked (true->false)", - inputs: []*menu.Menu{menu1, menu2}, - startState: true, - expectedState: false, - expectedMenuUpdates: map[*menu.Menu][]*menu.MenuItem{ - menu1: {checkbox}, - menu2: {checkbox}, - }, - }, - { - name: "should callback only for the menus that the checkbox is in (true->false)", - inputs: []*menu.Menu{menu1, menuWithNoCheckbox}, - startState: true, - expectedState: false, - expectedMenuUpdates: map[*menu.Menu][]*menu.MenuItem{ - menu1: {checkbox}, - }, - }, - { - name: "should callback no menus if checkbox not in them", - inputs: []*menu.Menu{menuWithNoCheckbox}, - startState: false, - expectedState: false, - expectedMenuUpdates: nil, - }, - { - name: "should call Click on the checkbox", - inputs: []*menu.Menu{menu1, menu2}, - startState: false, - expectedState: true, - expectedMenuUpdates: map[*menu.Menu][]*menu.MenuItem{ - menu1: {checkbox}, - menu2: {checkbox}, - }, - click: func(data *menu.CallbackData) { - clicked = true - }, - }, - } - for _, tt := range tests { - - menusUpdated := map[*menu.Menu][]*menu.MenuItem{} - clicked = false - - var checkMenuItemStateInMenu func(menu *menu.Menu) - - checkMenuItemStateInMenu = func(menu *menu.Menu) { - for _, item := range menusUpdated[menu] { - if item == checkbox { - require.Equal(t, tt.expectedState, item.Checked) - } - if item.SubMenu != nil { - checkMenuItemStateInMenu(item.SubMenu) - } - } - } - - t.Run(tt.name, func(t *testing.T) { - m := platformMenu.NewManager() - checkbox.SetChecked(tt.startState) - checkbox.Click = tt.click - for _, thisMenu := range tt.inputs { - thisMenu := thisMenu - m.AddMenu(thisMenu, func(menuItem *menu.MenuItem) { - menusUpdated[thisMenu] = append(menusUpdated[thisMenu], menuItem) - }) - } - m.ProcessClick(checkbox) - - // Check the item has the correct state in all the menus - for thisMenu := range menusUpdated { - require.EqualValues(t, tt.expectedMenuUpdates[thisMenu], menusUpdated[thisMenu]) - } - - if tt.click != nil { - require.Equal(t, true, clicked) - } - }) - } -} - -func TestManager_ProcessClick_RadioGroups(t *testing.T) { - - radio1 := menu.Radio("Radio1", false, nil, nil) - radio2 := menu.Radio("Radio2", false, nil, nil) - radio3 := menu.Radio("Radio3", false, nil, nil) - radio4 := menu.Radio("Radio4", false, nil, nil) - radio5 := menu.Radio("Radio5", false, nil, nil) - radio6 := menu.Radio("Radio6", false, nil, nil) - - radioGroupOne := &menu.Menu{ - Items: []*menu.MenuItem{ - radio1, - radio2, - radio3, - }, - } - - radioGroupTwo := &menu.Menu{ - Items: []*menu.MenuItem{ - radio4, - radio5, - radio6, - }, - } - - radioGroupThree := &menu.Menu{ - Items: []*menu.MenuItem{ - radio1, - radio2, - radio3, - }, - } - - clicked := false - - tests := []struct { - name string - inputs []*menu.Menu - startState map[*menu.MenuItem]bool - selected *menu.MenuItem - expectedMenuUpdates map[*menu.Menu][]*menu.MenuItem - click func(*menu.CallbackData) - expectedState map[*menu.MenuItem]bool - }{ - { - name: "should only set the clicked radio item", - inputs: []*menu.Menu{radioGroupOne}, - expectedMenuUpdates: map[*menu.Menu][]*menu.MenuItem{ - radioGroupOne: {radio1, radio2, radio3}, - }, - startState: map[*menu.MenuItem]bool{ - radio1: true, - radio2: false, - radio3: false, - }, - selected: radio2, - expectedState: map[*menu.MenuItem]bool{ - radio1: false, - radio2: true, - radio3: false, - }, - }, - { - name: "should not affect other radio groups or menus", - inputs: []*menu.Menu{radioGroupOne, radioGroupTwo}, - expectedMenuUpdates: map[*menu.Menu][]*menu.MenuItem{ - radioGroupOne: {radio1, radio2, radio3}, - }, - startState: map[*menu.MenuItem]bool{ - radio1: true, - radio2: false, - radio3: false, - radio4: true, - radio5: false, - radio6: false, - }, - selected: radio2, - expectedState: map[*menu.MenuItem]bool{ - radio1: false, - radio2: true, - radio3: false, - radio4: true, - radio5: false, - radio6: false, - }, - }, - { - name: "menus with the same radio group should be updated", - inputs: []*menu.Menu{radioGroupOne, radioGroupThree}, - expectedMenuUpdates: map[*menu.Menu][]*menu.MenuItem{ - radioGroupOne: {radio1, radio2, radio3}, - radioGroupThree: {radio1, radio2, radio3}, - }, - startState: map[*menu.MenuItem]bool{ - radio1: true, - radio2: false, - radio3: false, - }, - selected: radio2, - expectedState: map[*menu.MenuItem]bool{ - radio1: false, - radio2: true, - radio3: false, - }, - }, - } - for _, tt := range tests { - - menusUpdated := map[*menu.Menu][]*menu.MenuItem{} - clicked = false - - t.Run(tt.name, func(t *testing.T) { - m := platformMenu.NewManager() - - for item, value := range tt.startState { - item.SetChecked(value) - } - - tt.selected.Click = tt.click - for _, thisMenu := range tt.inputs { - thisMenu := thisMenu - m.AddMenu(thisMenu, func(menuItem *menu.MenuItem) { - menusUpdated[thisMenu] = append(menusUpdated[thisMenu], menuItem) - }) - } - m.ProcessClick(tt.selected) - require.Equal(t, tt.expectedMenuUpdates, menusUpdated) - - // Check the items have the correct state in all the menus - for item, expectedValue := range tt.expectedState { - require.Equal(t, expectedValue, item.Checked) - } - - if tt.click != nil { - require.Equal(t, true, clicked) - } - }) - } -} diff --git a/v2/internal/platform/menu/windows.go b/v2/internal/platform/menu/windows.go deleted file mode 100644 index 68ebbcb49..000000000 --- a/v2/internal/platform/menu/windows.go +++ /dev/null @@ -1,9 +0,0 @@ -//go:build windows - -package menu - -import "github.com/wailsapp/wails/v2/internal/platform/win32" - -type Menu struct { - menu win32.HMENU -} diff --git a/v2/internal/platform/win32/consts.go b/v2/internal/platform/win32/consts.go deleted file mode 100644 index 43149b036..000000000 --- a/v2/internal/platform/win32/consts.go +++ /dev/null @@ -1,859 +0,0 @@ -//go:build windows - -package win32 - -import ( - "fmt" - "syscall" - "unsafe" - - "github.com/wailsapp/wails/v2/internal/system/operatingsystem" - "golang.org/x/sys/windows" -) - -var ( - modKernel32 = syscall.NewLazyDLL("kernel32.dll") - procGetModuleHandle = modKernel32.NewProc("GetModuleHandleW") - - moduser32 = syscall.NewLazyDLL("user32.dll") - procRegisterClassEx = moduser32.NewProc("RegisterClassExW") - procLoadIcon = moduser32.NewProc("LoadIconW") - procLoadCursor = moduser32.NewProc("LoadCursorW") - procCreateWindowEx = moduser32.NewProc("CreateWindowExW") - procPostMessage = moduser32.NewProc("PostMessageW") - procGetCursorPos = moduser32.NewProc("GetCursorPos") - procSetForegroundWindow = moduser32.NewProc("SetForegroundWindow") - procCreatePopupMenu = moduser32.NewProc("CreatePopupMenu") - procTrackPopupMenu = moduser32.NewProc("TrackPopupMenu") - procDestroyMenu = moduser32.NewProc("DestroyMenu") - procAppendMenuW = moduser32.NewProc("AppendMenuW") - procCheckMenuItem = moduser32.NewProc("CheckMenuItem") - procCheckMenuRadioItem = moduser32.NewProc("CheckMenuRadioItem") - procCreateIconFromResourceEx = moduser32.NewProc("CreateIconFromResourceEx") - procGetMessageW = moduser32.NewProc("GetMessageW") - procIsDialogMessage = moduser32.NewProc("IsDialogMessageW") - procTranslateMessage = moduser32.NewProc("TranslateMessage") - procDispatchMessage = moduser32.NewProc("DispatchMessageW") - procPostQuitMessage = moduser32.NewProc("PostQuitMessage") - procSystemParametersInfo = moduser32.NewProc("SystemParametersInfoW") - procSetWindowCompositionAttribute = moduser32.NewProc("SetWindowCompositionAttribute") - procGetKeyState = moduser32.NewProc("GetKeyState") - procCreateAcceleratorTable = moduser32.NewProc("CreateAcceleratorTableW") - procTranslateAccelerator = moduser32.NewProc("TranslateAcceleratorW") - - modshell32 = syscall.NewLazyDLL("shell32.dll") - procShellNotifyIcon = modshell32.NewProc("Shell_NotifyIconW") - - moddwmapi = syscall.NewLazyDLL("dwmapi.dll") - procDwmSetWindowAttribute = moddwmapi.NewProc("DwmSetWindowAttribute") - - moduxtheme = syscall.NewLazyDLL("uxtheme.dll") - procSetWindowTheme = moduxtheme.NewProc("SetWindowTheme") - - AllowDarkModeForWindow func(HWND, bool) uintptr - SetPreferredAppMode func(int32) uintptr -) - -type PreferredAppMode = int32 - -const ( - PreferredAppModeDefault PreferredAppMode = iota - PreferredAppModeAllowDark - PreferredAppModeForceDark - PreferredAppModeForceLight - PreferredAppModeMax -) - -/* -RtlGetNtVersionNumbers = void (LPDWORD major, LPDWORD minor, LPDWORD build) // 1809 17763 -ShouldAppsUseDarkMode = bool () // ordinal 132 -AllowDarkModeForWindow = bool (HWND hWnd, bool allow) // ordinal 133 -AllowDarkModeForApp = bool (bool allow) // ordinal 135, removed since 18334 -FlushMenuThemes = void () // ordinal 136 -RefreshImmersiveColorPolicyState = void () // ordinal 104 -IsDarkModeAllowedForWindow = bool (HWND hWnd) // ordinal 137 -GetIsImmersiveColorUsingHighContrast = bool (IMMERSIVE_HC_CACHE_MODE mode) // ordinal 106 -OpenNcThemeData = HTHEME (HWND hWnd, LPCWSTR pszClassList) // ordinal 49 -// Insider 18290 -ShouldSystemUseDarkMode = bool () // ordinal 138 -// Insider 18334 -SetPreferredAppMode = PreferredAppMode (PreferredAppMode appMode) // ordinal 135, since 18334 -IsDarkModeAllowedForApp = bool () // ordinal 139 -*/ -func Init() { - if IsWindowsVersionAtLeast(10, 0, 18334) { - - // AllowDarkModeForWindow is only available on Windows 10+ - uxtheme, err := windows.LoadLibrary("uxtheme.dll") - if err == nil { - procAllowDarkModeForWindow, err := windows.GetProcAddressByOrdinal(uxtheme, uintptr(133)) - if err == nil { - AllowDarkModeForWindow = func(hwnd HWND, allow bool) uintptr { - var allowInt int32 - if allow { - allowInt = 1 - } - ret, _, _ := syscall.SyscallN(procAllowDarkModeForWindow, uintptr(hwnd), uintptr(allowInt)) - return ret - } - } - } - - // SetPreferredAppMode is only available on Windows 10+ - procSetPreferredAppMode, err := windows.GetProcAddressByOrdinal(uxtheme, uintptr(135)) - if err == nil { - SetPreferredAppMode = func(mode int32) uintptr { - ret, _, _ := syscall.SyscallN(procSetPreferredAppMode, uintptr(mode)) - return ret - } - SetPreferredAppMode(PreferredAppModeAllowDark) - } - } - -} - -type HANDLE uintptr -type HINSTANCE = HANDLE -type HICON = HANDLE -type HCURSOR = HANDLE -type HBRUSH = HANDLE -type HWND = HANDLE -type HMENU = HANDLE -type DWORD = uint32 -type ATOM uint16 -type MenuID uint16 - -const ( - WM_APP = 32768 - WM_ACTIVATE = 6 - WM_ACTIVATEAPP = 28 - WM_AFXFIRST = 864 - WM_AFXLAST = 895 - WM_ASKCBFORMATNAME = 780 - WM_CANCELJOURNAL = 75 - WM_CANCELMODE = 31 - WM_CAPTURECHANGED = 533 - WM_CHANGECBCHAIN = 781 - WM_CHAR = 258 - WM_CHARTOITEM = 47 - WM_CHILDACTIVATE = 34 - WM_CLEAR = 771 - WM_CLOSE = 16 - WM_COMMAND = 273 - WM_COMMNOTIFY = 68 /* OBSOLETE */ - WM_COMPACTING = 65 - WM_COMPAREITEM = 57 - WM_CONTEXTMENU = 123 - WM_COPY = 769 - WM_COPYDATA = 74 - WM_CREATE = 1 - WM_CTLCOLORBTN = 309 - WM_CTLCOLORDLG = 310 - WM_CTLCOLOREDIT = 307 - WM_CTLCOLORLISTBOX = 308 - WM_CTLCOLORMSGBOX = 306 - WM_CTLCOLORSCROLLBAR = 311 - WM_CTLCOLORSTATIC = 312 - WM_CUT = 768 - WM_DEADCHAR = 259 - WM_DELETEITEM = 45 - WM_DESTROY = 2 - WM_DESTROYCLIPBOARD = 775 - WM_DEVICECHANGE = 537 - WM_DEVMODECHANGE = 27 - WM_DISPLAYCHANGE = 126 - WM_DRAWCLIPBOARD = 776 - WM_DRAWITEM = 43 - WM_DROPFILES = 563 - WM_ENABLE = 10 - WM_ENDSESSION = 22 - WM_ENTERIDLE = 289 - WM_ENTERMENULOOP = 529 - WM_ENTERSIZEMOVE = 561 - WM_ERASEBKGND = 20 - WM_EXITMENULOOP = 530 - WM_EXITSIZEMOVE = 562 - WM_FONTCHANGE = 29 - WM_GETDLGCODE = 135 - WM_GETFONT = 49 - WM_GETHOTKEY = 51 - WM_GETICON = 127 - WM_GETMINMAXINFO = 36 - WM_GETTEXT = 13 - WM_GETTEXTLENGTH = 14 - WM_HANDHELDFIRST = 856 - WM_HANDHELDLAST = 863 - WM_HELP = 83 - WM_HOTKEY = 786 - WM_HSCROLL = 276 - WM_HSCROLLCLIPBOARD = 782 - WM_ICONERASEBKGND = 39 - WM_INITDIALOG = 272 - WM_INITMENU = 278 - WM_INITMENUPOPUP = 279 - WM_INPUT = 0x00FF - WM_INPUTLANGCHANGE = 81 - WM_INPUTLANGCHANGEREQUEST = 80 - WM_KEYDOWN = 256 - WM_KEYUP = 257 - WM_KILLFOCUS = 8 - WM_MDIACTIVATE = 546 - WM_MDICASCADE = 551 - WM_MDICREATE = 544 - WM_MDIDESTROY = 545 - WM_MDIGETACTIVE = 553 - WM_MDIICONARRANGE = 552 - WM_MDIMAXIMIZE = 549 - WM_MDINEXT = 548 - WM_MDIREFRESHMENU = 564 - WM_MDIRESTORE = 547 - WM_MDISETMENU = 560 - WM_MDITILE = 550 - WM_MEASUREITEM = 44 - WM_GETOBJECT = 0x003D - WM_CHANGEUISTATE = 0x0127 - WM_UPDATEUISTATE = 0x0128 - WM_QUERYUISTATE = 0x0129 - WM_UNINITMENUPOPUP = 0x0125 - WM_MENURBUTTONUP = 290 - WM_MENUCOMMAND = 0x0126 - WM_MENUGETOBJECT = 0x0124 - WM_MENUDRAG = 0x0123 - WM_APPCOMMAND = 0x0319 - WM_MENUCHAR = 288 - WM_MENUSELECT = 287 - WM_MOVE = 3 - WM_MOVING = 534 - WM_NCACTIVATE = 134 - WM_NCCALCSIZE = 131 - WM_NCCREATE = 129 - WM_NCDESTROY = 130 - WM_NCHITTEST = 132 - WM_NCLBUTTONDBLCLK = 163 - WM_NCLBUTTONDOWN = 161 - WM_NCLBUTTONUP = 162 - WM_NCMBUTTONDBLCLK = 169 - WM_NCMBUTTONDOWN = 167 - WM_NCMBUTTONUP = 168 - WM_NCXBUTTONDOWN = 171 - WM_NCXBUTTONUP = 172 - WM_NCXBUTTONDBLCLK = 173 - WM_NCMOUSEHOVER = 0x02A0 - WM_NCMOUSELEAVE = 0x02A2 - WM_NCMOUSEMOVE = 160 - WM_NCPAINT = 133 - WM_NCRBUTTONDBLCLK = 166 - WM_NCRBUTTONDOWN = 164 - WM_NCRBUTTONUP = 165 - WM_NEXTDLGCTL = 40 - WM_NEXTMENU = 531 - WM_NOTIFY = 78 - WM_NOTIFYFORMAT = 85 - WM_NULL = 0 - WM_PAINT = 15 - WM_PAINTCLIPBOARD = 777 - WM_PAINTICON = 38 - WM_PALETTECHANGED = 785 - WM_PALETTEISCHANGING = 784 - WM_PARENTNOTIFY = 528 - WM_PASTE = 770 - WM_PENWINFIRST = 896 - WM_PENWINLAST = 911 - WM_POWER = 72 - WM_PRINT = 791 - WM_PRINTCLIENT = 792 - WM_QUERYDRAGICON = 55 - WM_QUERYENDSESSION = 17 - WM_QUERYNEWPALETTE = 783 - WM_QUERYOPEN = 19 - WM_QUEUESYNC = 35 - WM_QUIT = 18 - WM_RENDERALLFORMATS = 774 - WM_RENDERFORMAT = 773 - WM_SETCURSOR = 32 - WM_SETFOCUS = 7 - WM_SETFONT = 48 - WM_SETHOTKEY = 50 - WM_SETICON = 128 - WM_SETREDRAW = 11 - WM_SETTEXT = 12 - WM_SETTINGCHANGE = 26 - WM_SHOWWINDOW = 24 - WM_SIZE = 5 - WM_SIZECLIPBOARD = 779 - WM_SIZING = 532 - WM_SPOOLERSTATUS = 42 - WM_STYLECHANGED = 125 - WM_STYLECHANGING = 124 - WM_SYSCHAR = 262 - WM_SYSCOLORCHANGE = 21 - WM_SYSCOMMAND = 274 - WM_SYSDEADCHAR = 263 - WM_SYSKEYDOWN = 260 - WM_SYSKEYUP = 261 - WM_TCARD = 82 - WM_THEMECHANGED = 794 - WM_TIMECHANGE = 30 - WM_TIMER = 275 - WM_UNDO = 772 - WM_USER = 1024 - WM_USERCHANGED = 84 - WM_VKEYTOITEM = 46 - WM_VSCROLL = 277 - WM_VSCROLLCLIPBOARD = 778 - WM_WINDOWPOSCHANGED = 71 - WM_WINDOWPOSCHANGING = 70 - WM_WININICHANGE = 26 - WM_KEYFIRST = 256 - WM_KEYLAST = 264 - WM_SYNCPAINT = 136 - WM_MOUSEACTIVATE = 33 - WM_MOUSEMOVE = 512 - WM_LBUTTONDOWN = 513 - WM_LBUTTONUP = 514 - WM_LBUTTONDBLCLK = 515 - WM_RBUTTONDOWN = 516 - WM_RBUTTONUP = 517 - WM_RBUTTONDBLCLK = 518 - WM_MBUTTONDOWN = 519 - WM_MBUTTONUP = 520 - WM_MBUTTONDBLCLK = 521 - WM_MOUSEWHEEL = 522 - WM_MOUSEFIRST = 512 - WM_XBUTTONDOWN = 523 - WM_XBUTTONUP = 524 - WM_XBUTTONDBLCLK = 525 - WM_MOUSELAST = 525 - WM_MOUSEHOVER = 0x2A1 - WM_MOUSELEAVE = 0x2A3 - WM_CLIPBOARDUPDATE = 0x031D - - WS_EX_APPWINDOW = 0x00040000 - WS_OVERLAPPEDWINDOW = 0x00000000 | 0x00C00000 | 0x00080000 | 0x00040000 | 0x00020000 | 0x00010000 - WS_EX_NOREDIRECTIONBITMAP = 0x00200000 - CW_USEDEFAULT = ^0x7fffffff - - NIM_ADD = 0x00000000 - NIM_MODIFY = 0x00000001 - NIM_DELETE = 0x00000002 - NIM_SETVERSION = 0x00000004 - - NIF_MESSAGE = 0x00000001 - NIF_ICON = 0x00000002 - NIF_TIP = 0x00000004 - NIF_STATE = 0x00000008 - NIF_INFO = 0x00000010 - - NIS_HIDDEN = 0x00000001 - - NIIF_NONE = 0x00000000 - NIIF_INFO = 0x00000001 - NIIF_WARNING = 0x00000002 - NIIF_ERROR = 0x00000003 - NIIF_USER = 0x00000004 - NIIF_NOSOUND = 0x00000010 - NIIF_LARGE_ICON = 0x00000020 - NIIF_RESPECT_QUIET_TIME = 0x00000080 - NIIF_ICON_MASK = 0x0000000F - - IMAGE_BITMAP = 0 - IMAGE_ICON = 1 - LR_LOADFROMFILE = 0x00000010 - LR_DEFAULTSIZE = 0x00000040 - - IDC_ARROW = 32512 - COLOR_WINDOW = 5 - COLOR_BTNFACE = 15 - - GWLP_USERDATA = -21 - WS_CLIPSIBLINGS = 0x04000000 - WS_EX_CONTROLPARENT = 0x00010000 - - HWND_MESSAGE = ^HWND(2) - NOTIFYICON_VERSION = 4 - - IDI_APPLICATION = 32512 - - MenuItemMsgID = WM_APP + 1024 - NotifyIconMessageId = WM_APP + iota - - MF_STRING = 0x00000000 - MF_ENABLED = 0x00000000 - MF_GRAYED = 0x00000001 - MF_DISABLED = 0x00000002 - MF_SEPARATOR = 0x00000800 - MF_UNCHECKED = 0x00000000 - MF_CHECKED = 0x00000008 - MF_POPUP = 0x00000010 - MF_MENUBARBREAK = 0x00000020 - MF_BYCOMMAND = 0x00000000 - - TPM_LEFTALIGN = 0x0000 - - CS_VREDRAW = 0x0001 - CS_HREDRAW = 0x0002 -) - -func WMMessageToString(msg uintptr) string { - // Convert windows message to string - switch msg { - case WM_APP: - return "WM_APP" - case WM_ACTIVATE: - return "WM_ACTIVATE" - case WM_ACTIVATEAPP: - return "WM_ACTIVATEAPP" - case WM_AFXFIRST: - return "WM_AFXFIRST" - case WM_AFXLAST: - return "WM_AFXLAST" - case WM_ASKCBFORMATNAME: - return "WM_ASKCBFORMATNAME" - case WM_CANCELJOURNAL: - return "WM_CANCELJOURNAL" - case WM_CANCELMODE: - return "WM_CANCELMODE" - case WM_CAPTURECHANGED: - return "WM_CAPTURECHANGED" - case WM_CHANGECBCHAIN: - return "WM_CHANGECBCHAIN" - case WM_CHAR: - return "WM_CHAR" - case WM_CHARTOITEM: - return "WM_CHARTOITEM" - case WM_CHILDACTIVATE: - return "WM_CHILDACTIVATE" - case WM_CLEAR: - return "WM_CLEAR" - case WM_CLOSE: - return "WM_CLOSE" - case WM_COMMAND: - return "WM_COMMAND" - case WM_COMMNOTIFY /* OBSOLETE */ : - return "WM_COMMNOTIFY" - case WM_COMPACTING: - return "WM_COMPACTING" - case WM_COMPAREITEM: - return "WM_COMPAREITEM" - case WM_CONTEXTMENU: - return "WM_CONTEXTMENU" - case WM_COPY: - return "WM_COPY" - case WM_COPYDATA: - return "WM_COPYDATA" - case WM_CREATE: - return "WM_CREATE" - case WM_CTLCOLORBTN: - return "WM_CTLCOLORBTN" - case WM_CTLCOLORDLG: - return "WM_CTLCOLORDLG" - case WM_CTLCOLOREDIT: - return "WM_CTLCOLOREDIT" - case WM_CTLCOLORLISTBOX: - return "WM_CTLCOLORLISTBOX" - case WM_CTLCOLORMSGBOX: - return "WM_CTLCOLORMSGBOX" - case WM_CTLCOLORSCROLLBAR: - return "WM_CTLCOLORSCROLLBAR" - case WM_CTLCOLORSTATIC: - return "WM_CTLCOLORSTATIC" - case WM_CUT: - return "WM_CUT" - case WM_DEADCHAR: - return "WM_DEADCHAR" - case WM_DELETEITEM: - return "WM_DELETEITEM" - case WM_DESTROY: - return "WM_DESTROY" - case WM_DESTROYCLIPBOARD: - return "WM_DESTROYCLIPBOARD" - case WM_DEVICECHANGE: - return "WM_DEVICECHANGE" - case WM_DEVMODECHANGE: - return "WM_DEVMODECHANGE" - case WM_DISPLAYCHANGE: - return "WM_DISPLAYCHANGE" - case WM_DRAWCLIPBOARD: - return "WM_DRAWCLIPBOARD" - case WM_DRAWITEM: - return "WM_DRAWITEM" - case WM_DROPFILES: - return "WM_DROPFILES" - case WM_ENABLE: - return "WM_ENABLE" - case WM_ENDSESSION: - return "WM_ENDSESSION" - case WM_ENTERIDLE: - return "WM_ENTERIDLE" - case WM_ENTERMENULOOP: - return "WM_ENTERMENULOOP" - case WM_ENTERSIZEMOVE: - return "WM_ENTERSIZEMOVE" - case WM_ERASEBKGND: - return "WM_ERASEBKGND" - case WM_EXITMENULOOP: - return "WM_EXITMENULOOP" - case WM_EXITSIZEMOVE: - return "WM_EXITSIZEMOVE" - case WM_FONTCHANGE: - return "WM_FONTCHANGE" - case WM_GETDLGCODE: - return "WM_GETDLGCODE" - case WM_GETFONT: - return "WM_GETFONT" - case WM_GETHOTKEY: - return "WM_GETHOTKEY" - case WM_GETICON: - return "WM_GETICON" - case WM_GETMINMAXINFO: - return "WM_GETMINMAXINFO" - case WM_GETTEXT: - return "WM_GETTEXT" - case WM_GETTEXTLENGTH: - return "WM_GETTEXTLENGTH" - case WM_HANDHELDFIRST: - return "WM_HANDHELDFIRST" - case WM_HANDHELDLAST: - return "WM_HANDHELDLAST" - case WM_HELP: - return "WM_HELP" - case WM_HOTKEY: - return "WM_HOTKEY" - case WM_HSCROLL: - return "WM_HSCROLL" - case WM_HSCROLLCLIPBOARD: - return "WM_HSCROLLCLIPBOARD" - case WM_ICONERASEBKGND: - return "WM_ICONERASEBKGND" - case WM_INITDIALOG: - return "WM_INITDIALOG" - case WM_INITMENU: - return "WM_INITMENU" - case WM_INITMENUPOPUP: - return "WM_INITMENUPOPUP" - case WM_INPUT: - return "WM_INPUT" - case WM_INPUTLANGCHANGE: - return "WM_INPUTLANGCHANGE" - case WM_INPUTLANGCHANGEREQUEST: - return "WM_INPUTLANGCHANGEREQUEST" - case WM_KEYDOWN: - return "WM_KEYDOWN" - case WM_KEYUP: - return "WM_KEYUP" - case WM_KILLFOCUS: - return "WM_KILLFOCUS" - case WM_MDIACTIVATE: - return "WM_MDIACTIVATE" - case WM_MDICASCADE: - return "WM_MDICASCADE" - case WM_MDICREATE: - return "WM_MDICREATE" - case WM_MDIDESTROY: - return "WM_MDIDESTROY" - case WM_MDIGETACTIVE: - return "WM_MDIGETACTIVE" - case WM_MDIICONARRANGE: - return "WM_MDIICONARRANGE" - case WM_MDIMAXIMIZE: - return "WM_MDIMAXIMIZE" - case WM_MDINEXT: - return "WM_MDINEXT" - case WM_MDIREFRESHMENU: - return "WM_MDIREFRESHMENU" - case WM_MDIRESTORE: - return "WM_MDIRESTORE" - case WM_MDISETMENU: - return "WM_MDISETMENU" - case WM_MDITILE: - return "WM_MDITILE" - case WM_MEASUREITEM: - return "WM_MEASUREITEM" - case WM_GETOBJECT: - return "WM_GETOBJECT" - case WM_CHANGEUISTATE: - return "WM_CHANGEUISTATE" - case WM_UPDATEUISTATE: - return "WM_UPDATEUISTATE" - case WM_QUERYUISTATE: - return "WM_QUERYUISTATE" - case WM_UNINITMENUPOPUP: - return "WM_UNINITMENUPOPUP" - case WM_MENURBUTTONUP: - return "WM_MENURBUTTONUP" - case WM_MENUCOMMAND: - return "WM_MENUCOMMAND" - case WM_MENUGETOBJECT: - return "WM_MENUGETOBJECT" - case WM_MENUDRAG: - return "WM_MENUDRAG" - case WM_APPCOMMAND: - return "WM_APPCOMMAND" - case WM_MENUCHAR: - return "WM_MENUCHAR" - case WM_MENUSELECT: - return "WM_MENUSELECT" - case WM_MOVE: - return "WM_MOVE" - case WM_MOVING: - return "WM_MOVING" - case WM_NCACTIVATE: - return "WM_NCACTIVATE" - case WM_NCCALCSIZE: - return "WM_NCCALCSIZE" - case WM_NCCREATE: - return "WM_NCCREATE" - case WM_NCDESTROY: - return "WM_NCDESTROY" - case WM_NCHITTEST: - return "WM_NCHITTEST" - case WM_NCLBUTTONDBLCLK: - return "WM_NCLBUTTONDBLCLK" - case WM_NCLBUTTONDOWN: - return "WM_NCLBUTTONDOWN" - case WM_NCLBUTTONUP: - return "WM_NCLBUTTONUP" - case WM_NCMBUTTONDBLCLK: - return "WM_NCMBUTTONDBLCLK" - case WM_NCMBUTTONDOWN: - return "WM_NCMBUTTONDOWN" - case WM_NCMBUTTONUP: - return "WM_NCMBUTTONUP" - case WM_NCXBUTTONDOWN: - return "WM_NCXBUTTONDOWN" - case WM_NCXBUTTONUP: - return "WM_NCXBUTTONUP" - case WM_NCXBUTTONDBLCLK: - return "WM_NCXBUTTONDBLCLK" - case WM_NCMOUSEHOVER: - return "WM_NCMOUSEHOVER" - case WM_NCMOUSELEAVE: - return "WM_NCMOUSELEAVE" - case WM_NCMOUSEMOVE: - return "WM_NCMOUSEMOVE" - case WM_NCPAINT: - return "WM_NCPAINT" - case WM_NCRBUTTONDBLCLK: - return "WM_NCRBUTTONDBLCLK" - case WM_NCRBUTTONDOWN: - return "WM_NCRBUTTONDOWN" - case WM_NCRBUTTONUP: - return "WM_NCRBUTTONUP" - case WM_NEXTDLGCTL: - return "WM_NEXTDLGCTL" - case WM_NEXTMENU: - return "WM_NEXTMENU" - case WM_NOTIFY: - return "WM_NOTIFY" - case WM_NOTIFYFORMAT: - return "WM_NOTIFYFORMAT" - case WM_NULL: - return "WM_NULL" - case WM_PAINT: - return "WM_PAINT" - case WM_PAINTCLIPBOARD: - return "WM_PAINTCLIPBOARD" - case WM_PAINTICON: - return "WM_PAINTICON" - case WM_PALETTECHANGED: - return "WM_PALETTECHANGED" - case WM_PALETTEISCHANGING: - return "WM_PALETTEISCHANGING" - case WM_PARENTNOTIFY: - return "WM_PARENTNOTIFY" - case WM_PASTE: - return "WM_PASTE" - case WM_PENWINFIRST: - return "WM_PENWINFIRST" - case WM_PENWINLAST: - return "WM_PENWINLAST" - case WM_POWER: - return "WM_POWER" - case WM_PRINT: - return "WM_PRINT" - case WM_PRINTCLIENT: - return "WM_PRINTCLIENT" - case WM_QUERYDRAGICON: - return "WM_QUERYDRAGICON" - case WM_QUERYENDSESSION: - return "WM_QUERYENDSESSION" - case WM_QUERYNEWPALETTE: - return "WM_QUERYNEWPALETTE" - case WM_QUERYOPEN: - return "WM_QUERYOPEN" - case WM_QUEUESYNC: - return "WM_QUEUESYNC" - case WM_QUIT: - return "WM_QUIT" - case WM_RENDERALLFORMATS: - return "WM_RENDERALLFORMATS" - case WM_RENDERFORMAT: - return "WM_RENDERFORMAT" - case WM_SETCURSOR: - return "WM_SETCURSOR" - case WM_SETFOCUS: - return "WM_SETFOCUS" - case WM_SETFONT: - return "WM_SETFONT" - case WM_SETHOTKEY: - return "WM_SETHOTKEY" - case WM_SETICON: - return "WM_SETICON" - case WM_SETREDRAW: - return "WM_SETREDRAW" - case WM_SETTEXT: - return "WM_SETTEXT" - case WM_SETTINGCHANGE: - return "WM_SETTINGCHANGE" - case WM_SHOWWINDOW: - return "WM_SHOWWINDOW" - case WM_SIZE: - return "WM_SIZE" - case WM_SIZECLIPBOARD: - return "WM_SIZECLIPBOARD" - case WM_SIZING: - return "WM_SIZING" - case WM_SPOOLERSTATUS: - return "WM_SPOOLERSTATUS" - case WM_STYLECHANGED: - return "WM_STYLECHANGED" - case WM_STYLECHANGING: - return "WM_STYLECHANGING" - case WM_SYSCHAR: - return "WM_SYSCHAR" - case WM_SYSCOLORCHANGE: - return "WM_SYSCOLORCHANGE" - case WM_SYSCOMMAND: - return "WM_SYSCOMMAND" - case WM_SYSDEADCHAR: - return "WM_SYSDEADCHAR" - case WM_SYSKEYDOWN: - return "WM_SYSKEYDOWN" - case WM_SYSKEYUP: - return "WM_SYSKEYUP" - case WM_TCARD: - return "WM_TCARD" - case WM_THEMECHANGED: - return "WM_THEMECHANGED" - case WM_TIMECHANGE: - return "WM_TIMECHANGE" - case WM_TIMER: - return "WM_TIMER" - case WM_UNDO: - return "WM_UNDO" - case WM_USER: - return "WM_USER" - case WM_USERCHANGED: - return "WM_USERCHANGED" - case WM_VKEYTOITEM: - return "WM_VKEYTOITEM" - case WM_VSCROLL: - return "WM_VSCROLL" - case WM_VSCROLLCLIPBOARD: - return "WM_VSCROLLCLIPBOARD" - case WM_WINDOWPOSCHANGED: - return "WM_WINDOWPOSCHANGED" - case WM_WINDOWPOSCHANGING: - return "WM_WINDOWPOSCHANGING" - case WM_KEYLAST: - return "WM_KEYLAST" - case WM_SYNCPAINT: - return "WM_SYNCPAINT" - case WM_MOUSEACTIVATE: - return "WM_MOUSEACTIVATE" - case WM_MOUSEMOVE: - return "WM_MOUSEMOVE" - case WM_LBUTTONDOWN: - return "WM_LBUTTONDOWN" - case WM_LBUTTONUP: - return "WM_LBUTTONUP" - case WM_LBUTTONDBLCLK: - return "WM_LBUTTONDBLCLK" - case WM_RBUTTONDOWN: - return "WM_RBUTTONDOWN" - case WM_RBUTTONUP: - return "WM_RBUTTONUP" - case WM_RBUTTONDBLCLK: - return "WM_RBUTTONDBLCLK" - case WM_MBUTTONDOWN: - return "WM_MBUTTONDOWN" - case WM_MBUTTONUP: - return "WM_MBUTTONUP" - case WM_MBUTTONDBLCLK: - return "WM_MBUTTONDBLCLK" - case WM_MOUSEWHEEL: - return "WM_MOUSEWHEEL" - case WM_XBUTTONDOWN: - return "WM_XBUTTONDOWN" - case WM_XBUTTONUP: - return "WM_XBUTTONUP" - case WM_MOUSELAST: - return "WM_MOUSELAST" - case WM_MOUSEHOVER: - return "WM_MOUSEHOVER" - case WM_MOUSELEAVE: - return "WM_MOUSELEAVE" - case WM_CLIPBOARDUPDATE: - return "WM_CLIPBOARDUPDATE" - default: - return fmt.Sprintf("0x%08x", msg) - } -} - -var windowsVersion, _ = operatingsystem.GetWindowsVersionInfo() - -func IsWindowsVersionAtLeast(major, minor, buildNumber int) bool { - return windowsVersion.Major >= major && - windowsVersion.Minor >= minor && - windowsVersion.Build >= buildNumber -} - -type WindowProc func(hwnd HWND, msg uint32, wparam, lparam uintptr) uintptr - -func GetModuleHandle(value uintptr) uintptr { - result, _, _ := procGetModuleHandle.Call(value) - return result -} - -func GetMessage(msg *MSG) uintptr { - rt, _, _ := procGetMessageW.Call(uintptr(unsafe.Pointer(msg)), 0, 0, 0) - return rt -} - -func PostMessage(hwnd HWND, msg uint32, wParam, lParam uintptr) uintptr { - ret, _, _ := procPostMessage.Call( - uintptr(hwnd), - uintptr(msg), - wParam, - lParam) - - return ret -} - -func ShellNotifyIcon(cmd uintptr, nid *NOTIFYICONDATA) bool { - ret, _, _ := procShellNotifyIcon.Call(cmd, uintptr(unsafe.Pointer(nid))) - return ret == 1 -} - -func IsDialogMessage(hwnd HWND, msg *MSG) uintptr { - ret, _, _ := procIsDialogMessage.Call(uintptr(hwnd), uintptr(unsafe.Pointer(msg))) - return ret -} - -func TranslateMessage(msg *MSG) uintptr { - ret, _, _ := procTranslateMessage.Call(uintptr(unsafe.Pointer(msg))) - return ret -} - -func DispatchMessage(msg *MSG) uintptr { - ret, _, _ := procDispatchMessage.Call(uintptr(unsafe.Pointer(msg))) - return ret -} - -func PostQuitMessage(exitCode int32) { - procPostQuitMessage.Call(uintptr(exitCode)) -} - -func LoHiWords(input uint32) (uint16, uint16) { - return uint16(input & 0xffff), uint16(input >> 16 & 0xffff) -} diff --git a/v2/internal/platform/win32/cursor.go b/v2/internal/platform/win32/cursor.go deleted file mode 100644 index 04449a91b..000000000 --- a/v2/internal/platform/win32/cursor.go +++ /dev/null @@ -1,11 +0,0 @@ -//go:build windows - -package win32 - -import "unsafe" - -func GetCursorPos() (x, y int, ok bool) { - pt := POINT{} - ret, _, _ := procGetCursorPos.Call(uintptr(unsafe.Pointer(&pt))) - return int(pt.X), int(pt.Y), ret != 0 -} diff --git a/v2/internal/platform/win32/icon.go b/v2/internal/platform/win32/icon.go deleted file mode 100644 index 916b92d44..000000000 --- a/v2/internal/platform/win32/icon.go +++ /dev/null @@ -1,41 +0,0 @@ -//go:build windows - -package win32 - -import ( - "unsafe" -) - -func CreateIconFromResourceEx(presbits uintptr, dwResSize uint32, isIcon bool, version uint32, cxDesired int, cyDesired int, flags uint) (uintptr, error) { - icon := 0 - if isIcon { - icon = 1 - } - r, _, err := procCreateIconFromResourceEx.Call( - presbits, - uintptr(dwResSize), - uintptr(icon), - uintptr(version), - uintptr(cxDesired), - uintptr(cyDesired), - uintptr(flags), - ) - - if r == 0 { - return 0, err - } - return r, nil -} - -// CreateHIconFromPNG creates a HICON from a PNG file -func CreateHIconFromPNG(pngData []byte) (HICON, error) { - icon, err := CreateIconFromResourceEx( - uintptr(unsafe.Pointer(&pngData[0])), - uint32(len(pngData)), - true, - 0x00030000, - 0, - 0, - LR_DEFAULTSIZE) - return HICON(icon), err -} diff --git a/v2/internal/platform/win32/keyboard.go b/v2/internal/platform/win32/keyboard.go deleted file mode 100644 index 7a86d6643..000000000 --- a/v2/internal/platform/win32/keyboard.go +++ /dev/null @@ -1,810 +0,0 @@ -//go:build windows - -/* - * Copyright (C) 2019 The Winc Authors. All Rights Reserved. - * Copyright (C) 2010-2013 Allen Dang. All Rights Reserved. - */ - -package win32 - -import ( - "bytes" - "github.com/wailsapp/wails/v2/pkg/menu/keys" - "strings" - "unsafe" -) - -type Key uint16 - -func (k Key) String() string { - return key2string[k] -} - -// Virtual key codes -const ( - VK_LBUTTON = 1 - VK_RBUTTON = 2 - VK_CANCEL = 3 - VK_MBUTTON = 4 - VK_XBUTTON1 = 5 - VK_XBUTTON2 = 6 - VK_BACK = 8 - VK_TAB = 9 - VK_CLEAR = 12 - VK_RETURN = 13 - VK_SHIFT = 16 - VK_CONTROL = 17 - VK_MENU = 18 - VK_PAUSE = 19 - VK_CAPITAL = 20 - VK_KANA = 0x15 - VK_HANGEUL = 0x15 - VK_HANGUL = 0x15 - VK_JUNJA = 0x17 - VK_FINAL = 0x18 - VK_HANJA = 0x19 - VK_KANJI = 0x19 - VK_ESCAPE = 0x1B - VK_CONVERT = 0x1C - VK_NONCONVERT = 0x1D - VK_ACCEPT = 0x1E - VK_MODECHANGE = 0x1F - VK_SPACE = 32 - VK_PRIOR = 33 - VK_NEXT = 34 - VK_END = 35 - VK_HOME = 36 - VK_LEFT = 37 - VK_UP = 38 - VK_RIGHT = 39 - VK_DOWN = 40 - VK_SELECT = 41 - VK_PRINT = 42 - VK_EXECUTE = 43 - VK_SNAPSHOT = 44 - VK_INSERT = 45 - VK_DELETE = 46 - VK_HELP = 47 - VK_LWIN = 0x5B - VK_RWIN = 0x5C - VK_APPS = 0x5D - VK_SLEEP = 0x5F - VK_NUMPAD0 = 0x60 - VK_NUMPAD1 = 0x61 - VK_NUMPAD2 = 0x62 - VK_NUMPAD3 = 0x63 - VK_NUMPAD4 = 0x64 - VK_NUMPAD5 = 0x65 - VK_NUMPAD6 = 0x66 - VK_NUMPAD7 = 0x67 - VK_NUMPAD8 = 0x68 - VK_NUMPAD9 = 0x69 - VK_MULTIPLY = 0x6A - VK_ADD = 0x6B - VK_SEPARATOR = 0x6C - VK_SUBTRACT = 0x6D - VK_DECIMAL = 0x6E - VK_DIVIDE = 0x6F - VK_F1 = 0x70 - VK_F2 = 0x71 - VK_F3 = 0x72 - VK_F4 = 0x73 - VK_F5 = 0x74 - VK_F6 = 0x75 - VK_F7 = 0x76 - VK_F8 = 0x77 - VK_F9 = 0x78 - VK_F10 = 0x79 - VK_F11 = 0x7A - VK_F12 = 0x7B - VK_F13 = 0x7C - VK_F14 = 0x7D - VK_F15 = 0x7E - VK_F16 = 0x7F - VK_F17 = 0x80 - VK_F18 = 0x81 - VK_F19 = 0x82 - VK_F20 = 0x83 - VK_F21 = 0x84 - VK_F22 = 0x85 - VK_F23 = 0x86 - VK_F24 = 0x87 - VK_NUMLOCK = 0x90 - VK_SCROLL = 0x91 - VK_LSHIFT = 0xA0 - VK_RSHIFT = 0xA1 - VK_LCONTROL = 0xA2 - VK_RCONTROL = 0xA3 - VK_LMENU = 0xA4 - VK_RMENU = 0xA5 - VK_BROWSER_BACK = 0xA6 - VK_BROWSER_FORWARD = 0xA7 - VK_BROWSER_REFRESH = 0xA8 - VK_BROWSER_STOP = 0xA9 - VK_BROWSER_SEARCH = 0xAA - VK_BROWSER_FAVORITES = 0xAB - VK_BROWSER_HOME = 0xAC - VK_VOLUME_MUTE = 0xAD - VK_VOLUME_DOWN = 0xAE - VK_VOLUME_UP = 0xAF - VK_MEDIA_NEXT_TRACK = 0xB0 - VK_MEDIA_PREV_TRACK = 0xB1 - VK_MEDIA_STOP = 0xB2 - VK_MEDIA_PLAY_PAUSE = 0xB3 - VK_LAUNCH_MAIL = 0xB4 - VK_LAUNCH_MEDIA_SELECT = 0xB5 - VK_LAUNCH_APP1 = 0xB6 - VK_LAUNCH_APP2 = 0xB7 - VK_OEM_1 = 0xBA - VK_OEM_PLUS = 0xBB - VK_OEM_COMMA = 0xBC - VK_OEM_MINUS = 0xBD - VK_OEM_PERIOD = 0xBE - VK_OEM_2 = 0xBF - VK_OEM_3 = 0xC0 - VK_OEM_4 = 0xDB - VK_OEM_5 = 0xDC - VK_OEM_6 = 0xDD - VK_OEM_7 = 0xDE - VK_OEM_8 = 0xDF - VK_OEM_102 = 0xE2 - VK_PROCESSKEY = 0xE5 - VK_PACKET = 0xE7 - VK_ATTN = 0xF6 - VK_CRSEL = 0xF7 - VK_EXSEL = 0xF8 - VK_EREOF = 0xF9 - VK_PLAY = 0xFA - VK_ZOOM = 0xFB - VK_NONAME = 0xFC - VK_PA1 = 0xFD - VK_OEM_CLEAR = 0xFE -) - -const ( - KeyLButton Key = VK_LBUTTON - KeyRButton Key = VK_RBUTTON - KeyCancel Key = VK_CANCEL - KeyMButton Key = VK_MBUTTON - KeyXButton1 Key = VK_XBUTTON1 - KeyXButton2 Key = VK_XBUTTON2 - KeyBack Key = VK_BACK - KeyTab Key = VK_TAB - KeyClear Key = VK_CLEAR - KeyReturn Key = VK_RETURN - KeyShift Key = VK_SHIFT - KeyControl Key = VK_CONTROL - KeyAlt Key = VK_MENU - KeyMenu Key = VK_MENU - KeyPause Key = VK_PAUSE - KeyCapital Key = VK_CAPITAL - KeyKana Key = VK_KANA - KeyHangul Key = VK_HANGUL - KeyJunja Key = VK_JUNJA - KeyFinal Key = VK_FINAL - KeyHanja Key = VK_HANJA - KeyKanji Key = VK_KANJI - KeyEscape Key = VK_ESCAPE - KeyConvert Key = VK_CONVERT - KeyNonconvert Key = VK_NONCONVERT - KeyAccept Key = VK_ACCEPT - KeyModeChange Key = VK_MODECHANGE - KeySpace Key = VK_SPACE - KeyPrior Key = VK_PRIOR - KeyNext Key = VK_NEXT - KeyEnd Key = VK_END - KeyHome Key = VK_HOME - KeyLeft Key = VK_LEFT - KeyUp Key = VK_UP - KeyRight Key = VK_RIGHT - KeyDown Key = VK_DOWN - KeySelect Key = VK_SELECT - KeyPrint Key = VK_PRINT - KeyExecute Key = VK_EXECUTE - KeySnapshot Key = VK_SNAPSHOT - KeyInsert Key = VK_INSERT - KeyDelete Key = VK_DELETE - KeyHelp Key = VK_HELP - Key0 Key = 0x30 - Key1 Key = 0x31 - Key2 Key = 0x32 - Key3 Key = 0x33 - Key4 Key = 0x34 - Key5 Key = 0x35 - Key6 Key = 0x36 - Key7 Key = 0x37 - Key8 Key = 0x38 - Key9 Key = 0x39 - KeyA Key = 0x41 - KeyB Key = 0x42 - KeyC Key = 0x43 - KeyD Key = 0x44 - KeyE Key = 0x45 - KeyF Key = 0x46 - KeyG Key = 0x47 - KeyH Key = 0x48 - KeyI Key = 0x49 - KeyJ Key = 0x4A - KeyK Key = 0x4B - KeyL Key = 0x4C - KeyM Key = 0x4D - KeyN Key = 0x4E - KeyO Key = 0x4F - KeyP Key = 0x50 - KeyQ Key = 0x51 - KeyR Key = 0x52 - KeyS Key = 0x53 - KeyT Key = 0x54 - KeyU Key = 0x55 - KeyV Key = 0x56 - KeyW Key = 0x57 - KeyX Key = 0x58 - KeyY Key = 0x59 - KeyZ Key = 0x5A - KeyLWIN Key = VK_LWIN - KeyRWIN Key = VK_RWIN - KeyApps Key = VK_APPS - KeySleep Key = VK_SLEEP - KeyNumpad0 Key = VK_NUMPAD0 - KeyNumpad1 Key = VK_NUMPAD1 - KeyNumpad2 Key = VK_NUMPAD2 - KeyNumpad3 Key = VK_NUMPAD3 - KeyNumpad4 Key = VK_NUMPAD4 - KeyNumpad5 Key = VK_NUMPAD5 - KeyNumpad6 Key = VK_NUMPAD6 - KeyNumpad7 Key = VK_NUMPAD7 - KeyNumpad8 Key = VK_NUMPAD8 - KeyNumpad9 Key = VK_NUMPAD9 - KeyMultiply Key = VK_MULTIPLY - KeyAdd Key = VK_ADD - KeySeparator Key = VK_SEPARATOR - KeySubtract Key = VK_SUBTRACT - KeyDecimal Key = VK_DECIMAL - KeyDivide Key = VK_DIVIDE - KeyF1 Key = VK_F1 - KeyF2 Key = VK_F2 - KeyF3 Key = VK_F3 - KeyF4 Key = VK_F4 - KeyF5 Key = VK_F5 - KeyF6 Key = VK_F6 - KeyF7 Key = VK_F7 - KeyF8 Key = VK_F8 - KeyF9 Key = VK_F9 - KeyF10 Key = VK_F10 - KeyF11 Key = VK_F11 - KeyF12 Key = VK_F12 - KeyF13 Key = VK_F13 - KeyF14 Key = VK_F14 - KeyF15 Key = VK_F15 - KeyF16 Key = VK_F16 - KeyF17 Key = VK_F17 - KeyF18 Key = VK_F18 - KeyF19 Key = VK_F19 - KeyF20 Key = VK_F20 - KeyF21 Key = VK_F21 - KeyF22 Key = VK_F22 - KeyF23 Key = VK_F23 - KeyF24 Key = VK_F24 - KeyNumlock Key = VK_NUMLOCK - KeyScroll Key = VK_SCROLL - KeyLShift Key = VK_LSHIFT - KeyRShift Key = VK_RSHIFT - KeyLControl Key = VK_LCONTROL - KeyRControl Key = VK_RCONTROL - KeyLAlt Key = VK_LMENU - KeyLMenu Key = VK_LMENU - KeyRAlt Key = VK_RMENU - KeyRMenu Key = VK_RMENU - KeyBrowserBack Key = VK_BROWSER_BACK - KeyBrowserForward Key = VK_BROWSER_FORWARD - KeyBrowserRefresh Key = VK_BROWSER_REFRESH - KeyBrowserStop Key = VK_BROWSER_STOP - KeyBrowserSearch Key = VK_BROWSER_SEARCH - KeyBrowserFavorites Key = VK_BROWSER_FAVORITES - KeyBrowserHome Key = VK_BROWSER_HOME - KeyVolumeMute Key = VK_VOLUME_MUTE - KeyVolumeDown Key = VK_VOLUME_DOWN - KeyVolumeUp Key = VK_VOLUME_UP - KeyMediaNextTrack Key = VK_MEDIA_NEXT_TRACK - KeyMediaPrevTrack Key = VK_MEDIA_PREV_TRACK - KeyMediaStop Key = VK_MEDIA_STOP - KeyMediaPlayPause Key = VK_MEDIA_PLAY_PAUSE - KeyLaunchMail Key = VK_LAUNCH_MAIL - KeyLaunchMediaSelect Key = VK_LAUNCH_MEDIA_SELECT - KeyLaunchApp1 Key = VK_LAUNCH_APP1 - KeyLaunchApp2 Key = VK_LAUNCH_APP2 - KeyOEM1 Key = VK_OEM_1 - KeyOEMPlus Key = VK_OEM_PLUS - KeyOEMComma Key = VK_OEM_COMMA - KeyOEMMinus Key = VK_OEM_MINUS - KeyOEMPeriod Key = VK_OEM_PERIOD - KeyOEM2 Key = VK_OEM_2 - KeyOEM3 Key = VK_OEM_3 - KeyOEM4 Key = VK_OEM_4 - KeyOEM5 Key = VK_OEM_5 - KeyOEM6 Key = VK_OEM_6 - KeyOEM7 Key = VK_OEM_7 - KeyOEM8 Key = VK_OEM_8 - KeyOEM102 Key = VK_OEM_102 - KeyProcessKey Key = VK_PROCESSKEY - KeyPacket Key = VK_PACKET - KeyAttn Key = VK_ATTN - KeyCRSel Key = VK_CRSEL - KeyEXSel Key = VK_EXSEL - KeyErEOF Key = VK_EREOF - KeyPlay Key = VK_PLAY - KeyZoom Key = VK_ZOOM - KeyNoName Key = VK_NONAME - KeyPA1 Key = VK_PA1 - KeyOEMClear Key = VK_OEM_CLEAR -) - -var key2string = map[Key]string{ - KeyLButton: "LButton", - KeyRButton: "RButton", - KeyCancel: "Cancel", - KeyMButton: "MButton", - KeyXButton1: "XButton1", - KeyXButton2: "XButton2", - KeyBack: "Back", - KeyTab: "Tab", - KeyClear: "Clear", - KeyReturn: "Return", - KeyShift: "Shift", - KeyControl: "Control", - KeyAlt: "Alt / Menu", - KeyPause: "Pause", - KeyCapital: "Capital", - KeyKana: "Kana / Hangul", - KeyJunja: "Junja", - KeyFinal: "Final", - KeyHanja: "Hanja / Kanji", - KeyEscape: "Escape", - KeyConvert: "Convert", - KeyNonconvert: "Nonconvert", - KeyAccept: "Accept", - KeyModeChange: "ModeChange", - KeySpace: "Space", - KeyPrior: "Prior", - KeyNext: "Next", - KeyEnd: "End", - KeyHome: "Home", - KeyLeft: "Left", - KeyUp: "Up", - KeyRight: "Right", - KeyDown: "Down", - KeySelect: "Select", - KeyPrint: "Print", - KeyExecute: "Execute", - KeySnapshot: "Snapshot", - KeyInsert: "Insert", - KeyDelete: "Delete", - KeyHelp: "Help", - Key0: "0", - Key1: "1", - Key2: "2", - Key3: "3", - Key4: "4", - Key5: "5", - Key6: "6", - Key7: "7", - Key8: "8", - Key9: "9", - KeyA: "A", - KeyB: "B", - KeyC: "C", - KeyD: "D", - KeyE: "E", - KeyF: "F", - KeyG: "G", - KeyH: "H", - KeyI: "I", - KeyJ: "J", - KeyK: "K", - KeyL: "L", - KeyM: "M", - KeyN: "N", - KeyO: "O", - KeyP: "P", - KeyQ: "Q", - KeyR: "R", - KeyS: "S", - KeyT: "T", - KeyU: "U", - KeyV: "V", - KeyW: "W", - KeyX: "X", - KeyY: "Y", - KeyZ: "Z", - KeyLWIN: "LWIN", - KeyRWIN: "RWIN", - KeyApps: "Apps", - KeySleep: "Sleep", - KeyNumpad0: "Numpad0", - KeyNumpad1: "Numpad1", - KeyNumpad2: "Numpad2", - KeyNumpad3: "Numpad3", - KeyNumpad4: "Numpad4", - KeyNumpad5: "Numpad5", - KeyNumpad6: "Numpad6", - KeyNumpad7: "Numpad7", - KeyNumpad8: "Numpad8", - KeyNumpad9: "Numpad9", - KeyMultiply: "Multiply", - KeyAdd: "Add", - KeySeparator: "Separator", - KeySubtract: "Subtract", - KeyDecimal: "Decimal", - KeyDivide: "Divide", - KeyF1: "F1", - KeyF2: "F2", - KeyF3: "F3", - KeyF4: "F4", - KeyF5: "F5", - KeyF6: "F6", - KeyF7: "F7", - KeyF8: "F8", - KeyF9: "F9", - KeyF10: "F10", - KeyF11: "F11", - KeyF12: "F12", - KeyF13: "F13", - KeyF14: "F14", - KeyF15: "F15", - KeyF16: "F16", - KeyF17: "F17", - KeyF18: "F18", - KeyF19: "F19", - KeyF20: "F20", - KeyF21: "F21", - KeyF22: "F22", - KeyF23: "F23", - KeyF24: "F24", - KeyNumlock: "Numlock", - KeyScroll: "Scroll", - KeyLShift: "LShift", - KeyRShift: "RShift", - KeyLControl: "LControl", - KeyRControl: "RControl", - KeyLMenu: "LMenu", - KeyRMenu: "RMenu", - KeyBrowserBack: "BrowserBack", - KeyBrowserForward: "BrowserForward", - KeyBrowserRefresh: "BrowserRefresh", - KeyBrowserStop: "BrowserStop", - KeyBrowserSearch: "BrowserSearch", - KeyBrowserFavorites: "BrowserFavorites", - KeyBrowserHome: "BrowserHome", - KeyVolumeMute: "VolumeMute", - KeyVolumeDown: "VolumeDown", - KeyVolumeUp: "VolumeUp", - KeyMediaNextTrack: "MediaNextTrack", - KeyMediaPrevTrack: "MediaPrevTrack", - KeyMediaStop: "MediaStop", - KeyMediaPlayPause: "MediaPlayPause", - KeyLaunchMail: "LaunchMail", - KeyLaunchMediaSelect: "LaunchMediaSelect", - KeyLaunchApp1: "LaunchApp1", - KeyLaunchApp2: "LaunchApp2", - KeyOEM1: "OEM1", - KeyOEMPlus: "OEMPlus", - KeyOEMComma: "OEMComma", - KeyOEMMinus: "OEMMinus", - KeyOEMPeriod: "OEMPeriod", - KeyOEM2: "OEM2", - KeyOEM3: "OEM3", - KeyOEM4: "OEM4", - KeyOEM5: "OEM5", - KeyOEM6: "OEM6", - KeyOEM7: "OEM7", - KeyOEM8: "OEM8", - KeyOEM102: "OEM102", - KeyProcessKey: "ProcessKey", - KeyPacket: "Packet", - KeyAttn: "Attn", - KeyCRSel: "CRSel", - KeyEXSel: "EXSel", - KeyErEOF: "ErEOF", - KeyPlay: "Play", - KeyZoom: "Zoom", - KeyNoName: "NoName", - KeyPA1: "PA1", - KeyOEMClear: "OEMClear", -} - -type Modifiers byte - -func (m Modifiers) String() string { - return modifiers2string[m] -} - -var modifiers2string = map[Modifiers]string{ - ModShift: "Shift", - ModControl: "Ctrl", - ModControl | ModShift: "Ctrl+Shift", - ModAlt: "Alt", - ModAlt | ModShift: "Alt+Shift", - ModAlt | ModControl | ModShift: "Alt+Ctrl+Shift", -} - -const ( - ModShift Modifiers = 1 << iota - ModControl - ModAlt -) - -func ModifiersDown() Modifiers { - var m Modifiers - - if ShiftDown() { - m |= ModShift - } - if ControlDown() { - m |= ModControl - } - if AltDown() { - m |= ModAlt - } - - return m -} - -type Shortcut struct { - Modifiers Modifiers - Key Key -} - -func (s Shortcut) String() string { - m := s.Modifiers.String() - if m == "" { - return s.Key.String() - } - - b := new(bytes.Buffer) - - b.WriteString(m) - b.WriteRune('+') - b.WriteString(s.Key.String()) - - return b.String() -} - -func GetKeyState(nVirtKey int32) int16 { - ret, _, _ := procGetKeyState.Call( - uintptr(nVirtKey), - ) - - return int16(ret) -} - -func AltDown() bool { - return GetKeyState(int32(KeyAlt))>>15 != 0 -} - -func ControlDown() bool { - return GetKeyState(int32(KeyControl))>>15 != 0 -} - -func ShiftDown() bool { - return GetKeyState(int32(KeyShift))>>15 != 0 -} - -var ModifierMap = map[keys.Modifier]Modifiers{ - keys.ShiftKey: ModShift, - keys.ControlKey: ModControl, - keys.OptionOrAltKey: ModAlt, - keys.CmdOrCtrlKey: ModControl, -} - -var NoShortcut = Shortcut{} - -func AcceleratorToShortcut(accelerator *keys.Accelerator) Shortcut { - - if accelerator == nil { - return NoShortcut - } - inKey := strings.ToUpper(accelerator.Key) - key, exists := KeyMap[inKey] - if !exists { - return NoShortcut - } - var modifiers Modifiers - if _, exists := shiftMap[inKey]; exists { - modifiers = ModShift - } - for _, mod := range accelerator.Modifiers { - modifiers |= ModifierMap[mod] - } - return Shortcut{ - Modifiers: modifiers, - Key: key, - } -} - -var shiftMap = map[string]struct{}{ - "~": {}, - ")": {}, - "!": {}, - "@": {}, - "#": {}, - "$": {}, - "%": {}, - "^": {}, - "&": {}, - "*": {}, - "(": {}, - "_": {}, - "PLUS": {}, - "<": {}, - ">": {}, - "?": {}, - ":": {}, - `"`: {}, - "{": {}, - "}": {}, - "|": {}, -} - -var KeyMap = map[string]Key{ - "0": Key0, - "1": Key1, - "2": Key2, - "3": Key3, - "4": Key4, - "5": Key5, - "6": Key6, - "7": Key7, - "8": Key8, - "9": Key9, - "A": KeyA, - "B": KeyB, - "C": KeyC, - "D": KeyD, - "E": KeyE, - "F": KeyF, - "G": KeyG, - "H": KeyH, - "I": KeyI, - "J": KeyJ, - "K": KeyK, - "L": KeyL, - "M": KeyM, - "N": KeyN, - "O": KeyO, - "P": KeyP, - "Q": KeyQ, - "R": KeyR, - "S": KeyS, - "T": KeyT, - "U": KeyU, - "V": KeyV, - "W": KeyW, - "X": KeyX, - "Y": KeyY, - "Z": KeyZ, - "F1": KeyF1, - "F2": KeyF2, - "F3": KeyF3, - "F4": KeyF4, - "F5": KeyF5, - "F6": KeyF6, - "F7": KeyF7, - "F8": KeyF8, - "F9": KeyF9, - "F10": KeyF10, - "F11": KeyF11, - "F12": KeyF12, - "F13": KeyF13, - "F14": KeyF14, - "F15": KeyF15, - "F16": KeyF16, - "F17": KeyF17, - "F18": KeyF18, - "F19": KeyF19, - "F20": KeyF20, - "F21": KeyF21, - "F22": KeyF22, - "F23": KeyF23, - "F24": KeyF24, - - "`": KeyOEM3, - ",": KeyOEMComma, - ".": KeyOEMPeriod, - "/": KeyOEM2, - ";": KeyOEM1, - "'": KeyOEM7, - "[": KeyOEM4, - "]": KeyOEM6, - `\`: KeyOEM5, - "~": KeyOEM3, - ")": Key0, - "!": Key1, - "@": Key2, - "#": Key3, - "$": Key4, - "%": Key5, - "^": Key6, - "&": Key7, - "*": Key8, - "(": Key9, - "_": KeyOEMMinus, - "PLUS": KeyOEMPlus, - "<": KeyOEMComma, - ">": KeyOEMPeriod, - "?": KeyOEM2, - ":": KeyOEM1, - `"`: KeyOEM7, - "{": KeyOEM4, - "}": KeyOEM6, - "|": KeyOEM5, - - "SPACE": KeySpace, - "TAB": KeyTab, - "CAPSLOCK": KeyCapital, - "NUMLOCK": KeyNumlock, - "SCROLLLOCK": KeyScroll, - "BACKSPACE": KeyBack, - "DELETE": KeyDelete, - "INSERT": KeyInsert, - "RETURN": KeyReturn, - "ENTER": KeyReturn, - "UP": KeyUp, - "DOWN": KeyDown, - "LEFT": KeyLeft, - "RIGHT": KeyRight, - "HOME": KeyHome, - "END": KeyEnd, - "PAGEUP": KeyPrior, - "PAGEDOWN": KeyNext, - "ESCAPE": KeyEscape, - "ESC": KeyEscape, - "VOLUMEUP": KeyVolumeUp, - "VOLUMEDOWN": KeyVolumeDown, - "VOLUMEMUTE": KeyVolumeMute, - "MEDIANEXTTRACK": KeyMediaNextTrack, - "MEDIAPREVIOUSTRACK": KeyMediaPrevTrack, - "MEDIASTOP": KeyMediaStop, - "MEDIAPLAYPAUSE": KeyMediaPlayPause, - "PRINTSCREEN": KeyPrint, - "NUM0": KeyNumpad0, - "NUM1": KeyNumpad1, - "NUM2": KeyNumpad2, - "NUM3": KeyNumpad3, - "NUM4": KeyNumpad4, - "NUM5": KeyNumpad5, - "NUM6": KeyNumpad6, - "NUM7": KeyNumpad7, - "NUM8": KeyNumpad8, - "NUM9": KeyNumpad9, - "nummult": KeyMultiply, - "numadd": KeyAdd, - "numsub": KeySubtract, - "numdec": KeyDecimal, - "numdiv": KeyDivide, -} - -type Accelerator struct { - Virtual byte - Key uint16 - Cmd uint16 -} - -func CreateAcceleratorTable(acc []Accelerator) uintptr { - if len(acc) == 0 { - return 0 - } - ret, _, _ := procCreateAcceleratorTable.Call( - uintptr(unsafe.Pointer(&acc[0])), - uintptr(len(acc)), - ) - return ret -} - -func TranslateAccelerator(hwnd HWND, hAccTable uintptr, lpMsg *MSG) bool { - ret, _, _ := procTranslateAccelerator.Call( - uintptr(hwnd), - hAccTable, - uintptr(unsafe.Pointer(lpMsg)), - ) - return ret != 0 -} diff --git a/v2/internal/platform/win32/menu.go b/v2/internal/platform/win32/menu.go deleted file mode 100644 index f05886414..000000000 --- a/v2/internal/platform/win32/menu.go +++ /dev/null @@ -1,82 +0,0 @@ -//go:build windows - -package win32 - -type Menu HMENU -type PopupMenu Menu - -func CreatePopupMenu() PopupMenu { - ret, _, _ := procCreatePopupMenu.Call(0, 0, 0, 0) - return PopupMenu(ret) -} - -func (m Menu) Destroy() bool { - ret, _, _ := procDestroyMenu.Call(uintptr(m)) - return ret != 0 -} - -func (p PopupMenu) Destroy() bool { - return Menu(p).Destroy() -} - -func (p PopupMenu) Track(flags uint, x, y int, wnd HWND) bool { - ret, _, _ := procTrackPopupMenu.Call( - uintptr(p), - uintptr(flags), - uintptr(x), - uintptr(y), - 0, - uintptr(wnd), - 0, - ) - return ret != 0 -} - -func (p PopupMenu) Append(flags uintptr, id uintptr, text string) bool { - return Menu(p).Append(flags, id, text) -} - -func (m Menu) Append(flags uintptr, id uintptr, text string) bool { - ret, _, _ := procAppendMenuW.Call( - uintptr(m), - flags, - id, - MustStringToUTF16uintptr(text), - ) - return ret != 0 -} - -func (p PopupMenu) Check(id uintptr, checked bool) bool { - return Menu(p).Check(id, checked) -} - -func (m Menu) Check(id uintptr, check bool) bool { - var checkState uint = MF_UNCHECKED - if check { - checkState = MF_CHECKED - } - return CheckMenuItem(HMENU(m), id, checkState) != 0 -} - -func (m Menu) CheckRadio(startID int, endID int, selectedID int) bool { - ret, _, _ := procCheckMenuRadioItem.Call( - uintptr(m), - uintptr(startID), - uintptr(endID), - uintptr(selectedID), - MF_BYCOMMAND) - return ret != 0 -} - -func CheckMenuItem(menu HMENU, id uintptr, flags uint) uint { - ret, _, _ := procCheckMenuItem.Call( - uintptr(menu), - id, - uintptr(flags), - ) - return uint(ret) -} - -func (p PopupMenu) CheckRadio(startID, endID, selectedID int) bool { - return Menu(p).CheckRadio(startID, endID, selectedID) -} diff --git a/v2/internal/platform/win32/structs.go b/v2/internal/platform/win32/structs.go deleted file mode 100644 index 3f79d8585..000000000 --- a/v2/internal/platform/win32/structs.go +++ /dev/null @@ -1,51 +0,0 @@ -//go:build windows - -package win32 - -import "golang.org/x/sys/windows" - -type NOTIFYICONDATA struct { - CbSize uint32 - HWnd HWND - UID uint32 - UFlags uint32 - UCallbackMessage uint32 - HIcon HICON - SzTip [128]uint16 - DwState uint32 - DwStateMask uint32 - SzInfo [256]uint16 - UVersion uint32 - SzInfoTitle [64]uint16 - DwInfoFlags uint32 - GuidItem windows.GUID - HBalloonIcon HICON -} - -type WNDCLASSEX struct { - CbSize uint32 - Style uint32 - LpfnWndProc uintptr - CbClsExtra int32 - CbWndExtra int32 - HInstance HINSTANCE - HIcon HICON - HCursor HCURSOR - HbrBackground HBRUSH - LpszMenuName *uint16 - LpszClassName *uint16 - HIconSm HICON -} - -type MSG struct { - HWnd HWND - Message uint32 - WParam uintptr - LParam uintptr - Time uint32 - Pt POINT -} - -type POINT struct { - X, Y int32 -} diff --git a/v2/internal/platform/win32/theme.go b/v2/internal/platform/win32/theme.go deleted file mode 100644 index ad29b1201..000000000 --- a/v2/internal/platform/win32/theme.go +++ /dev/null @@ -1,191 +0,0 @@ -//go:build windows - -package win32 - -import ( - "golang.org/x/sys/windows/registry" - "unsafe" -) - -type DWMWINDOWATTRIBUTE int32 - -const DwmwaUseImmersiveDarkModeBefore20h1 DWMWINDOWATTRIBUTE = 19 -const DwmwaUseImmersiveDarkMode DWMWINDOWATTRIBUTE = 20 -const DwmwaBorderColor DWMWINDOWATTRIBUTE = 34 -const DwmwaCaptionColor DWMWINDOWATTRIBUTE = 35 -const DwmwaTextColor DWMWINDOWATTRIBUTE = 36 -const DwmwaSystemBackdropType DWMWINDOWATTRIBUTE = 38 - -const SPI_GETHIGHCONTRAST = 0x0042 -const HCF_HIGHCONTRASTON = 0x00000001 -const WCA_ACCENT_POLICY WINDOWCOMPOSITIONATTRIB = 19 - -type ACCENT_STATE DWORD - -const ( - ACCENT_DISABLED ACCENT_STATE = 0 - ACCENT_ENABLE_GRADIENT ACCENT_STATE = 1 - ACCENT_ENABLE_TRANSPARENTGRADIENT ACCENT_STATE = 2 - ACCENT_ENABLE_BLURBEHIND ACCENT_STATE = 3 - ACCENT_ENABLE_ACRYLICBLURBEHIND ACCENT_STATE = 4 // RS4 1803 - ACCENT_ENABLE_HOSTBACKDROP ACCENT_STATE = 5 // RS5 1809 - ACCENT_INVALID_STATE ACCENT_STATE = 6 -) - -type ACCENT_POLICY struct { - AccentState ACCENT_STATE - AccentFlags DWORD - GradientColor DWORD - AnimationId DWORD -} - -type WINDOWCOMPOSITIONATTRIBDATA struct { - Attrib WINDOWCOMPOSITIONATTRIB - PvData unsafe.Pointer - CbData uintptr -} - -type WINDOWCOMPOSITIONATTRIB DWORD - -// BackdropType defines the type of translucency we wish to use -type BackdropType int32 - -const ( - BackdropTypeAuto BackdropType = 0 - BackdropTypeNone BackdropType = 1 - BackdropTypeMica BackdropType = 2 - BackdropTypeAcrylic BackdropType = 3 - BackdropTypeTabbed BackdropType = 4 -) - -func dwmSetWindowAttribute(hwnd HWND, dwAttribute DWMWINDOWATTRIBUTE, pvAttribute unsafe.Pointer, cbAttribute uintptr) { - ret, _, err := procDwmSetWindowAttribute.Call( - uintptr(hwnd), - uintptr(dwAttribute), - uintptr(pvAttribute), - cbAttribute) - if ret != 0 { - _ = err - // println(err.Error()) - } -} - -func SupportsThemes() bool { - // We can't support Windows versions before 17763 - return IsWindowsVersionAtLeast(10, 0, 17763) -} - -func SupportsCustomThemes() bool { - return IsWindowsVersionAtLeast(10, 0, 17763) -} - -func SupportsBackdropTypes() bool { - return IsWindowsVersionAtLeast(10, 0, 22621) -} - -func SupportsImmersiveDarkMode() bool { - return IsWindowsVersionAtLeast(10, 0, 18985) -} - -func SetTheme(hwnd HWND, useDarkMode bool) { - if SupportsThemes() { - attr := DwmwaUseImmersiveDarkModeBefore20h1 - if SupportsImmersiveDarkMode() { - attr = DwmwaUseImmersiveDarkMode - } - var winDark int32 - if useDarkMode { - winDark = 1 - } - dwmSetWindowAttribute(hwnd, attr, unsafe.Pointer(&winDark), unsafe.Sizeof(winDark)) - } -} - -func EnableBlurBehind(hwnd HWND) { - var accent = ACCENT_POLICY{ - AccentState: ACCENT_ENABLE_ACRYLICBLURBEHIND, - AccentFlags: 0x2, - } - var data WINDOWCOMPOSITIONATTRIBDATA - data.Attrib = WCA_ACCENT_POLICY - data.PvData = unsafe.Pointer(&accent) - data.CbData = unsafe.Sizeof(accent) - - SetWindowCompositionAttribute(hwnd, &data) -} - -func SetWindowCompositionAttribute(hwnd HWND, data *WINDOWCOMPOSITIONATTRIBDATA) bool { - if procSetWindowCompositionAttribute != nil { - ret, _, _ := procSetWindowCompositionAttribute.Call( - uintptr(hwnd), - uintptr(unsafe.Pointer(data)), - ) - return ret != 0 - } - return false -} - -func EnableTranslucency(hwnd HWND, backdrop BackdropType) { - if SupportsBackdropTypes() { - dwmSetWindowAttribute(hwnd, DwmwaSystemBackdropType, unsafe.Pointer(&backdrop), unsafe.Sizeof(backdrop)) - } else { - println("Warning: Translucency type unavailable on Windows < 22621") - } -} - -func SetTitleBarColour(hwnd HWND, titleBarColour int32) { - dwmSetWindowAttribute(hwnd, DwmwaCaptionColor, unsafe.Pointer(&titleBarColour), unsafe.Sizeof(titleBarColour)) -} - -func SetTitleTextColour(hwnd HWND, titleTextColour int32) { - dwmSetWindowAttribute(hwnd, DwmwaTextColor, unsafe.Pointer(&titleTextColour), unsafe.Sizeof(titleTextColour)) -} - -func SetBorderColour(hwnd HWND, titleBorderColour int32) { - dwmSetWindowAttribute(hwnd, DwmwaBorderColor, unsafe.Pointer(&titleBorderColour), unsafe.Sizeof(titleBorderColour)) -} - -func SetWindowTheme(hwnd HWND, appName string, subIdList string) uintptr { - var subID uintptr - if subIdList != "" { - subID = MustStringToUTF16uintptr(subIdList) - } - ret, _, _ := procSetWindowTheme.Call( - uintptr(hwnd), - MustStringToUTF16uintptr(appName), - subID, - ) - - return ret -} -func IsCurrentlyDarkMode() bool { - key, err := registry.OpenKey(registry.CURRENT_USER, `SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize`, registry.QUERY_VALUE) - if err != nil { - return false - } - defer key.Close() - - AppsUseLightTheme, _, err := key.GetIntegerValue("AppsUseLightTheme") - if err != nil { - return false - } - return AppsUseLightTheme == 0 -} - -type highContrast struct { - CbSize uint32 - DwFlags uint32 - LpszDefaultScheme *int16 -} - -func IsCurrentlyHighContrastMode() bool { - var result highContrast - result.CbSize = uint32(unsafe.Sizeof(result)) - res, _, err := procSystemParametersInfo.Call(SPI_GETHIGHCONTRAST, uintptr(result.CbSize), uintptr(unsafe.Pointer(&result)), 0) - if res == 0 { - _ = err - return false - } - r := result.DwFlags&HCF_HIGHCONTRASTON == HCF_HIGHCONTRASTON - return r -} diff --git a/v2/internal/platform/win32/window.go b/v2/internal/platform/win32/window.go deleted file mode 100644 index 0ca31ecee..000000000 --- a/v2/internal/platform/win32/window.go +++ /dev/null @@ -1,139 +0,0 @@ -//go:build windows - -package win32 - -import ( - "fmt" - "github.com/samber/lo" - "golang.org/x/sys/windows" - "syscall" - "unsafe" -) - -func LoadIconWithResourceID(instance HINSTANCE, res uintptr) HICON { - ret, _, _ := procLoadIcon.Call( - uintptr(instance), - res) - - return HICON(ret) -} - -func LoadCursorWithResourceID(instance HINSTANCE, res uintptr) HCURSOR { - ret, _, _ := procLoadCursor.Call( - uintptr(instance), - res) - - return HCURSOR(ret) -} - -func RegisterClassEx(wndClassEx *WNDCLASSEX) ATOM { - ret, _, _ := procRegisterClassEx.Call(uintptr(unsafe.Pointer(wndClassEx))) - return ATOM(ret) -} - -func RegisterClass(className string, wndproc uintptr, instance HINSTANCE) error { - classNamePtr, err := syscall.UTF16PtrFromString(className) - if err != nil { - return err - } - icon := LoadIconWithResourceID(instance, IDI_APPLICATION) - - var wc WNDCLASSEX - wc.CbSize = uint32(unsafe.Sizeof(wc)) - wc.Style = CS_HREDRAW | CS_VREDRAW - wc.LpfnWndProc = wndproc - wc.HInstance = instance - wc.HbrBackground = COLOR_WINDOW + 1 - wc.HIcon = icon - wc.HCursor = LoadCursorWithResourceID(0, IDC_ARROW) - wc.LpszClassName = classNamePtr - wc.LpszMenuName = nil - wc.HIconSm = icon - - if ret := RegisterClassEx(&wc); ret == 0 { - return syscall.GetLastError() - } - - return nil -} - -func CreateWindow(className string, instance HINSTANCE, parent HWND, exStyle, style uint) HWND { - - classNamePtr := lo.Must(syscall.UTF16PtrFromString(className)) - - result := CreateWindowEx( - exStyle, - classNamePtr, - nil, - style, - CW_USEDEFAULT, - CW_USEDEFAULT, - CW_USEDEFAULT, - CW_USEDEFAULT, - parent, - 0, - instance, - nil) - - if result == 0 { - errStr := fmt.Sprintf("Error occurred in CreateWindow(%s, %v, %d, %d)", className, parent, exStyle, style) - panic(errStr) - } - - return result -} - -func CreateWindowEx(exStyle uint, className, windowName *uint16, - style uint, x, y, width, height int, parent HWND, menu HMENU, - instance HINSTANCE, param unsafe.Pointer) HWND { - ret, _, _ := procCreateWindowEx.Call( - uintptr(exStyle), - uintptr(unsafe.Pointer(className)), - uintptr(unsafe.Pointer(windowName)), - uintptr(style), - uintptr(x), - uintptr(y), - uintptr(width), - uintptr(height), - uintptr(parent), - uintptr(menu), - uintptr(instance), - uintptr(param)) - - return HWND(ret) -} - -func MustStringToUTF16Ptr(input string) *uint16 { - ret, err := syscall.UTF16PtrFromString(input) - if err != nil { - panic(err) - } - return ret -} - -func MustStringToUTF16uintptr(input string) uintptr { - ret, err := syscall.UTF16PtrFromString(input) - if err != nil { - panic(err) - } - return uintptr(unsafe.Pointer(ret)) -} - -func MustUTF16FromString(input string) []uint16 { - ret, err := syscall.UTF16FromString(input) - if err != nil { - panic(err) - } - return ret -} - -func UTF16PtrToString(input uintptr) string { - return windows.UTF16PtrToString((*uint16)(unsafe.Pointer(input))) -} - -func SetForegroundWindow(wnd HWND) bool { - ret, _, _ := procSetForegroundWindow.Call( - uintptr(wnd), - ) - return ret != 0 -} diff --git a/v2/internal/process/process.go b/v2/internal/process/process.go index 18c9f45da..6d497ed8e 100644 --- a/v2/internal/process/process.go +++ b/v2/internal/process/process.go @@ -25,6 +25,7 @@ func NewProcess(cmd string, args ...string) *Process { // Start the process func (p *Process) Start(exitCodeChannel chan int) error { + err := p.cmd.Start() if err != nil { return err diff --git a/v2/internal/project/project.go b/v2/internal/project/project.go index 2df99bdfa..148f4eda6 100644 --- a/v2/internal/project/project.go +++ b/v2/internal/project/project.go @@ -2,32 +2,23 @@ package project import ( "encoding/json" + "io/ioutil" "os" "path/filepath" "runtime" "strings" - - "github.com/samber/lo" ) // Project holds the data related to a Wails project type Project struct { + /*** Application Data ***/ Name string `json:"name"` - AssetDirectory string `json:"assetdir,omitempty"` - - ReloadDirectories string `json:"reloaddirs,omitempty"` + AssetDirectory string `json:"assetdir"` BuildCommand string `json:"frontend:build"` InstallCommand string `json:"frontend:install"` - - // Commands used in `wails dev` - DevCommand string `json:"frontend:dev"` - DevBuildCommand string `json:"frontend:dev:build"` - DevInstallCommand string `json:"frontend:dev:install"` - DevWatcherCommand string `json:"frontend:dev:watcher"` - // The url of the external wails dev server. If this is set, this server is used for the frontend. Default "" - FrontendDevServerURL string `json:"frontend:dev:serverUrl"` + DevCommand string `json:"frontend:dev"` // Directory to generate the API Module WailsJSDir string `json:"wailsjsdir"` @@ -37,13 +28,10 @@ type Project struct { /*** Internal Data ***/ // The path to the project directory - Path string `json:"projectdir"` + Path string // Build directory - BuildDir string `json:"build:dir"` - - // BuildTags Extra tags to process during build - BuildTags string `json:"build:tags"` + BuildDir string // The output filename OutputFilename string `json:"outputfilename"` @@ -54,94 +42,17 @@ type Project struct { // The platform to target Platform string - // RunNonNativeBuildHooks will run build hooks though they are defined for a GOOS which is not equal to the host os - RunNonNativeBuildHooks bool `json:"runNonNativeBuildHooks"` - - // Build hooks for different targets, the hooks are executed in the following order - // Key: GOOS/GOARCH - Executed at build level before/after a build of the specific platform and arch - // Key: GOOS/* - Executed at build level before/after a build of the specific platform - // Key: */* - Executed at build level before/after a build - // The following keys are not yet supported. - // Key: GOOS - Executed at platform level before/after all builds of the specific platform - // Key: * - Executed at platform level before/after all builds of a platform - // Key: [empty] - Executed at global level before/after all builds of all platforms - PostBuildHooks map[string]string `json:"postBuildHooks"` - PreBuildHooks map[string]string `json:"preBuildHooks"` - // The application author Author Author - // The application information - Info Info - // Fully qualified filename filename string // The debounce time for hot-reload of the built-in dev server. Default 100 DebounceMS int `json:"debounceMS"` - // The address to bind the wails dev server to. Default "localhost:34115" - DevServer string `json:"devServer"` - - // Arguments that are forward to the application in dev mode - AppArgs string `json:"appargs"` - - // NSISType to be build - NSISType string `json:"nsisType"` - - // Garble - Obfuscated bool `json:"obfuscated"` - GarbleArgs string `json:"garbleargs"` - - // Frontend directory - FrontendDir string `json:"frontend:dir"` - - // The timeout in seconds for Vite server detection. Default 10 - ViteServerTimeout int `json:"viteServerTimeout"` - - Bindings Bindings `json:"bindings"` -} - -func (p *Project) GetFrontendDir() string { - if filepath.IsAbs(p.FrontendDir) { - return p.FrontendDir - } - return filepath.Join(p.Path, p.FrontendDir) -} - -func (p *Project) GetWailsJSDir() string { - if filepath.IsAbs(p.WailsJSDir) { - return p.WailsJSDir - } - return filepath.Join(p.Path, p.WailsJSDir) -} - -func (p *Project) GetBuildDir() string { - if filepath.IsAbs(p.BuildDir) { - return p.BuildDir - } - return filepath.Join(p.Path, p.BuildDir) -} - -func (p *Project) GetDevBuildCommand() string { - if p.DevBuildCommand != "" { - return p.DevBuildCommand - } - if p.DevCommand != "" { - return p.DevCommand - } - return p.BuildCommand -} - -func (p *Project) GetDevInstallerCommand() string { - if p.DevInstallCommand != "" { - return p.DevInstallCommand - } - return p.InstallCommand -} - -func (p *Project) IsFrontendDevServerURLAutoDiscovery() bool { - return p.FrontendDevServerURL == "auto" + // The url to use to server assets. Default "https://localhost:34115" + DevServerURL string `json:"devserverurl"` } func (p *Project) Save() error { @@ -149,71 +60,7 @@ func (p *Project) Save() error { if err != nil { return err } - return os.WriteFile(p.filename, data, 0o755) -} - -func (p *Project) setDefaults() { - if p.Path == "" { - p.Path = lo.Must(os.Getwd()) - } - if p.Version == "" { - p.Version = "2" - } - // Create default name if not given - if p.Name == "" { - p.Name = "wailsapp" - } - if p.OutputFilename == "" { - p.OutputFilename = p.Name - } - if p.FrontendDir == "" { - p.FrontendDir = "frontend" - } - if p.WailsJSDir == "" { - p.WailsJSDir = p.FrontendDir - } - if p.BuildDir == "" { - p.BuildDir = "build" - } - if p.DebounceMS == 0 { - p.DebounceMS = 100 - } - if p.DevServer == "" { - p.DevServer = "localhost:34115" - } - if p.ViteServerTimeout == 0 { - p.ViteServerTimeout = 10 - } - if p.NSISType == "" { - p.NSISType = "multiple" - } - if p.Info.CompanyName == "" { - p.Info.CompanyName = p.Name - } - if p.Info.ProductName == "" { - p.Info.ProductName = p.Name - } - if p.Info.ProductVersion == "" { - p.Info.ProductVersion = "1.0.0" - } - if p.Info.Copyright == nil { - v := "Copyright........." - p.Info.Copyright = &v - } - if p.Info.Comments == nil { - v := "Built using Wails (https://wails.io)" - p.Info.Comments = &v - } - - // Fix up OutputFilename - switch runtime.GOOS { - case "windows": - if !strings.HasSuffix(p.OutputFilename, ".exe") { - p.OutputFilename += ".exe" - } - case "darwin", "linux": - p.OutputFilename = strings.TrimSuffix(p.OutputFilename, ".exe") - } + return os.WriteFile(p.filename, data, 0755) } // Author stores details about the application author @@ -222,62 +69,47 @@ type Author struct { Email string `json:"email"` } -type Info struct { - CompanyName string `json:"companyName"` - ProductName string `json:"productName"` - ProductVersion string `json:"productVersion"` - Copyright *string `json:"copyright"` - Comments *string `json:"comments"` - FileAssociations []FileAssociation `json:"fileAssociations"` - Protocols []Protocol `json:"protocols"` -} - -type FileAssociation struct { - Ext string `json:"ext"` - Name string `json:"name"` - Description string `json:"description"` - IconName string `json:"iconName"` - Role string `json:"role"` -} - -type Protocol struct { - Scheme string `json:"scheme"` - Description string `json:"description"` - Role string `json:"role"` -} - -type Bindings struct { - TsGeneration TsGeneration `json:"ts_generation"` -} - -type TsGeneration struct { - Prefix string `json:"prefix"` - Suffix string `json:"suffix"` - OutputType string `json:"outputType"` -} - -// Parse the given JSON data into a Project struct -func Parse(projectData []byte) (*Project, error) { - project := &Project{} - err := json.Unmarshal(projectData, project) - if err != nil { - return nil, err - } - project.setDefaults() - return project, nil -} - // Load the project from the current working directory func Load(projectPath string) (*Project, error) { + + // Attempt to load project.json projectFile := filepath.Join(projectPath, "wails.json") - rawBytes, err := os.ReadFile(projectFile) + rawBytes, err := ioutil.ReadFile(projectFile) if err != nil { return nil, err } - result, err := Parse(rawBytes) + + // Unmarshal JSON + var result Project + err = json.Unmarshal(rawBytes, &result) if err != nil { return nil, err } + + // Fix up our project paths result.filename = projectFile - return result, nil + + if result.Version == "" { + result.Version = "2" + } + + // Create default name if not given + if result.Name == "" { + result.Name = "wailsapp" + } + + // Fix up OutputFilename + switch runtime.GOOS { + case "windows": + if !strings.HasSuffix(result.OutputFilename, ".exe") { + result.OutputFilename += ".exe" + } + case "darwin", "linux": + if strings.HasSuffix(result.OutputFilename, ".exe") { + result.OutputFilename = strings.TrimSuffix(result.OutputFilename, ".exe") + } + } + + // Return our project data + return &result, nil } diff --git a/v2/internal/project/project_test.go b/v2/internal/project/project_test.go deleted file mode 100644 index 8c080307b..000000000 --- a/v2/internal/project/project_test.go +++ /dev/null @@ -1,142 +0,0 @@ -package project_test - -import ( - "os" - "path/filepath" - "runtime" - "testing" - - "github.com/samber/lo" - "github.com/wailsapp/wails/v2/internal/project" -) - -func TestProject_GetFrontendDir(t *testing.T) { - cwd := lo.Must(os.Getwd()) - tests := []struct { - name string - inputJSON string - want string - wantError bool - }{ - { - name: "Should use 'frontend' by default", - inputJSON: "{}", - want: filepath.ToSlash(filepath.Join(cwd, "frontend")), - wantError: false, - }, - { - name: "Should resolve a relative path with no project path", - inputJSON: `{"frontend:dir": "./frontend"}`, - want: filepath.ToSlash(filepath.Join(cwd, "frontend")), - wantError: false, - }, - { - name: "Should resolve a relative path with project path set", - inputJSON: func() string { - if runtime.GOOS == "windows" { - return `{"frontend:dir": "./frontend", "projectdir": "C:\\project"}` - } else { - return `{"frontend:dir": "./frontend", "projectdir": "/home/user/project"}` - } - }(), - want: func() string { - if runtime.GOOS == "windows" { - return `C:/project/frontend` - } else { - return `/home/user/project/frontend` - } - }(), - wantError: false, - }, - { - name: "Should honour an absolute path", - inputJSON: func() string { - if runtime.GOOS == "windows" { - return `{"frontend:dir": "C:\\frontend", "projectdir": "C:\\project"}` - } else { - return `{"frontend:dir": "/home/myproject/frontend", "projectdir": "/home/user/project"}` - } - }(), - want: func() string { - if runtime.GOOS == "windows" { - return `C:/frontend` - } else { - return `/home/myproject/frontend` - } - }(), - wantError: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - proj, err := project.Parse([]byte(tt.inputJSON)) - if err != nil && !tt.wantError { - t.Errorf("Error parsing project: %s", err) - } - got := proj.GetFrontendDir() - got = filepath.ToSlash(got) - if got != tt.want { - t.Errorf("GetFrontendDir() = %v, want %v", got, tt.want) - } - }) - } -} -func TestProject_GetBuildDir(t *testing.T) { - cwd := lo.Must(os.Getwd()) - tests := []struct { - name string - inputJSON string - want string - wantError bool - }{ - { - name: "Should use 'build' by default", - inputJSON: "{}", - want: filepath.ToSlash(filepath.Join(cwd, "build")), - wantError: false, - }, - { - name: "Should resolve a relative path with no project path", - inputJSON: `{"build:dir": "./build"}`, - want: filepath.ToSlash(filepath.Join(cwd, "build")), - wantError: false, - }, - { - name: "Should resolve a relative path with project path set", - inputJSON: `{"build:dir": "./build", "projectdir": "/home/user/project"}`, - want: "/home/user/project/build", - wantError: false, - }, - { - name: "Should honour an absolute path", - inputJSON: func() string { - if runtime.GOOS == "windows" { - return `{"build:dir": "C:\\build", "projectdir": "C:\\project"}` - } else { - return `{"build:dir": "/home/myproject/build", "projectdir": "/home/user/project"}` - } - }(), - want: func() string { - if runtime.GOOS == "windows" { - return `C:/build` - } else { - return `/home/myproject/build` - } - }(), - wantError: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - proj, err := project.Parse([]byte(tt.inputJSON)) - if err != nil && !tt.wantError { - t.Errorf("Error parsing project: %s", err) - } - got := proj.GetBuildDir() - got = filepath.ToSlash(got) - if got != tt.want { - t.Errorf("GetFrontendDir() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/v2/internal/runtime/assets/assets.go b/v2/internal/runtime/assets/assets.go new file mode 100644 index 000000000..cdc0f3b2e --- /dev/null +++ b/v2/internal/runtime/assets/assets.go @@ -0,0 +1,12 @@ +package assets + +import _ "embed" + +//go:embed desktop_darwin.js +var desktopDarwinJS string + +//go:embed desktop_windows.js +var desktopWindowsJS string + +//go:embed wails.js +var wailsJS string diff --git a/v2/internal/runtime/assets/desktop_darwin.js b/v2/internal/runtime/assets/desktop_darwin.js new file mode 100644 index 000000000..4758b4e29 --- /dev/null +++ b/v2/internal/runtime/assets/desktop_darwin.js @@ -0,0 +1 @@ +var Wails=function(n){var t={};function e(r){if(t[r])return t[r].exports;var i=t[r]={i:r,l:!1,exports:{}};return n[r].call(i.exports,i,i.exports,e),i.l=!0,i.exports}return e.m=n,e.c=t,e.d=function(n,t,r){e.o(n,t)||Object.defineProperty(n,t,{enumerable:!0,get:r})},e.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},e.t=function(n,t){if(1&t&&(n=e(n)),8&t)return n;if(4&t&&"object"==typeof n&&n&&n.__esModule)return n;var r=Object.create(null);if(e.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:n}),2&t&&"string"!=typeof n)for(var i in n)e.d(r,i,function(t){return n[t]}.bind(null,i));return r},e.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return e.d(t,"a",t),t},e.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},e.p="",e(e.s=0)}([function(n,t,e){"use strict";e.r(t);var r={};e.r(r),e.d(r,"Trace",(function(){return v})),e.d(r,"Print",(function(){return p})),e.d(r,"Debug",(function(){return y})),e.d(r,"Info",(function(){return m})),e.d(r,"Warning",(function(){return b})),e.d(r,"Error",(function(){return g})),e.d(r,"Fatal",(function(){return h})),e.d(r,"SetLogLevel",(function(){return S})),e.d(r,"Level",(function(){return E}));var i={};e.r(i),e.d(i,"Open",(function(){return x}));var o={};e.r(o),e.d(o,"Center",(function(){return N})),e.d(o,"SetTitle",(function(){return T})),e.d(o,"Fullscreen",(function(){return j})),e.d(o,"UnFullscreen",(function(){return D})),e.d(o,"SetSize",(function(){return I})),e.d(o,"SetPosition",(function(){return P})),e.d(o,"Hide",(function(){return A})),e.d(o,"Show",(function(){return J})),e.d(o,"Maximise",(function(){return L})),e.d(o,"Unmaximise",(function(){return R})),e.d(o,"Minimise",(function(){return _})),e.d(o,"Unminimise",(function(){return F})),e.d(o,"Close",(function(){return U}));var a={};e.r(a),e.d(a,"Open",(function(){return B})),e.d(a,"Save",(function(){return H})),e.d(a,"Message",(function(){return G}));var u={};e.r(u),e.d(u,"New",(function(){return en}));var c={};e.r(c),e.d(c,"SetIcon",(function(){return rn}));var l={AppType:"desktop",Platform:function(){return"darwin"}};var s=[];function f(n){s.push(n)}function d(n){if(function(n){window.wailsInvoke(n)}(n),s.length>0)for(var t=0;t0)var a=setTimeout((function(){i(Error("Call to "+n+" timed out. Request ID: "+o))}),e);k[o]={timeoutHandle:a,reject:i,resolve:r};try{var u={name:n,args:t,callbackID:o};d("C"+JSON.stringify(u))}catch(n){console.error(n)}}))}function W(n){var t;try{t=JSON.parse(n)}catch(t){var e="Invalid JSON passed to callback: ".concat(t.message,". Message: ").concat(n);throw y(e),new Error(e)}var r=t.callbackid,i=k[r];if(!i){var o="Callback '".concat(r,"' not registered!!!");throw console.error(o),new Error(o)}clearTimeout(i.timeoutHandle),delete k[r],t.error?i.reject(t.error):i.resolve(t.result)}function M(n){var t=[].slice.apply(arguments).slice(1);return C(".wails."+n,t)}function x(n){return d("RBO"+n)}function N(){d("Wc")}function T(n){d("WT"+n)}function j(){d("WF")}function D(){d("Wf")}function I(n,t){d("Ws:"+n+":"+t)}function P(n,t){d("Wp:"+n+":"+t)}function A(){d("WH")}function J(){d("WS")}function L(){d("WM")}function R(){d("WU")}function _(){d("Wm")}function F(){d("Wu")}function U(){d("WC")}function B(n){return M("Dialog.Open",n)}function H(n){return M("Dialog.Save",n)}function G(n){return M("Dialog.Message",n)}O=window.crypto?function(){var n=new Uint32Array(1);return window.crypto.getRandomValues(n)[0]}:function(){return 9007199254740991*Math.random()},window.backend={};var q=function n(t,e){!function(n,t){if(!(n instanceof t))throw new TypeError("Cannot call a class as a function")}(this,n),e=e||-1,this.Callback=function(n){return t.apply(null,n),-1!==e&&0===(e-=1)}},z={};function V(n,t,e){z[n]=z[n]||[];var r=new q(t,e);console.log("Pushing event listener: "+n),z[n].push(r)}function K(n,t){V(n,t)}function Q(n,t){V(n,t,1)}function X(n){var t=n.name;if(z[t]){for(var e=z[t].slice(),r=0;r0)for(var t=0;t0)var a=setTimeout((function(){i(Error("Call to "+n+" timed out. Request ID: "+o))}),e);k[o]={timeoutHandle:a,reject:i,resolve:r};try{var u={name:n,args:t,callbackID:o};d("C"+JSON.stringify(u))}catch(n){console.error(n)}}))}function W(n){var t;try{t=JSON.parse(n)}catch(t){var e="Invalid JSON passed to callback: ".concat(t.message,". Message: ").concat(n);throw y(e),new Error(e)}var r=t.callbackid,i=k[r];if(!i){var o="Callback '".concat(r,"' not registered!!!");throw console.error(o),new Error(o)}clearTimeout(i.timeoutHandle),delete k[r],t.error?i.reject(t.error):i.resolve(t.result)}function x(n){var t=[].slice.apply(arguments).slice(1);return C(".wails."+n,t)}function M(n){return d("RBO"+n)}function N(){d("Wc")}function T(n){d("WT"+n)}function j(){d("WF")}function D(){d("Wf")}function I(n,t){d("Ws:"+n+":"+t)}function P(n,t){d("Wp:"+n+":"+t)}function A(){d("WH")}function J(){d("WS")}function L(){d("WM")}function R(){d("WU")}function _(){d("Wm")}function F(){d("Wu")}function U(){d("WC")}function B(n){return x("Dialog.Open",n)}function H(n){return x("Dialog.Save",n)}function G(n){return x("Dialog.Message",n)}O=window.crypto?function(){var n=new Uint32Array(1);return window.crypto.getRandomValues(n)[0]}:function(){return 9007199254740991*Math.random()},window.backend={};var q=function n(t,e){!function(n,t){if(!(n instanceof t))throw new TypeError("Cannot call a class as a function")}(this,n),e=e||-1,this.Callback=function(n){return t.apply(null,n),-1!==e&&0===(e-=1)}},z={};function V(n,t,e){z[n]=z[n]||[];var r=new q(t,e);console.log("Pushing event listener: "+n),z[n].push(r)}function K(n,t){V(n,t)}function Q(n,t){V(n,t,1)}function X(n){var t=n.name;if(z[t]){for(var e=z[t].slice(),r=0;r0)for(var t=0;t0)var a=setTimeout((function(){i(Error("Call to "+n+" timed out. Request ID: "+o))}),e);k[o]={timeoutHandle:a,reject:i,resolve:r};try{var u={name:n,args:t,callbackID:o};d("C"+JSON.stringify(u))}catch(n){console.error(n)}}))}function W(n){var t;try{t=JSON.parse(n)}catch(t){var e="Invalid JSON passed to callback: ".concat(t.message,". Message: ").concat(n);throw y(e),new Error(e)}var r=t.callbackid,i=k[r];if(!i){var o="Callback '".concat(r,"' not registered!!!");throw console.error(o),new Error(o)}clearTimeout(i.timeoutHandle),delete k[r],t.error?i.reject(t.error):i.resolve(t.result)}function N(n){var t=[].slice.apply(arguments).slice(1);return C(".wails."+n,t)}function T(n){return d("RBO"+n)}function j(){d("Wc")}function x(n){d("WT"+n)}function M(){d("WF")}function I(){d("Wf")}function D(n,t){d("Ws:"+n+":"+t)}function P(n,t){d("Wp:"+n+":"+t)}function A(){d("WH")}function J(){d("WS")}function L(){d("WM")}function R(){d("WU")}function _(){d("Wm")}function F(){d("Wu")}function U(){d("WC")}function B(n){return N("Dialog.Open",n)}function H(n){return N("Dialog.Save",n)}function G(n){return N("Dialog.Message",n)}O=window.crypto?function(){var n=new Uint32Array(1);return window.crypto.getRandomValues(n)[0]}:function(){return 9007199254740991*Math.random()},window.backend={};var q=function n(t,e){!function(n,t){if(!(n instanceof t))throw new TypeError("Cannot call a class as a function")}(this,n),e=e||-1,this.Callback=function(n){return t.apply(null,n),-1!==e&&0===(e-=1)}},z={};function V(n,t,e){z[n]=z[n]||[];var r=new q(t,e);console.log("Pushing event listener: "+n),z[n].push(r)}function K(n,t){V(n,t)}function Q(n,t){V(n,t,1)}function X(n){var t=n.name;if(z[t]){for(var e=z[t].slice(),r=0;r0)for(var e=0;e1){var e={name:n,data:[].slice.apply(arguments).slice(1)};a("Ej"+JSON.stringify(e))}else a("ej"+n)}var b={};var m,E={};function O(n,e,t){return null!=t&&null!=t||(t=0),new Promise((function(r,o){var i;do{i=n+"-"+m()}while(E[i]);if(t>0)var c=setTimeout((function(){o(Error("Call to "+n+" timed out. Request ID: "+i))}),t);E[i]={timeoutHandle:c,reject:o,resolve:r};try{JSON.stringify(e);a("call")}catch(n){console.error(n)}}))}function j(n){try{return new Function("var "+n),!0}catch(n){return!1}}function S(){return(S=Object.assign||function(n){for(var e=1;e1)for(var r=0;r + } + ], + outputs: [ + { + type: + } + ] + } + } + } +} + */ + +export function SetBindings(bindingsMap) { + try { + bindingsMap = JSON.parse(bindingsMap); + } catch (e) { + console.error(e); + } + + // Initialise the backend map + window.go = window.go || {}; + + // Iterate package names + Object.keys(bindingsMap).forEach((packageName) => { + + // Create inner map if it doesn't exist + window.go[packageName] = window.go[packageName] || {}; + + // Iterate struct names + Object.keys(bindingsMap[packageName]).forEach((structName) => { + + // Create inner map if it doesn't exist + window.go[packageName][structName] = window.go[packageName][structName] || {}; + + Object.keys(bindingsMap[packageName][structName]).forEach((methodName) => { + + window.go[packageName][structName][methodName] = function () { + + // No timeout by default + let timeout = 0; + + // Actual function + function dynamic() { + var args = [].slice.call(arguments); + return Call([packageName, structName, methodName].join('.'), args, timeout); + } + + // Allow setting timeout to function + dynamic.setTimeout = function (newTimeout) { + timeout = newTimeout; + }; + + // Allow getting timeout to function + dynamic.getTimeout = function () { + return timeout; + }; + + return dynamic; + }(); + }); + }); + }); +} diff --git a/v2/internal/runtime/js/core/calls.js b/v2/internal/runtime/js/core/calls.js new file mode 100644 index 000000000..242fbd8dc --- /dev/null +++ b/v2/internal/runtime/js/core/calls.js @@ -0,0 +1,157 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The electron alternative for Go +(c) Lea Anthony 2019-present +*/ +/* jshint esversion: 6 */ + +import {Debug} from './log'; +import {SendMessage} from 'ipc'; + +var callbacks = {}; + +/** + * Returns a number from the native browser random function + * + * @returns number + */ +function cryptoRandom() { + var array = new Uint32Array(1); + return window.crypto.getRandomValues(array)[0]; +} + +/** + * Returns a number using da old-skool Math.Random + * I likes to call it LOLRandom + * + * @returns number + */ +function basicRandom() { + return Math.random() * 9007199254740991; +} + +// Pick a random number function based on browser capability +var randomFunc; +if (window.crypto) { + randomFunc = cryptoRandom; +} else { + randomFunc = basicRandom; +} + + +/** + * Call sends a message to the backend to call the binding with the + * given data. A promise is returned and will be completed when the + * backend responds. This will be resolved when the call was successful + * or rejected if an error is passed back. + * There is a timeout mechanism. If the call doesn't respond in the given + * time (in milliseconds) then the promise is rejected. + * + * @export + * @param {string} name + * @param {string} args + * @param {number=} timeout + * @returns + */ +export function Call(name, args, timeout) { + + // Timeout infinite by default + if (timeout == null || timeout == undefined) { + timeout = 0; + } + + // Create a promise + return new Promise(function (resolve, reject) { + + // Create a unique callbackID + var callbackID; + do { + callbackID = name + '-' + randomFunc(); + } while (callbacks[callbackID]); + + // Set timeout + if (timeout > 0) { + var timeoutHandle = setTimeout(function () { + reject(Error('Call to ' + name + ' timed out. Request ID: ' + callbackID)); + }, timeout); + } + + // Store callback + callbacks[callbackID] = { + timeoutHandle: timeoutHandle, + reject: reject, + resolve: resolve + }; + + try { + const payload = { + name, + args, + callbackID, + }; + + // Make the call + SendMessage('C' + JSON.stringify(payload)); + } catch (e) { + // eslint-disable-next-line + console.error(e); + } + }); +} + + + +/** + * Called by the backend to return data to a previously called + * binding invocation + * + * @export + * @param {string} incomingMessage + */ +export function Callback(incomingMessage) { + // Decode the message - Credit: https://stackoverflow.com/a/13865680 + //incomingMessage = decodeURIComponent(incomingMessage.replace(/\s+/g, '').replace(/[0-9a-f]{2}/g, '%$&')); + + // Parse the message + var message; + try { + message = JSON.parse(incomingMessage); + } catch (e) { + const error = `Invalid JSON passed to callback: ${e.message}. Message: ${incomingMessage}`; + Debug(error); + throw new Error(error); + } + var callbackID = message.callbackid; + var callbackData = callbacks[callbackID]; + if (!callbackData) { + const error = `Callback '${callbackID}' not registered!!!`; + console.error(error); // eslint-disable-line + throw new Error(error); + } + clearTimeout(callbackData.timeoutHandle); + + delete callbacks[callbackID]; + + if (message.error) { + callbackData.reject(message.error); + } else { + callbackData.resolve(message.result); + } +} + +/** + * SystemCall is used to call wails methods from the frontend + * + * @export + * @param {string} method + * @param {any[]=} data + * @returns + */ +export function SystemCall(method) { + var data = [].slice.apply(arguments).slice(1); + return Call('.wails.' + method, data); +} diff --git a/v2/internal/runtime/js/core/desktop.js b/v2/internal/runtime/js/core/desktop.js new file mode 100644 index 000000000..6649214e9 --- /dev/null +++ b/v2/internal/runtime/js/core/desktop.js @@ -0,0 +1,24 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The electron alternative for Go +(c) Lea Anthony 2019-present +*/ +/* jshint esversion: 6 */ +import {SetBindings} from './bindings'; +import {Init} from './main'; + +// Initialise the Runtime +Init(); + +// Load Bindings if they exist +if (window.wailsbindings) { + SetBindings(window.wailsbindings); +} + +// Emit loaded event. Leaving this for now. It will show any errors if runtime fails to load. +window.wails.Events.Emit('wails:loaded'); + diff --git a/v2/internal/runtime/js/core/events.js b/v2/internal/runtime/js/core/events.js new file mode 100644 index 000000000..f9beebb10 --- /dev/null +++ b/v2/internal/runtime/js/core/events.js @@ -0,0 +1,169 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The electron alternative for Go +(c) Lea Anthony 2019-present +*/ +/* jshint esversion: 6 */ + +import {Error} from './log'; +import {SendMessage} from 'ipc'; + +// Defines a single listener with a maximum number of times to callback + +/** + * The Listener class defines a listener! :-) + * + * @class Listener + */ +class Listener { + /** + * Creates an instance of Listener. + * @param {function} callback + * @param {number} maxCallbacks + * @memberof Listener + */ + constructor(callback, maxCallbacks) { + // Default of -1 means infinite + maxCallbacks = maxCallbacks || -1; + // Callback invokes the callback with the given data + // Returns true if this listener should be destroyed + this.Callback = (data) => { + callback.apply(null, data); + // If maxCallbacks is infinite, return false (do not destroy) + if (maxCallbacks === -1) { + return false; + } + // Decrement maxCallbacks. Return true if now 0, otherwise false + maxCallbacks -= 1; + return maxCallbacks === 0; + }; + } +} + +let eventListeners = {}; + +/** + * Registers an event listener that will be invoked `maxCallbacks` times before being destroyed + * + * @export + * @param {string} eventName + * @param {function} callback + * @param {number} maxCallbacks + */ +export function OnMultiple(eventName, callback, maxCallbacks) { + eventListeners[eventName] = eventListeners[eventName] || []; + const thisListener = new Listener(callback, maxCallbacks); + console.log('Pushing event listener: ' + eventName); + eventListeners[eventName].push(thisListener); +} + +/** + * Registers an event listener that will be invoked every time the event is emitted + * + * @export + * @param {string} eventName + * @param {function} callback + */ +export function On(eventName, callback) { + OnMultiple(eventName, callback); +} + +/** + * Registers listeners for when the system theme changes from light/dark. A bool is + * sent to the listener, true if it is dark mode. + * + * @export + * @param {function} callback + */ +export function OnThemeChange(callback) { + On('wails:system:themechange', callback); +} + +/** + * Registers an event listener that will be invoked once then destroyed + * + * @export + * @param {string} eventName + * @param {function} callback + */ +export function Once(eventName, callback) { + OnMultiple(eventName, callback, 1); +} + +function notifyListeners(eventData) { + + // Get the event name + let eventName = eventData.name; + + // Check if we have any listeners for this event + if (eventListeners[eventName]) { + + // Keep a list of listener indexes to destroy + const newEventListenerList = eventListeners[eventName].slice(); + + // Iterate listeners + for (let count = 0; count < eventListeners[eventName].length; count += 1) { + + // Get next listener + const listener = eventListeners[eventName][count]; + + let data = eventData.data; + + // Do the callback + const destroy = listener.Callback(data); + if (destroy) { + // if the listener indicated to destroy itself, add it to the destroy list + newEventListenerList.splice(count, 1); + } + } + + // Update callbacks with new list of listeners + eventListeners[eventName] = newEventListenerList; + } +} + +/** + * Notify informs frontend listeners that an event was emitted with the given data + * + * @export + * @param {string} notifyMessage - encoded notification message + + */ +export function Notify(notifyMessage) { + + // Parse the message + var message; + try { + message = JSON.parse(notifyMessage); + } catch (e) { + const error = 'Invalid JSON passed to Notify: ' + notifyMessage; + throw new Error(error); + } + + notifyListeners(message); +} + +/** + * Emit an event with the given name and data + * + * @export + * @param {string} eventName + */ +export function Emit(eventName) { + + const payload = { + name: eventName, + data: [].slice.apply(arguments).slice(1), + }; + + // Notify JS listeners + notifyListeners(payload); + + // Notify Go listeners + SendMessage('Ej' + JSON.stringify(payload)); + +} \ No newline at end of file diff --git a/v2/internal/runtime/js/core/log.js b/v2/internal/runtime/js/core/log.js new file mode 100644 index 000000000..ea624a8ee --- /dev/null +++ b/v2/internal/runtime/js/core/log.js @@ -0,0 +1,115 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The electron alternative for Go +(c) Lea Anthony 2019-present +*/ + +/* jshint esversion: 6 */ + +import {SendMessage} from 'ipc'; + +/** + * Sends a log message to the backend with the given level + message + * + * @param {string} level + * @param {string} message + */ +function sendLogMessage(level, message) { + + // Log Message format: + // l[type][message] + SendMessage('L' + level + message); +} + +/** + * Log the given trace message with the backend + * + * @export + * @param {string} message + */ +export function Trace(message) { + sendLogMessage('T', message); +} + +/** + * Log the given message with the backend + * + * @export + * @param {string} message + */ +export function Print(message) { + sendLogMessage('P', message); +} + +/** + * Log the given debug message with the backend + * + * @export + * @param {string} message + */ +export function Debug(message) { + sendLogMessage('D', message); +} + +/** + * Log the given info message with the backend + * + * @export + * @param {string} message + */ +export function Info(message) { + sendLogMessage('I', message); +} + +/** + * Log the given warning message with the backend + * + * @export + * @param {string} message + */ +export function Warning(message) { + sendLogMessage('W', message); +} + +/** + * Log the given error message with the backend + * + * @export + * @param {string} message + */ +export function Error(message) { + sendLogMessage('E', message); +} + +/** + * Log the given fatal message with the backend + * + * @export + * @param {string} message + */ +export function Fatal(message) { + sendLogMessage('F', message); +} + +/** + * Sets the Log level to the given log level + * + * @export + * @param {number} loglevel + */ +export function SetLogLevel(loglevel) { + sendLogMessage('S', loglevel); +} + +// Log levels +export const Level = { + TRACE: 1, + DEBUG: 2, + INFO: 3, + WARNING: 4, + ERROR: 5, +}; diff --git a/v2/internal/runtime/js/core/main.js b/v2/internal/runtime/js/core/main.js new file mode 100644 index 000000000..3971cfc9c --- /dev/null +++ b/v2/internal/runtime/js/core/main.js @@ -0,0 +1,46 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The electron alternative for Go +(c) Lea Anthony 2019-present +*/ +/* jshint esversion: 6 */ +import * as Log from './log'; +import {Emit, Notify, On, Once, OnMultiple} from './events'; +import {Callback, SystemCall} from './calls'; +import {AddScript, DisableDefaultContextMenu, InjectCSS} from './utils'; +import {AddIPCListener, SendMessage} from 'ipc'; +import * as Platform from 'platform'; + +export function Init() { + // Where the Go struct wrappers get bound to + window.go = {}; + + // Initialise global if not already + window.wails = { + Log, + Events: { + On, + Once, + OnMultiple, + Emit, + }, + _: { + Callback, + Notify, + AddScript, + InjectCSS, + DisableDefaultContextMenu, + // Init, + AddIPCListener, + SystemCall, + SendMessage, + }, + }; + + // Do platform specific Init + Platform.Init(); +} \ No newline at end of file diff --git a/v2/internal/runtime/js/core/utils.js b/v2/internal/runtime/js/core/utils.js new file mode 100644 index 000000000..34f376016 --- /dev/null +++ b/v2/internal/runtime/js/core/utils.js @@ -0,0 +1,42 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The electron alternative for Go +(c) Lea Anthony 2019-present +*/ +/* jshint esversion: 6 */ + +import {Emit} from './events'; + +export function AddScript(js, callbackID) { + var script = document.createElement('script'); + script.text = js; + document.body.appendChild(script); + if (callbackID) { + Emit(callbackID); + } +} + +// Adapted from webview - thanks zserge! +export function InjectCSS(css) { + try { + var elem = document.createElement('style'); + elem.setAttribute('type', 'text/css'); + if (elem.styleSheet) { + elem.styleSheet.cssText = css; + } else { + elem.appendChild(document.createTextNode(css)); + } + var head = document.head || document.getElementsByTagName('head')[0]; + head.appendChild(elem); + } catch (e) { + console.log(e); + } +} + +export function DisableDefaultContextMenu() { + window.disableWailsDefaultContextMenu = true; +} diff --git a/v2/internal/runtime/js/desktop/common.js b/v2/internal/runtime/js/desktop/common.js new file mode 100644 index 000000000..80ed5408c --- /dev/null +++ b/v2/internal/runtime/js/desktop/common.js @@ -0,0 +1,15 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The electron alternative for Go +(c) Lea Anthony 2019-present +*/ +/* jshint esversion: 6 */ + +/** + * Initialises platform specific code + */ +export const AppType = "desktop"; diff --git a/v2/internal/runtime/js/desktop/darwin.js b/v2/internal/runtime/js/desktop/darwin.js new file mode 100644 index 000000000..6b47f2f9b --- /dev/null +++ b/v2/internal/runtime/js/desktop/darwin.js @@ -0,0 +1,61 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The electron alternative for Go +(c) Lea Anthony 2019-present +*/ + +/* jshint esversion: 6 */ + +/** + * Initialises platform specific code + */ + +export function SendMessage(message) { + window.wailsInvoke(message); +} + +export function Init() { + + // Setup drag handler + // Based on code from: https://github.com/patr0nus/DeskGap + window.addEventListener('mousedown', function (e) { + let currentElement = e.target; + while (currentElement != null) { + if (currentElement.hasAttribute('data-wails-no-drag')) { + break; + } else if (currentElement.hasAttribute('data-wails-drag')) { + window.wailsDrag(null); + break; + } + currentElement = currentElement.parentElement; + } + }); + + // Setup context menu hook + window.addEventListener('contextmenu', function (e) { + let currentElement = e.target; + let contextMenuId; + while (currentElement != null) { + contextMenuId = currentElement.dataset['wails-context-menu-id']; + if (contextMenuId != null) { + break; + } + currentElement = currentElement.parentElement; + } + if (contextMenuId != null || window.disableWailsDefaultContextMenu) { + e.preventDefault(); + } + if( contextMenuId != null ) { + let contextData = currentElement.dataset['wails-context-menu-data']; + let message = { + id: contextMenuId, + data: contextData || '', + }; + window.wailsContextMenuMessage(JSON.stringify(message)); + } + }); +} \ No newline at end of file diff --git a/v2/internal/runtime/js/desktop/ipc.js b/v2/internal/runtime/js/desktop/ipc.js new file mode 100644 index 000000000..b81a524eb --- /dev/null +++ b/v2/internal/runtime/js/desktop/ipc.js @@ -0,0 +1,41 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The electron alternative for Go +(c) Lea Anthony 2019-present +*/ +/* jshint esversion: 6 */ + +import * as Platform from 'platform'; + +// IPC Listeners +var listeners = []; + +/** + * Adds a listener to IPC messages + * @param {function} callback + */ +export function AddIPCListener(callback) { + listeners.push(callback); +} + +/** + * SendMessage sends the given message to the backend + * + * @param {string} message + */ +export function SendMessage(message) { + + // Call Platform specific invoke method + Platform.SendMessage(message); + + // Also send to listeners + if (listeners.length > 0) { + for (var i = 0; i < listeners.length; i++) { + listeners[i](message); + } + } +} diff --git a/v2/internal/runtime/js/desktop/linux.js b/v2/internal/runtime/js/desktop/linux.js new file mode 100644 index 000000000..6b47f2f9b --- /dev/null +++ b/v2/internal/runtime/js/desktop/linux.js @@ -0,0 +1,61 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The electron alternative for Go +(c) Lea Anthony 2019-present +*/ + +/* jshint esversion: 6 */ + +/** + * Initialises platform specific code + */ + +export function SendMessage(message) { + window.wailsInvoke(message); +} + +export function Init() { + + // Setup drag handler + // Based on code from: https://github.com/patr0nus/DeskGap + window.addEventListener('mousedown', function (e) { + let currentElement = e.target; + while (currentElement != null) { + if (currentElement.hasAttribute('data-wails-no-drag')) { + break; + } else if (currentElement.hasAttribute('data-wails-drag')) { + window.wailsDrag(null); + break; + } + currentElement = currentElement.parentElement; + } + }); + + // Setup context menu hook + window.addEventListener('contextmenu', function (e) { + let currentElement = e.target; + let contextMenuId; + while (currentElement != null) { + contextMenuId = currentElement.dataset['wails-context-menu-id']; + if (contextMenuId != null) { + break; + } + currentElement = currentElement.parentElement; + } + if (contextMenuId != null || window.disableWailsDefaultContextMenu) { + e.preventDefault(); + } + if( contextMenuId != null ) { + let contextData = currentElement.dataset['wails-context-menu-data']; + let message = { + id: contextMenuId, + data: contextData || '', + }; + window.wailsContextMenuMessage(JSON.stringify(message)); + } + }); +} \ No newline at end of file diff --git a/v2/internal/runtime/js/desktop/windows.js b/v2/internal/runtime/js/desktop/windows.js new file mode 100644 index 000000000..dd3b08f20 --- /dev/null +++ b/v2/internal/runtime/js/desktop/windows.js @@ -0,0 +1,61 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The electron alternative for Go +(c) Lea Anthony 2019-present +*/ + +/* jshint esversion: 9 */ + +/** + * Initialises platform specific code + */ + +export function SendMessage(message) { + window.wailsInvoke(message); +} + +export function Init() { + + // Setup drag handler + // Based on code from: https://github.com/patr0nus/DeskGap + window.addEventListener('mousedown', function (e) { + let currentElement = e.target; + while (currentElement != null) { + if (currentElement.hasAttribute('data-wails-no-drag')) { + break; + } else if (currentElement.hasAttribute('data-wails-drag')) { + window.wailsInvoke('wails-drag'); + break; + } + currentElement = currentElement.parentElement; + } + }); + + // Setup context menu hook + window.addEventListener('contextmenu', function (e) { + let currentElement = e.target; + let contextMenuId; + while (currentElement != null) { + contextMenuId = currentElement.dataset['wails-context-menu-id']; + if (contextMenuId != null) { + break; + } + currentElement = currentElement.parentElement; + } + if (contextMenuId != null || window.disableWailsDefaultContextMenu) { + e.preventDefault(); + } + if( contextMenuId != null ) { + let contextData = currentElement.dataset['wails-context-menu-data']; + let message = { + id: contextMenuId, + data: contextData || '', + }; + window.wailsInvoke('C'+JSON.stringify(message)); + } + }); +} \ No newline at end of file diff --git a/v2/internal/runtime/js/package-lock.json b/v2/internal/runtime/js/package-lock.json new file mode 100644 index 000000000..913320cea --- /dev/null +++ b/v2/internal/runtime/js/package-lock.json @@ -0,0 +1,5988 @@ +{ + "name": "wails-runtime", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/cli": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.8.4.tgz", + "integrity": "sha512-XXLgAm6LBbaNxaGhMAznXXaxtCWfuv6PIDJ9Alsy9JYTOh+j2jJz+L/162kkfU1j/pTSxK1xGmlwI4pdIMkoag==", + "dev": true, + "requires": { + "chokidar": "^2.1.8", + "commander": "^4.0.1", + "convert-source-map": "^1.1.0", + "fs-readdir-recursive": "^1.1.0", + "glob": "^7.0.0", + "lodash": "^4.17.13", + "make-dir": "^2.1.0", + "slash": "^2.0.0", + "source-map": "^0.5.0" + } + }, + "@babel/code-frame": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/compat-data": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.9.0.tgz", + "integrity": "sha512-zeFQrr+284Ekvd9e7KAX954LkapWiOmQtsfHirhxqfdlX6MEC32iRE+pqUGlYIBchdevaCwvzxWGSy/YBNI85g==", + "dev": true, + "requires": { + "browserslist": "^4.9.1", + "invariant": "^2.2.4", + "semver": "^5.5.0" + } + }, + "@babel/core": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.9.0.tgz", + "integrity": "sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.9.0", + "@babel/helper-module-transforms": "^7.9.0", + "@babel/helpers": "^7.9.0", + "@babel/parser": "^7.9.0", + "@babel/template": "^7.8.6", + "@babel/traverse": "^7.9.0", + "@babel/types": "^7.9.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.9.5.tgz", + "integrity": "sha512-GbNIxVB3ZJe3tLeDm1HSn2AhuD/mVcyLDpgtLXa5tplmWrJdF/elxB56XNqCuD6szyNkDi6wuoKXln3QeBmCHQ==", + "dev": true, + "requires": { + "@babel/types": "^7.9.5", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz", + "integrity": "sha512-6o+mJrZBxOoEX77Ezv9zwW7WV8DdluouRKNY/IR5u/YTMuKHgugHOzYWlYvYLpLA9nPsQCAAASpCIbjI9Mv+Uw==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.8.3.tgz", + "integrity": "sha512-5eFOm2SyFPK4Rh3XMMRDjN7lBH0orh3ss0g3rTYZnBQ+r6YPj7lgDyCvPphynHvUrobJmeMignBr6Acw9mAPlw==", + "dev": true, + "requires": { + "@babel/helper-explode-assignable-expression": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.7.tgz", + "integrity": "sha512-4mWm8DCK2LugIS+p1yArqvG1Pf162upsIsjE7cNBjez+NjliQpVhj20obE520nao0o14DaTnFJv+Fw5a0JpoUw==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.8.6", + "browserslist": "^4.9.1", + "invariant": "^2.2.4", + "levenary": "^1.1.1", + "semver": "^5.5.0" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.8.8", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.8.tgz", + "integrity": "sha512-LYVPdwkrQEiX9+1R29Ld/wTrmQu1SSKYnuOk3g0CkcZMA1p0gsNxJFj/3gBdaJ7Cg0Fnek5z0DsMULePP7Lrqg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.8.3", + "@babel/helper-regex": "^7.8.3", + "regexpu-core": "^4.7.0" + } + }, + "@babel/helper-define-map": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.8.3.tgz", + "integrity": "sha512-PoeBYtxoZGtct3md6xZOCWPcKuMuk3IHhgxsRRNtnNShebf4C8YonTSblsK4tvDbm+eJAw2HAPOfCr+Q/YRG/g==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.8.3", + "@babel/types": "^7.8.3", + "lodash": "^4.17.13" + } + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.8.3.tgz", + "integrity": "sha512-N+8eW86/Kj147bO9G2uclsg5pwfs/fqqY5rwgIL7eTBklgXjcOJ3btzS5iM6AitJcftnY7pm2lGsrJVYLGjzIw==", + "dev": true, + "requires": { + "@babel/traverse": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-function-name": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz", + "integrity": "sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.9.5" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.8.3.tgz", + "integrity": "sha512-ky1JLOjcDUtSc+xkt0xhYff7Z6ILTAHKmZLHPxAhOP0Nd77O+3nCsd6uSVYur6nJnCI029CrNbYlc0LoPfAPQg==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz", + "integrity": "sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-module-imports": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz", + "integrity": "sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-module-transforms": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.9.0.tgz", + "integrity": "sha512-0FvKyu0gpPfIQ8EkxlrAydOWROdHpBmiCiRwLkUiBGhCUPRRbVD2/tm3sFr/c/GWFrQ/ffutGUAnx7V0FzT2wA==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-replace-supers": "^7.8.6", + "@babel/helper-simple-access": "^7.8.3", + "@babel/helper-split-export-declaration": "^7.8.3", + "@babel/template": "^7.8.6", + "@babel/types": "^7.9.0", + "lodash": "^4.17.13" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz", + "integrity": "sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + }, + "@babel/helper-regex": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.8.3.tgz", + "integrity": "sha512-BWt0QtYv/cg/NecOAZMdcn/waj/5P26DR4mVLXfFtDokSR6fyuG0Pj+e2FqtSME+MqED1khnSMulkmGl8qWiUQ==", + "dev": true, + "requires": { + "lodash": "^4.17.13" + } + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.8.3.tgz", + "integrity": "sha512-kgwDmw4fCg7AVgS4DukQR/roGp+jP+XluJE5hsRZwxCYGg+Rv9wSGErDWhlI90FODdYfd4xG4AQRiMDjjN0GzA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.8.3", + "@babel/helper-wrap-function": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/traverse": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-replace-supers": { + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz", + "integrity": "sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.8.3", + "@babel/helper-optimise-call-expression": "^7.8.3", + "@babel/traverse": "^7.8.6", + "@babel/types": "^7.8.6" + } + }, + "@babel/helper-simple-access": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz", + "integrity": "sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw==", + "dev": true, + "requires": { + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", + "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz", + "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==", + "dev": true + }, + "@babel/helper-wrap-function": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz", + "integrity": "sha512-LACJrbUET9cQDzb6kG7EeD7+7doC3JNvUgTEQOx2qaO1fKlzE/Bf05qs9w1oXQMmXlPO65lC3Tq9S6gZpTErEQ==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/traverse": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helpers": { + "version": "7.9.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.9.2.tgz", + "integrity": "sha512-JwLvzlXVPjO8eU9c/wF9/zOIN7X6h8DYf7mG4CiFRZRvZNKEF5dQ3H3V+ASkHoIB3mWhatgl5ONhyqHRI6MppA==", + "dev": true, + "requires": { + "@babel/template": "^7.8.3", + "@babel/traverse": "^7.9.0", + "@babel/types": "^7.9.0" + } + }, + "@babel/highlight": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", + "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.9.0", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.9.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.4.tgz", + "integrity": "sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA==", + "dev": true + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz", + "integrity": "sha512-NZ9zLv848JsV3hs8ryEh7Uaz/0KsmPLqv0+PdkDJL1cJy0K4kOCFa8zc1E3mp+RHPQcpdfb/6GovEsW4VDrOMw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-remap-async-to-generator": "^7.8.3", + "@babel/plugin-syntax-async-generators": "^7.8.0" + } + }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.8.3.tgz", + "integrity": "sha512-NyaBbyLFXFLT9FP+zk0kYlUlA8XtCUbehs67F0nnEg7KICgMc2mNkIeu9TYhKzyXMkrapZFwAhXLdnt4IYHy1w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-dynamic-import": "^7.8.0" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.8.3.tgz", + "integrity": "sha512-KGhQNZ3TVCQG/MjRbAUwuH+14y9q0tpxs1nWWs3pbSleRdDro9SAMMDyye8HhY1gqZ7/NqIc8SKhya0wRDgP1Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.0" + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-TS9MlfzXpXKt6YYomudb/KU7nQI6/xnapG6in1uZxoxDghuSMZsPb6D2fyUwNYSAp4l1iR7QtFOjkqcRYcUsfw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.8.3.tgz", + "integrity": "sha512-jWioO1s6R/R+wEHizfaScNsAx+xKgwTLNXSh7tTC4Usj3ItsPEhYkEpU4h+lpnBwq7NBVOJXfO6cRFYcX69JUQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.9.5.tgz", + "integrity": "sha512-VP2oXvAf7KCYTthbUHwBlewbl1Iq059f6seJGsxMizaCdgHIeczOr7FBqELhSqfkIl04Fi8okzWzl63UKbQmmg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-transform-parameters": "^7.9.5" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-0gkX7J7E+AtAw9fcwlVQj8peP61qhdg/89D5swOkjYbkboA2CVckn3kiyum1DE0wskGb7KJJxBdyEBApDLLVdw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.9.0.tgz", + "integrity": "sha512-NDn5tu3tcv4W30jNhmc2hyD5c56G6cXx4TesJubhxrJeCvuuMpttxr0OnNCqbZGhFjLrg+NIhxxC+BK5F6yS3w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.0" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.8.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.8.tgz", + "integrity": "sha512-EVhjVsMpbhLw9ZfHWSx2iy13Q8Z/eg8e8ccVWt23sWQK5l1UdkoLJPN5w69UA4uITGBnEZD2JOe4QOHycYKv8A==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.8.8", + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.8.3.tgz", + "integrity": "sha512-H7dCMAdN83PcCmqmkHB5dtp+Xa9a6LKSvA2hiFBC/5alSHxM5VgWZXFqDi0YFe8XNGT6iCa+z4V4zSt/PdZ7Dw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.8.3.tgz", + "integrity": "sha512-kwj1j9lL/6Wd0hROD3b/OZZ7MSrZLqqn9RAZ5+cYYsflQ9HZBIKCUkr3+uL1MEJ1NePiUbf98jjiMQSv0NMR9g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.8.3.tgz", + "integrity": "sha512-0MRF+KC8EqH4dbuITCWwPSzsyO3HIWWlm30v8BbbpOrS1B++isGxPnnuq/IZvOX5J2D/p7DQalQm+/2PnlKGxg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.8.3.tgz", + "integrity": "sha512-imt9tFLD9ogt56Dd5CI/6XgpukMwd/fLGSrix2httihVe7LOGVPhyhMh1BU5kDM7iHD08i8uUtmV2sWaBFlHVQ==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-remap-async-to-generator": "^7.8.3" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.8.3.tgz", + "integrity": "sha512-vo4F2OewqjbB1+yaJ7k2EJFHlTP3jR634Z9Cj9itpqNjuLXvhlVxgnjsHsdRgASR8xYDrx6onw4vW5H6We0Jmg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.8.3.tgz", + "integrity": "sha512-pGnYfm7RNRgYRi7bids5bHluENHqJhrV4bCZRwc5GamaWIIs07N4rZECcmJL6ZClwjDz1GbdMZFtPs27hTB06w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "lodash": "^4.17.13" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.9.5.tgz", + "integrity": "sha512-x2kZoIuLC//O5iA7PEvecB105o7TLzZo8ofBVhP79N+DO3jaX+KYfww9TQcfBEZD0nikNyYcGB1IKtRq36rdmg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.8.3", + "@babel/helper-define-map": "^7.8.3", + "@babel/helper-function-name": "^7.9.5", + "@babel/helper-optimise-call-expression": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-replace-supers": "^7.8.6", + "@babel/helper-split-export-declaration": "^7.8.3", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.8.3.tgz", + "integrity": "sha512-O5hiIpSyOGdrQZRQ2ccwtTVkgUDBBiCuK//4RJ6UfePllUTCENOzKxfh6ulckXKc0DixTFLCfb2HVkNA7aDpzA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.9.5.tgz", + "integrity": "sha512-j3OEsGel8nHL/iusv/mRd5fYZ3DrOxWC82x0ogmdN/vHfAP4MYw+AFKYanzWlktNwikKvlzUV//afBW5FTp17Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.8.3.tgz", + "integrity": "sha512-kLs1j9Nn4MQoBYdRXH6AeaXMbEJFaFu/v1nQkvib6QzTj8MZI5OQzqmD83/2jEM1z0DLilra5aWO5YpyC0ALIw==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.8.3.tgz", + "integrity": "sha512-s8dHiBUbcbSgipS4SMFuWGqCvyge5V2ZeAWzR6INTVC3Ltjig/Vw1G2Gztv0vU/hRG9X8IvKvYdoksnUfgXOEQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.8.3.tgz", + "integrity": "sha512-zwIpuIymb3ACcInbksHaNcR12S++0MDLKkiqXHl3AzpgdKlFNhog+z/K0+TGW+b0w5pgTq4H6IwV/WhxbGYSjQ==", + "dev": true, + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.9.0.tgz", + "integrity": "sha512-lTAnWOpMwOXpyDx06N+ywmF3jNbafZEqZ96CGYabxHrxNX8l5ny7dt4bK/rGwAh9utyP2b2Hv7PlZh1AAS54FQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.8.3.tgz", + "integrity": "sha512-rO/OnDS78Eifbjn5Py9v8y0aR+aSYhDhqAwVfsTl0ERuMZyr05L1aFSCJnbv2mmsLkit/4ReeQ9N2BgLnOcPCQ==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.8.3.tgz", + "integrity": "sha512-3Tqf8JJ/qB7TeldGl+TT55+uQei9JfYaregDcEAyBZ7akutriFrt6C/wLYIer6OYhleVQvH/ntEhjE/xMmy10A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.8.3.tgz", + "integrity": "sha512-3Wk2EXhnw+rP+IDkK6BdtPKsUE5IeZ6QOGrPYvw52NwBStw9V1ZVzxgK6fSKSxqUvH9eQPR3tm3cOq79HlsKYA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.9.0.tgz", + "integrity": "sha512-vZgDDF003B14O8zJy0XXLnPH4sg+9X5hFBBGN1V+B2rgrB+J2xIypSN6Rk9imB2hSTHQi5OHLrFWsZab1GMk+Q==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.9.0", + "@babel/helper-plugin-utils": "^7.8.3", + "babel-plugin-dynamic-import-node": "^2.3.0" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.9.0.tgz", + "integrity": "sha512-qzlCrLnKqio4SlgJ6FMMLBe4bySNis8DFn1VkGmOcxG9gqEyPIOzeQrA//u0HAKrWpJlpZbZMPB1n/OPa4+n8g==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.9.0", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-simple-access": "^7.8.3", + "babel-plugin-dynamic-import-node": "^2.3.0" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.9.0.tgz", + "integrity": "sha512-FsiAv/nao/ud2ZWy4wFacoLOm5uxl0ExSQ7ErvP7jpoihLR6Cq90ilOFyX9UXct3rbtKsAiZ9kFt5XGfPe/5SQ==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.8.3", + "@babel/helper-module-transforms": "^7.9.0", + "@babel/helper-plugin-utils": "^7.8.3", + "babel-plugin-dynamic-import-node": "^2.3.0" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.9.0.tgz", + "integrity": "sha512-uTWkXkIVtg/JGRSIABdBoMsoIeoHQHPTL0Y2E7xf5Oj7sLqwVsNXOkNk0VJc7vF0IMBsPeikHxFjGe+qmwPtTQ==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.9.0", + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.8.3.tgz", + "integrity": "sha512-f+tF/8UVPU86TrCb06JoPWIdDpTNSGGcAtaD9mLP0aYGA0OS0j7j7DHJR0GTFrUZPUU6loZhbsVZgTh0N+Qdnw==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.8.3" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.8.3.tgz", + "integrity": "sha512-QuSGysibQpyxexRyui2vca+Cmbljo8bcRckgzYV4kRIsHpVeyeC3JDO63pY+xFZ6bWOBn7pfKZTqV4o/ix9sFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-object-assign": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-assign/-/plugin-transform-object-assign-7.8.3.tgz", + "integrity": "sha512-i3LuN8tPDqUCRFu3dkzF2r1Nx0jp4scxtm7JxtIqI9he9Vk20YD+/zshdzR9JLsoBMlJlNR82a62vQExNEVx/Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.8.3.tgz", + "integrity": "sha512-57FXk+gItG/GejofIyLIgBKTas4+pEU47IXKDBWFTxdPd7F80H8zybyAY7UoblVfBhBGs2EKM+bJUu2+iUYPDQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-replace-supers": "^7.8.3" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.9.5.tgz", + "integrity": "sha512-0+1FhHnMfj6lIIhVvS4KGQJeuhe1GI//h5uptK4PvLt+BGBxsoUJbd3/IW002yk//6sZPlFgsG1hY6OHLcy6kA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.8.3.tgz", + "integrity": "sha512-uGiiXAZMqEoQhRWMK17VospMZh5sXWg+dlh2soffpkAl96KAm+WZuJfa6lcELotSRmooLqg0MWdH6UUq85nmmg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.7.tgz", + "integrity": "sha512-TIg+gAl4Z0a3WmD3mbYSk+J9ZUH6n/Yc57rtKRnlA/7rcCvpekHXe0CMZHP1gYp7/KLe9GHTuIba0vXmls6drA==", + "dev": true, + "requires": { + "regenerator-transform": "^0.14.2" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.8.3.tgz", + "integrity": "sha512-mwMxcycN3omKFDjDQUl+8zyMsBfjRFr0Zn/64I41pmjv4NJuqcYlEtezwYtw9TFd9WR1vN5kiM+O0gMZzO6L0A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.8.3.tgz", + "integrity": "sha512-I9DI6Odg0JJwxCHzbzW08ggMdCezoWcuQRz3ptdudgwaHxTjxw5HgdFJmZIkIMlRymL6YiZcped4TTCB0JcC8w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.8.3.tgz", + "integrity": "sha512-CkuTU9mbmAoFOI1tklFWYYbzX5qCIZVXPVy0jpXgGwkplCndQAa58s2jr66fTeQnA64bDox0HL4U56CFYoyC7g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.8.3.tgz", + "integrity": "sha512-9Spq0vGCD5Bb4Z/ZXXSK5wbbLFMG085qd2vhL1JYu1WcQ5bXqZBAYRzU1d+p79GcHs2szYv5pVQCX13QgldaWw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-regex": "^7.8.3" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.8.3.tgz", + "integrity": "sha512-820QBtykIQOLFT8NZOcTRJ1UNuztIELe4p9DCgvj4NK+PwluSJ49we7s9FB1HIGNIYT7wFUJ0ar2QpCDj0escQ==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.4.tgz", + "integrity": "sha512-2QKyfjGdvuNfHsb7qnBBlKclbD4CfshH2KvDabiijLMGXPHJXGxtDzwIF7bQP+T0ysw8fYTtxPafgfs/c1Lrqg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.8.3.tgz", + "integrity": "sha512-+ufgJjYdmWfSQ+6NS9VGUR2ns8cjJjYbrbi11mZBTaWm+Fui/ncTLFF28Ei1okavY+xkojGr1eJxNsWYeA5aZw==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/preset-env": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.9.5.tgz", + "integrity": "sha512-eWGYeADTlPJH+wq1F0wNfPbVS1w1wtmMJiYk55Td5Yu28AsdR9AsC97sZ0Qq8fHqQuslVSIYSGJMcblr345GfQ==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.9.0", + "@babel/helper-compilation-targets": "^7.8.7", + "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-proposal-async-generator-functions": "^7.8.3", + "@babel/plugin-proposal-dynamic-import": "^7.8.3", + "@babel/plugin-proposal-json-strings": "^7.8.3", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-proposal-numeric-separator": "^7.8.3", + "@babel/plugin-proposal-object-rest-spread": "^7.9.5", + "@babel/plugin-proposal-optional-catch-binding": "^7.8.3", + "@babel/plugin-proposal-optional-chaining": "^7.9.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.8.3", + "@babel/plugin-syntax-async-generators": "^7.8.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.0", + "@babel/plugin-syntax-json-strings": "^7.8.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", + "@babel/plugin-syntax-numeric-separator": "^7.8.0", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.0", + "@babel/plugin-syntax-top-level-await": "^7.8.3", + "@babel/plugin-transform-arrow-functions": "^7.8.3", + "@babel/plugin-transform-async-to-generator": "^7.8.3", + "@babel/plugin-transform-block-scoped-functions": "^7.8.3", + "@babel/plugin-transform-block-scoping": "^7.8.3", + "@babel/plugin-transform-classes": "^7.9.5", + "@babel/plugin-transform-computed-properties": "^7.8.3", + "@babel/plugin-transform-destructuring": "^7.9.5", + "@babel/plugin-transform-dotall-regex": "^7.8.3", + "@babel/plugin-transform-duplicate-keys": "^7.8.3", + "@babel/plugin-transform-exponentiation-operator": "^7.8.3", + "@babel/plugin-transform-for-of": "^7.9.0", + "@babel/plugin-transform-function-name": "^7.8.3", + "@babel/plugin-transform-literals": "^7.8.3", + "@babel/plugin-transform-member-expression-literals": "^7.8.3", + "@babel/plugin-transform-modules-amd": "^7.9.0", + "@babel/plugin-transform-modules-commonjs": "^7.9.0", + "@babel/plugin-transform-modules-systemjs": "^7.9.0", + "@babel/plugin-transform-modules-umd": "^7.9.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.8.3", + "@babel/plugin-transform-new-target": "^7.8.3", + "@babel/plugin-transform-object-super": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.9.5", + "@babel/plugin-transform-property-literals": "^7.8.3", + "@babel/plugin-transform-regenerator": "^7.8.7", + "@babel/plugin-transform-reserved-words": "^7.8.3", + "@babel/plugin-transform-shorthand-properties": "^7.8.3", + "@babel/plugin-transform-spread": "^7.8.3", + "@babel/plugin-transform-sticky-regex": "^7.8.3", + "@babel/plugin-transform-template-literals": "^7.8.3", + "@babel/plugin-transform-typeof-symbol": "^7.8.4", + "@babel/plugin-transform-unicode-regex": "^7.8.3", + "@babel/preset-modules": "^0.1.3", + "@babel/types": "^7.9.5", + "browserslist": "^4.9.1", + "core-js-compat": "^3.6.2", + "invariant": "^2.2.2", + "levenary": "^1.1.1", + "semver": "^5.5.0" + } + }, + "@babel/preset-modules": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.3.tgz", + "integrity": "sha512-Ra3JXOHBq2xd56xSF7lMKXdjBn3T772Y1Wet3yWnkDly9zHvJki029tAFzvAAK5cf4YV3yoxuP61crYRol6SVg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + } + }, + "@babel/runtime": { + "version": "7.9.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.2.tgz", + "integrity": "sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/template": { + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", + "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6" + } + }, + "@babel/traverse": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.9.5.tgz", + "integrity": "sha512-c4gH3jsvSuGUezlP6rzSJ6jf8fYjLj3hsMZRx/nX0h+fmHN0w+ekubRrHPqnMec0meycA2nwCsJ7dC8IPem2FQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.9.5", + "@babel/helper-function-name": "^7.9.5", + "@babel/helper-split-export-declaration": "^7.8.3", + "@babel/parser": "^7.9.0", + "@babel/types": "^7.9.5", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.5.tgz", + "integrity": "sha512-XjnvNqenk818r5zMaba+sLQjnbda31UfUURv3ei0qPQw4u+j2jMyJ5b11y8ZHYTRSI3NnInQkkkRT4fLqqPdHg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.9.5", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "dev": true + }, + "@webassemblyjs/ast": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", + "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==", + "dev": true, + "requires": { + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz", + "integrity": "sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz", + "integrity": "sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz", + "integrity": "sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==", + "dev": true + }, + "@webassemblyjs/helper-code-frame": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz", + "integrity": "sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==", + "dev": true, + "requires": { + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "@webassemblyjs/helper-fsm": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz", + "integrity": "sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==", + "dev": true + }, + "@webassemblyjs/helper-module-context": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz", + "integrity": "sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz", + "integrity": "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz", + "integrity": "sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz", + "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz", + "integrity": "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz", + "integrity": "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz", + "integrity": "sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/helper-wasm-section": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-opt": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz", + "integrity": "sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz", + "integrity": "sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz", + "integrity": "sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "@webassemblyjs/wast-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz", + "integrity": "sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/floating-point-hex-parser": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-code-frame": "1.9.0", + "@webassemblyjs/helper-fsm": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz", + "integrity": "sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "acorn": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz", + "integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==", + "dev": true + }, + "acorn-jsx": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", + "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", + "dev": true + }, + "ajv": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz", + "integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", + "dev": true + }, + "ajv-keywords": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", + "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==", + "dev": true + }, + "ansi-escapes": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", + "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "dev": true, + "requires": { + "type-fest": "^0.11.0" + }, + "dependencies": { + "type-fest": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", + "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "dev": true + } + } + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "dev": true, + "requires": { + "object-assign": "^4.1.1", + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "requires": { + "inherits": "2.0.1" + } + } + } + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "dev": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "babel-helper-evaluate-path": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.5.0.tgz", + "integrity": "sha512-mUh0UhS607bGh5wUMAQfOpt2JX2ThXMtppHRdRU1kL7ZLRWIXxoV2UIV1r2cAeeNeU1M5SB5/RSUgUxrK8yOkA==", + "dev": true + }, + "babel-helper-flip-expressions": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.4.3.tgz", + "integrity": "sha1-NpZzahKKwYvCUlS19AoizrPB0/0=", + "dev": true + }, + "babel-helper-is-nodes-equiv": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/babel-helper-is-nodes-equiv/-/babel-helper-is-nodes-equiv-0.0.1.tgz", + "integrity": "sha1-NOmzALFHnd2Y7HfqC76TQt/jloQ=", + "dev": true + }, + "babel-helper-is-void-0": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-helper-is-void-0/-/babel-helper-is-void-0-0.4.3.tgz", + "integrity": "sha1-fZwBtFYee5Xb2g9u7kj1tg5nMT4=", + "dev": true + }, + "babel-helper-mark-eval-scopes": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.4.3.tgz", + "integrity": "sha1-0kSjvvmESHJgP/tG4izorN9VFWI=", + "dev": true + }, + "babel-helper-remove-or-void": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.4.3.tgz", + "integrity": "sha1-pPA7QAd6D/6I5F0HAQ3uJB/1rmA=", + "dev": true + }, + "babel-helper-to-multiple-sequence-expressions": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.5.0.tgz", + "integrity": "sha512-m2CvfDW4+1qfDdsrtf4dwOslQC3yhbgyBFptncp4wvtdrDHqueW7slsYv4gArie056phvQFhT2nRcGS4bnm6mA==", + "dev": true + }, + "babel-loader": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.1.0.tgz", + "integrity": "sha512-7q7nC1tYOrqvUrN3LQK4GwSk/TQorZSOlO9C+RZDZpODgyN4ZlCqE5q9cDsyWOliN+aU9B4JX01xK9eJXowJLw==", + "dev": true, + "requires": { + "find-cache-dir": "^2.1.0", + "loader-utils": "^1.4.0", + "mkdirp": "^0.5.3", + "pify": "^4.0.1", + "schema-utils": "^2.6.5" + } + }, + "babel-plugin-dynamic-import-node": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz", + "integrity": "sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ==", + "dev": true, + "requires": { + "object.assign": "^4.1.0" + } + }, + "babel-plugin-minify-builtins": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.5.0.tgz", + "integrity": "sha512-wpqbN7Ov5hsNwGdzuzvFcjgRlzbIeVv1gMIlICbPj0xkexnfoIDe7q+AZHMkQmAE/F9R5jkrB6TLfTegImlXag==", + "dev": true + }, + "babel-plugin-minify-constant-folding": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-constant-folding/-/babel-plugin-minify-constant-folding-0.5.0.tgz", + "integrity": "sha512-Vj97CTn/lE9hR1D+jKUeHfNy+m1baNiJ1wJvoGyOBUx7F7kJqDZxr9nCHjO/Ad+irbR3HzR6jABpSSA29QsrXQ==", + "dev": true, + "requires": { + "babel-helper-evaluate-path": "^0.5.0" + } + }, + "babel-plugin-minify-dead-code-elimination": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.5.1.tgz", + "integrity": "sha512-x8OJOZIrRmQBcSqxBcLbMIK8uPmTvNWPXH2bh5MDCW1latEqYiRMuUkPImKcfpo59pTUB2FT7HfcgtG8ZlR5Qg==", + "dev": true, + "requires": { + "babel-helper-evaluate-path": "^0.5.0", + "babel-helper-mark-eval-scopes": "^0.4.3", + "babel-helper-remove-or-void": "^0.4.3", + "lodash": "^4.17.11" + } + }, + "babel-plugin-minify-flip-comparisons": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-flip-comparisons/-/babel-plugin-minify-flip-comparisons-0.4.3.tgz", + "integrity": "sha1-AMqHDLjxO0XAOLPB68DyJyk8llo=", + "dev": true, + "requires": { + "babel-helper-is-void-0": "^0.4.3" + } + }, + "babel-plugin-minify-guarded-expressions": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.4.4.tgz", + "integrity": "sha512-RMv0tM72YuPPfLT9QLr3ix9nwUIq+sHT6z8Iu3sLbqldzC1Dls8DPCywzUIzkTx9Zh1hWX4q/m9BPoPed9GOfA==", + "dev": true, + "requires": { + "babel-helper-evaluate-path": "^0.5.0", + "babel-helper-flip-expressions": "^0.4.3" + } + }, + "babel-plugin-minify-infinity": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-infinity/-/babel-plugin-minify-infinity-0.4.3.tgz", + "integrity": "sha1-37h2obCKBldjhO8/kuZTumB7Oco=", + "dev": true + }, + "babel-plugin-minify-mangle-names": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.5.0.tgz", + "integrity": "sha512-3jdNv6hCAw6fsX1p2wBGPfWuK69sfOjfd3zjUXkbq8McbohWy23tpXfy5RnToYWggvqzuMOwlId1PhyHOfgnGw==", + "dev": true, + "requires": { + "babel-helper-mark-eval-scopes": "^0.4.3" + } + }, + "babel-plugin-minify-numeric-literals": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-numeric-literals/-/babel-plugin-minify-numeric-literals-0.4.3.tgz", + "integrity": "sha1-jk/VYcefeAEob/YOjF/Z3u6TwLw=", + "dev": true + }, + "babel-plugin-minify-replace": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-replace/-/babel-plugin-minify-replace-0.5.0.tgz", + "integrity": "sha512-aXZiaqWDNUbyNNNpWs/8NyST+oU7QTpK7J9zFEFSA0eOmtUNMU3fczlTTTlnCxHmq/jYNFEmkkSG3DDBtW3Y4Q==", + "dev": true + }, + "babel-plugin-minify-simplify": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.5.1.tgz", + "integrity": "sha512-OSYDSnoCxP2cYDMk9gxNAed6uJDiDz65zgL6h8d3tm8qXIagWGMLWhqysT6DY3Vs7Fgq7YUDcjOomhVUb+xX6A==", + "dev": true, + "requires": { + "babel-helper-evaluate-path": "^0.5.0", + "babel-helper-flip-expressions": "^0.4.3", + "babel-helper-is-nodes-equiv": "^0.0.1", + "babel-helper-to-multiple-sequence-expressions": "^0.5.0" + } + }, + "babel-plugin-minify-type-constructors": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-type-constructors/-/babel-plugin-minify-type-constructors-0.4.3.tgz", + "integrity": "sha1-G8bxW4f3qxCF1CszC3F2V6IVZQA=", + "dev": true, + "requires": { + "babel-helper-is-void-0": "^0.4.3" + } + }, + "babel-plugin-transform-inline-consecutive-adds": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.4.3.tgz", + "integrity": "sha1-Mj1Ho+pjqDp6w8gRro5pQfrysNE=", + "dev": true + }, + "babel-plugin-transform-member-expression-literals": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.9.4.tgz", + "integrity": "sha1-NwOcmgwzE6OUlfqsL/OmtbnQOL8=", + "dev": true + }, + "babel-plugin-transform-merge-sibling-variables": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.9.4.tgz", + "integrity": "sha1-hbQi/DN3tEnJ0c3kQIcgNTJAHa4=", + "dev": true + }, + "babel-plugin-transform-minify-booleans": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.9.4.tgz", + "integrity": "sha1-rLs+VqNVXdI5KOS1gtKFFi3SsZg=", + "dev": true + }, + "babel-plugin-transform-property-literals": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.9.4.tgz", + "integrity": "sha1-mMHSHiVXNlc/k+zlRFn2ziSYXTk=", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "babel-plugin-transform-regexp-constructors": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.4.3.tgz", + "integrity": "sha1-WLd3W2OvzzMyj66aX4j71PsLSWU=", + "dev": true + }, + "babel-plugin-transform-remove-console": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.9.4.tgz", + "integrity": "sha1-uYA2DAZzhOJLNXpYjYB9PINSd4A=", + "dev": true + }, + "babel-plugin-transform-remove-debugger": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.9.4.tgz", + "integrity": "sha1-QrcnYxyXl44estGZp67IShgznvI=", + "dev": true + }, + "babel-plugin-transform-remove-undefined": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-undefined/-/babel-plugin-transform-remove-undefined-0.5.0.tgz", + "integrity": "sha512-+M7fJYFaEE/M9CXa0/IRkDbiV3wRELzA1kKQFCJ4ifhrzLKn/9VCCgj9OFmYWwBd8IB48YdgPkHYtbYq+4vtHQ==", + "dev": true, + "requires": { + "babel-helper-evaluate-path": "^0.5.0" + } + }, + "babel-plugin-transform-simplify-comparison-operators": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.9.4.tgz", + "integrity": "sha1-9ir+CWyrDh9ootdT/fKDiIRxzrk=", + "dev": true + }, + "babel-plugin-transform-undefined-to-void": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.9.4.tgz", + "integrity": "sha1-viQcqBQEAwZ4t0hxcyK4nQyP4oA=", + "dev": true + }, + "babel-preset-minify": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/babel-preset-minify/-/babel-preset-minify-0.5.1.tgz", + "integrity": "sha512-1IajDumYOAPYImkHbrKeiN5AKKP9iOmRoO2IPbIuVp0j2iuCcj0n7P260z38siKMZZ+85d3mJZdtW8IgOv+Tzg==", + "dev": true, + "requires": { + "babel-plugin-minify-builtins": "^0.5.0", + "babel-plugin-minify-constant-folding": "^0.5.0", + "babel-plugin-minify-dead-code-elimination": "^0.5.1", + "babel-plugin-minify-flip-comparisons": "^0.4.3", + "babel-plugin-minify-guarded-expressions": "^0.4.4", + "babel-plugin-minify-infinity": "^0.4.3", + "babel-plugin-minify-mangle-names": "^0.5.0", + "babel-plugin-minify-numeric-literals": "^0.4.3", + "babel-plugin-minify-replace": "^0.5.0", + "babel-plugin-minify-simplify": "^0.5.1", + "babel-plugin-minify-type-constructors": "^0.4.3", + "babel-plugin-transform-inline-consecutive-adds": "^0.4.3", + "babel-plugin-transform-member-expression-literals": "^6.9.4", + "babel-plugin-transform-merge-sibling-variables": "^6.9.4", + "babel-plugin-transform-minify-booleans": "^6.9.4", + "babel-plugin-transform-property-literals": "^6.9.4", + "babel-plugin-transform-regexp-constructors": "^0.4.3", + "babel-plugin-transform-remove-console": "^6.9.4", + "babel-plugin-transform-remove-debugger": "^6.9.4", + "babel-plugin-transform-remove-undefined": "^0.5.0", + "babel-plugin-transform-simplify-comparison-operators": "^6.9.4", + "babel-plugin-transform-undefined-to-void": "^6.9.4", + "lodash": "^4.17.11" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", + "dev": true + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true + }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "optional": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", + "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", + "dev": true, + "requires": { + "bn.js": "^4.1.1", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.2", + "elliptic": "^6.0.0", + "inherits": "^2.0.1", + "parse-asn1": "^5.0.0" + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dev": true, + "requires": { + "pako": "~1.0.5" + } + }, + "browserslist": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.11.1.tgz", + "integrity": "sha512-DCTr3kDrKEYNw6Jb9HFxVLQNaue8z+0ZfRBRjmCunKDEXEBajKDj2Y+Uelg+Pi29OnvaSGwjOsnRyNEkXzHg5g==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001038", + "electron-to-chromium": "^1.3.390", + "node-releases": "^1.1.53", + "pkg-up": "^2.0.0" + } + }, + "buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", + "dev": true + }, + "cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "dev": true, + "requires": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001171", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001171.tgz", + "integrity": "sha512-5Alrh8TTYPG9IH4UkRqEBZoEToWRLvPbSQokvzSz0lii8/FOWKG4keO1HoYfPWs8IF/NH/dyNPg1cmJGvV3Zlg==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + }, + "dependencies": { + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "dev": true, + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } + } + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "chrome-trace-event": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", + "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", + "dev": true + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", + "dev": true + }, + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "core-js": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz", + "integrity": "sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==", + "dev": true + }, + "core-js-compat": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.5.tgz", + "integrity": "sha512-7ItTKOhOZbznhXAQ2g/slGg1PJV5zDO/WdkTwi7UEOJmkvsE32PWvx6mKtDjiMpjnR2CNf6BAD6sSxIlv7ptng==", + "dev": true, + "requires": { + "browserslist": "^4.8.5", + "semver": "7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true + } + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "create-ecdh": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", + "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.0.0" + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dev": true, + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "cyclist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", + "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "dev": true + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "dev": true + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dev": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "electron-to-chromium": { + "version": "1.3.402", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.402.tgz", + "integrity": "sha512-gaCDfX7IUH0s3JmBiHCDPrvVcdnTTP1r4WLJc2dHkYYbLmXZ2XHiJCcGQ9Balf91aKTvuCKCyu2JjJYRykoI1w==", + "dev": true + }, + "elliptic": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz", + "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==", + "dev": true, + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "enhanced-resolve": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz", + "integrity": "sha512-98p2zE+rL7/g/DzMHMTF4zZlCgeVdJ7yr6xzEpJRYwFYrGi9ANdn5DnJURg6RpBkyk60XYDnWIv51VfIhfNGuA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + }, + "dependencies": { + "memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + } + } + }, + "errno": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "dev": true, + "requires": { + "prr": "~1.0.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "eslint-scope": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", + "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "dev": true + }, + "espree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.2.0.tgz", + "integrity": "sha512-weltsSqdeWIX9G2qQZz7KlTRJdkkOCTPgLYJUz1Hacf48R4YOwGPHO3+ORfWedqJKbq5WQmsgK90n+pFLIKt/Q==", + "dev": true, + "requires": { + "estraverse": "^5.0.0" + }, + "dependencies": { + "estraverse": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.0.0.tgz", + "integrity": "sha512-j3acdrMzqrxmJTNj5dbr1YbjacrYgAxVMeF0gK16E3j494mOe7xygM/ZLIguEQ0ETwAg2hlJCtHRGav+y0Ny5A==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "events": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.1.0.tgz", + "integrity": "sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg==", + "dev": true + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "fast-deep-equal": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", + "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "figgy-pudding": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", + "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==", + "dev": true + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "optional": true + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "findup-sync": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "dev": true, + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-readdir-recursive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", + "dev": true + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "gensync": { + "version": "1.0.0-beta.1", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", + "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "requires": { + "global-prefix": "^3.0.0" + }, + "dependencies": { + "global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "requires": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + } + } + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "graceful-fs": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hash-base": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "requires": { + "parse-passwd": "^1.0.0" + } + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", + "dev": true + }, + "iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", + "dev": true + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "dev": true, + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, + "inquirer": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.1.0.tgz", + "integrity": "sha512-5fJMWEmikSYu0nv/flMc475MhGbB7TSPd/2IpFV4I4rMklboCH2rQjYY5kKiYGHqUF9gvaambupcJFFG9dvReg==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^3.0.0", + "cli-cursor": "^3.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.15", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.5.3", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "interpret": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", + "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", + "dev": true + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "requires": { + "loose-envify": "^1.0.0" + } + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "json5": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", + "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, + "levenary": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/levenary/-/levenary-1.1.1.tgz", + "integrity": "sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ==", + "dev": true, + "requires": { + "leven": "^3.1.0" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", + "dev": true + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + } + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "dev": true, + "requires": { + "p-defer": "^1.0.0" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "mem": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", + "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + } + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "dev": true, + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + } + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "nan": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", + "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==", + "dev": true, + "optional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "neo-async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node-libs-browser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", + "dev": true, + "requires": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.1", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "^1.0.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } + } + }, + "node-releases": { + "version": "1.1.53", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.53.tgz", + "integrity": "sha512-wp8zyQVwef2hpZ/dJH7SfSrIPD6YoJz6BDQDpGEkcA0s3LpAQoxBIYmfIq6QAhC1DhwsyCgTaTTcONwX8qzCuQ==", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", + "dev": true + }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", + "dev": true + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", + "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "parallel-transform": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", + "dev": true, + "requires": { + "cyclist": "^1.0.1", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-asn1": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", + "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==", + "dev": true, + "requires": { + "asn1.js": "^4.0.0", + "browserify-aes": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "pbkdf2": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", + "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", + "dev": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + } + } + }, + "pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "dev": true + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "regenerate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", + "dev": true + }, + "regenerate-unicode-properties": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", + "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", + "dev": true, + "requires": { + "regenerate": "^1.4.0" + } + }, + "regenerator-runtime": { + "version": "0.13.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz", + "integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==", + "dev": true + }, + "regenerator-transform": { + "version": "0.14.4", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.4.tgz", + "integrity": "sha512-EaJaKPBI9GvKpvUz2mz4fhx7WPgvwRLY9v3hlNHWmAuJHI13T4nwKnNvm5RWJzEdnI5g5UwtOww+S8IdoUC2bw==", + "dev": true, + "requires": { + "@babel/runtime": "^7.8.4", + "private": "^0.1.8" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, + "regexpu-core": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.0.tgz", + "integrity": "sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ==", + "dev": true, + "requires": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.2.0", + "regjsgen": "^0.5.1", + "regjsparser": "^0.6.4", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.2.0" + } + }, + "regjsgen": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.1.tgz", + "integrity": "sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==", + "dev": true + }, + "regjsparser": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz", + "integrity": "sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + } + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "resolve": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", + "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + } + } + }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "dependencies": { + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + } + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "run-async": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.0.tgz", + "integrity": "sha512-xJTbh/d7Lm7SBhc1tNvTpeCHaEzoyxPrqNlvSdMfBTYwaY++UJFyXUOxAtsRUXjlqOfj8luNaR9vjCh4KeV+pg==", + "dev": true, + "requires": { + "is-promise": "^2.1.0" + } + }, + "run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "dev": true, + "requires": { + "aproba": "^1.1.1" + } + }, + "rxjs": { + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.5.tgz", + "integrity": "sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "schema-utils": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.5.tgz", + "integrity": "sha512-5KXuwKziQrTVHh8j/Uxz+QUbxkaLW9X/86NBlx/gnKgtsZA2GIVMUn17qWhRFwF8jdYb3Dig5hRO/W5mZqy6SQ==", + "dev": true, + "requires": { + "ajv": "^6.12.0", + "ajv-keywords": "^3.4.1" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "serialize-javascript": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz", + "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + } + } + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "dev": true, + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", + "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "ssri": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "stream-each": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", + "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "dev": true, + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", + "dev": true + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + } + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.0.tgz", + "integrity": "sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "dev": true + }, + "terser": { + "version": "4.6.11", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.6.11.tgz", + "integrity": "sha512-76Ynm7OXUG5xhOpblhytE7X58oeNSmC8xnNhjWVo8CksHit0U0kO4hfNbPrrYwowLWFgM2n9L176VNx2QaHmtA==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "terser-webpack-plugin": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz", + "integrity": "sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA==", + "dev": true, + "requires": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^2.1.2", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + }, + "dependencies": { + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "timers-browserify": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz", + "integrity": "sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==", + "dev": true, + "requires": { + "setimmediate": "^1.0.4" + } + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "tslib": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", + "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==", + "dev": true + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", + "dev": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "unicode-canonical-property-names-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "dev": true + }, + "unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", + "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", + "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==", + "dev": true + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + } + } + }, + "upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + } + } + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "dev": true, + "requires": { + "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "v8-compile-cache": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", + "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", + "dev": true + }, + "vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "dev": true + }, + "watchpack": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.1.tgz", + "integrity": "sha512-+IF9hfUFOrYOOaKyfaI7h7dquUIOgyEMoQMLA7OP5FxegKA2+XdXThAZ9TU2kucfhDH7rfMHs1oPYziVGWRnZA==", + "dev": true, + "requires": { + "chokidar": "^2.1.8", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0" + } + }, + "webpack": { + "version": "4.42.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.42.1.tgz", + "integrity": "sha512-SGfYMigqEfdGchGhFFJ9KyRpQKnipvEvjc1TwrXEPCM6H5Wywu10ka8o3KGrMzSMxMQKt8aCHUFh5DaQ9UmyRg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/wasm-edit": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "acorn": "^6.2.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^4.1.0", + "eslint-scope": "^4.0.3", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.3", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", + "schema-utils": "^1.0.0", + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.3", + "watchpack": "^1.6.0", + "webpack-sources": "^1.4.1" + }, + "dependencies": { + "acorn": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", + "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==", + "dev": true + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "webpack-cli": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.11.tgz", + "integrity": "sha512-dXlfuml7xvAFwYUPsrtQAA9e4DOe58gnzSxhgrO/ZM/gyXTBowrsYeubyN4mqGhYdpXMFNyQ6emjJS9M7OBd4g==", + "dev": true, + "requires": { + "chalk": "2.4.2", + "cross-spawn": "6.0.5", + "enhanced-resolve": "4.1.0", + "findup-sync": "3.0.0", + "global-modules": "2.0.0", + "import-local": "2.0.0", + "interpret": "1.2.0", + "loader-utils": "1.2.3", + "supports-color": "6.1.0", + "v8-compile-cache": "2.0.3", + "yargs": "13.2.4" + }, + "dependencies": { + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true + }, + "enhanced-resolve": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz", + "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.4.0", + "tapable": "^1.0.0" + } + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^2.0.0", + "json5": "^1.0.1" + } + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "v8-compile-cache": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz", + "integrity": "sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w==", + "dev": true + } + } + }, + "webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "dev": true, + "requires": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "worker-farm": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", + "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", + "dev": true, + "requires": { + "errno": "~0.1.7" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "yargs": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz", + "integrity": "sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "os-locale": "^3.1.0", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.0" + }, + "dependencies": { + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } +} diff --git a/v2/internal/runtime/js/package.json b/v2/internal/runtime/js/package.json new file mode 100644 index 000000000..1c4d079f4 --- /dev/null +++ b/v2/internal/runtime/js/package.json @@ -0,0 +1,44 @@ +{ + "name": "wails-runtime", + "version": "1.0.0", + "description": "The Javascript Wails Runtime", + "main": "index.js", + "scripts": { + "build:desktop": "npx eslint core/ && npx webpack --env desktop --colors", + "build:server": "npx eslint core/ && npx webpack --env server --colors", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/wailsapp/runtime.git" + }, + "keywords": [ + "Wails", + "Go", + "Javascript", + "Runtime" + ], + "browserslist": [ + "> 5%", + "IE 9" + ], + "author": "Lea Anthony ", + "license": "MIT", + "bugs": { + "url": "https://github.com/wailsapp/runtime/issues" + }, + "homepage": "https://github.com/wailsapp/runtime#readme", + "devDependencies": { + "@babel/cli": "^7.7.7", + "@babel/core": "^7.7.7", + "@babel/plugin-transform-object-assign": "^7.7.4", + "@babel/preset-env": "^7.7.7", + "babel-loader": "^8.0.6", + "babel-preset-minify": "^0.5.1", + "core-js": "^3.6.1", + "eslint": "^6.8.0", + "webpack": "^4.41.5", + "webpack-cli": "^3.3.10" + }, + "dependencies": {} +} diff --git a/v2/internal/runtime/js/package.json.md5 b/v2/internal/runtime/js/package.json.md5 new file mode 100644 index 000000000..c565f69d7 --- /dev/null +++ b/v2/internal/runtime/js/package.json.md5 @@ -0,0 +1 @@ +7a2c438e79cf603ba763055e515650be \ No newline at end of file diff --git a/v2/internal/runtime/js/runtime/.npmignore b/v2/internal/runtime/js/runtime/.npmignore new file mode 100644 index 000000000..e8310385c --- /dev/null +++ b/v2/internal/runtime/js/runtime/.npmignore @@ -0,0 +1 @@ +src \ No newline at end of file diff --git a/v2/internal/runtime/js/runtime/README.md b/v2/internal/runtime/js/runtime/README.md new file mode 100644 index 000000000..1859d4023 --- /dev/null +++ b/v2/internal/runtime/js/runtime/README.md @@ -0,0 +1,3 @@ +# Wails Runtime + +This module is the Javascript runtime library for the [Wails](https://wails.app) framework. It is intended to be installed as part of a [Wails](https://wails.app) V2 project, not a standalone module. diff --git a/v2/internal/runtime/js/runtime/bridge.js b/v2/internal/runtime/js/runtime/bridge.js new file mode 100644 index 000000000..a58076a98 --- /dev/null +++ b/v2/internal/runtime/js/runtime/bridge.js @@ -0,0 +1,1726 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : + typeof define === 'function' && define.amd ? define(['exports'], factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.bridge = {})); +}(this, (function (exports) { 'use strict'; + + function noop() { } + const identity = x => x; + function run(fn) { + return fn(); + } + function blank_object() { + return Object.create(null); + } + function run_all(fns) { + fns.forEach(run); + } + function is_function(thing) { + return typeof thing === 'function'; + } + function safe_not_equal(a, b) { + return a != a ? b == b : a !== b || ((a && typeof a === 'object') || typeof a === 'function'); + } + function is_empty(obj) { + return Object.keys(obj).length === 0; + } + function subscribe(store, ...callbacks) { + if (store == null) { + return noop; + } + const unsub = store.subscribe(...callbacks); + return unsub.unsubscribe ? () => unsub.unsubscribe() : unsub; + } + function component_subscribe(component, store, callback) { + component.$$.on_destroy.push(subscribe(store, callback)); + } + function action_destroyer(action_result) { + return action_result && is_function(action_result.destroy) ? action_result.destroy : noop; + } + + const is_client = typeof window !== 'undefined'; + let now = is_client + ? () => window.performance.now() + : () => Date.now(); + let raf = is_client ? cb => requestAnimationFrame(cb) : noop; + + const tasks = new Set(); + function run_tasks(now) { + tasks.forEach(task => { + if (!task.c(now)) { + tasks.delete(task); + task.f(); + } + }); + if (tasks.size !== 0) + raf(run_tasks); + } + /** + * Creates a new task that runs on each raf frame + * until it returns a falsy value or is aborted + */ + function loop(callback) { + let task; + if (tasks.size === 0) + raf(run_tasks); + return { + promise: new Promise(fulfill => { + tasks.add(task = { c: callback, f: fulfill }); + }), + abort() { + tasks.delete(task); + } + }; + } + + function append(target, node) { + target.appendChild(node); + } + function insert(target, node, anchor) { + target.insertBefore(node, anchor || null); + } + function detach(node) { + node.parentNode.removeChild(node); + } + function destroy_each(iterations, detaching) { + for (let i = 0; i < iterations.length; i += 1) { + if (iterations[i]) + iterations[i].d(detaching); + } + } + function element(name) { + return document.createElement(name); + } + function text(data) { + return document.createTextNode(data); + } + function space() { + return text(' '); + } + function empty() { + return text(''); + } + function listen(node, event, handler, options) { + node.addEventListener(event, handler, options); + return () => node.removeEventListener(event, handler, options); + } + function attr(node, attribute, value) { + if (value == null) + node.removeAttribute(attribute); + else if (node.getAttribute(attribute) !== value) + node.setAttribute(attribute, value); + } + function children(element) { + return Array.from(element.childNodes); + } + function set_data(text, data) { + data = '' + data; + if (text.wholeText !== data) + text.data = data; + } + function custom_event(type, detail) { + const e = document.createEvent('CustomEvent'); + e.initCustomEvent(type, false, false, detail); + return e; + } + + const active_docs = new Set(); + let active = 0; + // https://github.com/darkskyapp/string-hash/blob/master/index.js + function hash(str) { + let hash = 5381; + let i = str.length; + while (i--) + hash = ((hash << 5) - hash) ^ str.charCodeAt(i); + return hash >>> 0; + } + function create_rule(node, a, b, duration, delay, ease, fn, uid = 0) { + const step = 16.666 / duration; + let keyframes = '{\n'; + for (let p = 0; p <= 1; p += step) { + const t = a + (b - a) * ease(p); + keyframes += p * 100 + `%{${fn(t, 1 - t)}}\n`; + } + const rule = keyframes + `100% {${fn(b, 1 - b)}}\n}`; + const name = `__svelte_${hash(rule)}_${uid}`; + const doc = node.ownerDocument; + active_docs.add(doc); + const stylesheet = doc.__svelte_stylesheet || (doc.__svelte_stylesheet = doc.head.appendChild(element('style')).sheet); + const current_rules = doc.__svelte_rules || (doc.__svelte_rules = {}); + if (!current_rules[name]) { + current_rules[name] = true; + stylesheet.insertRule(`@keyframes ${name} ${rule}`, stylesheet.cssRules.length); + } + const animation = node.style.animation || ''; + node.style.animation = `${animation ? `${animation}, ` : ''}${name} ${duration}ms linear ${delay}ms 1 both`; + active += 1; + return name; + } + function delete_rule(node, name) { + const previous = (node.style.animation || '').split(', '); + const next = previous.filter(name + ? anim => anim.indexOf(name) < 0 // remove specific animation + : anim => anim.indexOf('__svelte') === -1 // remove all Svelte animations + ); + const deleted = previous.length - next.length; + if (deleted) { + node.style.animation = next.join(', '); + active -= deleted; + if (!active) + clear_rules(); + } + } + function clear_rules() { + raf(() => { + if (active) + return; + active_docs.forEach(doc => { + const stylesheet = doc.__svelte_stylesheet; + let i = stylesheet.cssRules.length; + while (i--) + stylesheet.deleteRule(i); + doc.__svelte_rules = {}; + }); + active_docs.clear(); + }); + } + + let current_component; + function set_current_component(component) { + current_component = component; + } + function get_current_component() { + if (!current_component) + throw new Error('Function called outside component initialization'); + return current_component; + } + function onMount(fn) { + get_current_component().$$.on_mount.push(fn); + } + + const dirty_components = []; + const binding_callbacks = []; + const render_callbacks = []; + const flush_callbacks = []; + const resolved_promise = Promise.resolve(); + let update_scheduled = false; + function schedule_update() { + if (!update_scheduled) { + update_scheduled = true; + resolved_promise.then(flush); + } + } + function add_render_callback(fn) { + render_callbacks.push(fn); + } + let flushing = false; + const seen_callbacks = new Set(); + function flush() { + if (flushing) + return; + flushing = true; + do { + // first, call beforeUpdate functions + // and update components + for (let i = 0; i < dirty_components.length; i += 1) { + const component = dirty_components[i]; + set_current_component(component); + update(component.$$); + } + set_current_component(null); + dirty_components.length = 0; + while (binding_callbacks.length) + binding_callbacks.pop()(); + // then, once components are updated, call + // afterUpdate functions. This may cause + // subsequent updates... + for (let i = 0; i < render_callbacks.length; i += 1) { + const callback = render_callbacks[i]; + if (!seen_callbacks.has(callback)) { + // ...so guard against infinite loops + seen_callbacks.add(callback); + callback(); + } + } + render_callbacks.length = 0; + } while (dirty_components.length); + while (flush_callbacks.length) { + flush_callbacks.pop()(); + } + update_scheduled = false; + flushing = false; + seen_callbacks.clear(); + } + function update($$) { + if ($$.fragment !== null) { + $$.update(); + run_all($$.before_update); + const dirty = $$.dirty; + $$.dirty = [-1]; + $$.fragment && $$.fragment.p($$.ctx, dirty); + $$.after_update.forEach(add_render_callback); + } + } + + let promise; + function wait() { + if (!promise) { + promise = Promise.resolve(); + promise.then(() => { + promise = null; + }); + } + return promise; + } + function dispatch(node, direction, kind) { + node.dispatchEvent(custom_event(`${direction ? 'intro' : 'outro'}${kind}`)); + } + const outroing = new Set(); + let outros; + function group_outros() { + outros = { + r: 0, + c: [], + p: outros // parent group + }; + } + function check_outros() { + if (!outros.r) { + run_all(outros.c); + } + outros = outros.p; + } + function transition_in(block, local) { + if (block && block.i) { + outroing.delete(block); + block.i(local); + } + } + function transition_out(block, local, detach, callback) { + if (block && block.o) { + if (outroing.has(block)) + return; + outroing.add(block); + outros.c.push(() => { + outroing.delete(block); + if (callback) { + if (detach) + block.d(1); + callback(); + } + }); + block.o(local); + } + } + const null_transition = { duration: 0 }; + function create_bidirectional_transition(node, fn, params, intro) { + let config = fn(node, params); + let t = intro ? 0 : 1; + let running_program = null; + let pending_program = null; + let animation_name = null; + function clear_animation() { + if (animation_name) + delete_rule(node, animation_name); + } + function init(program, duration) { + const d = program.b - t; + duration *= Math.abs(d); + return { + a: t, + b: program.b, + d, + duration, + start: program.start, + end: program.start + duration, + group: program.group + }; + } + function go(b) { + const { delay = 0, duration = 300, easing = identity, tick = noop, css } = config || null_transition; + const program = { + start: now() + delay, + b + }; + if (!b) { + // @ts-ignore todo: improve typings + program.group = outros; + outros.r += 1; + } + if (running_program || pending_program) { + pending_program = program; + } + else { + // if this is an intro, and there's a delay, we need to do + // an initial tick and/or apply CSS animation immediately + if (css) { + clear_animation(); + animation_name = create_rule(node, t, b, duration, delay, easing, css); + } + if (b) + tick(0, 1); + running_program = init(program, duration); + add_render_callback(() => dispatch(node, b, 'start')); + loop(now => { + if (pending_program && now > pending_program.start) { + running_program = init(pending_program, duration); + pending_program = null; + dispatch(node, running_program.b, 'start'); + if (css) { + clear_animation(); + animation_name = create_rule(node, t, running_program.b, running_program.duration, 0, easing, config.css); + } + } + if (running_program) { + if (now >= running_program.end) { + tick(t = running_program.b, 1 - t); + dispatch(node, running_program.b, 'end'); + if (!pending_program) { + // we're done + if (running_program.b) { + // intro — we can tidy up immediately + clear_animation(); + } + else { + // outro — needs to be coordinated + if (!--running_program.group.r) + run_all(running_program.group.c); + } + } + running_program = null; + } + else if (now >= running_program.start) { + const p = now - running_program.start; + t = running_program.a + running_program.d * easing(p / running_program.duration); + tick(t, 1 - t); + } + } + return !!(running_program || pending_program); + }); + } + } + return { + run(b) { + if (is_function(config)) { + wait().then(() => { + // @ts-ignore + config = config(); + go(b); + }); + } + else { + go(b); + } + }, + end() { + clear_animation(); + running_program = pending_program = null; + } + }; + } + + const globals = (typeof window !== 'undefined' + ? window + : typeof globalThis !== 'undefined' + ? globalThis + : global); + function create_component(block) { + block && block.c(); + } + function mount_component(component, target, anchor) { + const { fragment, on_mount, on_destroy, after_update } = component.$$; + fragment && fragment.m(target, anchor); + // onMount happens before the initial afterUpdate + add_render_callback(() => { + const new_on_destroy = on_mount.map(run).filter(is_function); + if (on_destroy) { + on_destroy.push(...new_on_destroy); + } + else { + // Edge case - component was destroyed immediately, + // most likely as a result of a binding initialising + run_all(new_on_destroy); + } + component.$$.on_mount = []; + }); + after_update.forEach(add_render_callback); + } + function destroy_component(component, detaching) { + const $$ = component.$$; + if ($$.fragment !== null) { + run_all($$.on_destroy); + $$.fragment && $$.fragment.d(detaching); + // TODO null out other refs, including component.$$ (but need to + // preserve final state?) + $$.on_destroy = $$.fragment = null; + $$.ctx = []; + } + } + function make_dirty(component, i) { + if (component.$$.dirty[0] === -1) { + dirty_components.push(component); + schedule_update(); + component.$$.dirty.fill(0); + } + component.$$.dirty[(i / 31) | 0] |= (1 << (i % 31)); + } + function init(component, options, instance, create_fragment, not_equal, props, dirty = [-1]) { + const parent_component = current_component; + set_current_component(component); + const $$ = component.$$ = { + fragment: null, + ctx: null, + // state + props, + update: noop, + not_equal, + bound: blank_object(), + // lifecycle + on_mount: [], + on_destroy: [], + before_update: [], + after_update: [], + context: new Map(parent_component ? parent_component.$$.context : []), + // everything else + callbacks: blank_object(), + dirty, + skip_bound: false + }; + let ready = false; + $$.ctx = instance + ? instance(component, options.props || {}, (i, ret, ...rest) => { + const value = rest.length ? rest[0] : ret; + if ($$.ctx && not_equal($$.ctx[i], $$.ctx[i] = value)) { + if (!$$.skip_bound && $$.bound[i]) + $$.bound[i](value); + if (ready) + make_dirty(component, i); + } + return ret; + }) + : []; + $$.update(); + ready = true; + run_all($$.before_update); + // `false` as a special case of no DOM component + $$.fragment = create_fragment ? create_fragment($$.ctx) : false; + if (options.target) { + if (options.hydrate) { + const nodes = children(options.target); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + $$.fragment && $$.fragment.l(nodes); + nodes.forEach(detach); + } + else { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + $$.fragment && $$.fragment.c(); + } + if (options.intro) + transition_in(component.$$.fragment); + mount_component(component, options.target, options.anchor); + flush(); + } + set_current_component(parent_component); + } + /** + * Base class for Svelte components. Used when dev=false. + */ + class SvelteComponent { + $destroy() { + destroy_component(this, 1); + this.$destroy = noop; + } + $on(type, callback) { + const callbacks = (this.$$.callbacks[type] || (this.$$.callbacks[type] = [])); + callbacks.push(callback); + return () => { + const index = callbacks.indexOf(callback); + if (index !== -1) + callbacks.splice(index, 1); + }; + } + $set($$props) { + if (this.$$set && !is_empty($$props)) { + this.$$.skip_bound = true; + this.$$set($$props); + this.$$.skip_bound = false; + } + } + } + + const subscriber_queue = []; + /** + * Create a `Writable` store that allows both updating and reading by subscription. + * @param {*=}value initial value + * @param {StartStopNotifier=}start start and stop notifications for subscriptions + */ + function writable(value, start = noop) { + let stop; + const subscribers = []; + function set(new_value) { + if (safe_not_equal(value, new_value)) { + value = new_value; + if (stop) { // store is ready + const run_queue = !subscriber_queue.length; + for (let i = 0; i < subscribers.length; i += 1) { + const s = subscribers[i]; + s[1](); + subscriber_queue.push(s, value); + } + if (run_queue) { + for (let i = 0; i < subscriber_queue.length; i += 2) { + subscriber_queue[i][0](subscriber_queue[i + 1]); + } + subscriber_queue.length = 0; + } + } + } + } + function update(fn) { + set(fn(value)); + } + function subscribe(run, invalidate = noop) { + const subscriber = [run, invalidate]; + subscribers.push(subscriber); + if (subscribers.length === 1) { + stop = start(set) || noop; + } + run(value); + return () => { + const index = subscribers.indexOf(subscriber); + if (index !== -1) { + subscribers.splice(index, 1); + } + if (subscribers.length === 0) { + stop(); + stop = null; + } + }; + } + return { set, update, subscribe }; + } + + function log(message) { + // eslint-disable-next-line + console.log( + '%c wails bridge %c ' + message + ' ', + 'background: #aa0000; color: #fff; border-radius: 3px 0px 0px 3px; padding: 1px; font-size: 0.7rem', + 'background: #009900; color: #fff; border-radius: 0px 3px 3px 0px; padding: 1px; font-size: 0.7rem' + ); + } + + /** Overlay */ + const overlayVisible = writable(false); + + function showOverlay() { + overlayVisible.set(true); + } + function hideOverlay() { + overlayVisible.set(false); + } + + /** Menubar **/ + const menuVisible = writable(false); + + /** Trays **/ + + const trays = writable([]); + function setTray(tray) { + trays.update((current) => { + // Remove existing if it exists, else add + const index = current.findIndex(item => item.ID === tray.ID); + if ( index === -1 ) { + current.push(tray); + } else { + current[index] = tray; + } + return current; + }); + } + function updateTrayLabel(tray) { + trays.update((current) => { + // Remove existing if it exists, else add + const index = current.findIndex(item => item.ID === tray.ID); + if ( index === -1 ) { + return log("ERROR: Attempted to update tray index ", tray.ID) + } + current[index].Label = tray.Label; + return current; + }); + } + + function deleteTrayMenu(id) { + trays.update((current) => { + // Remove existing if it exists, else add + const index = current.findIndex(item => item.ID === id); + if ( index === -1 ) { + return log("ERROR: Attempted to delete tray index ") + } + current.splice(index, 1); + return current; + }); + } + + let selectedMenu = writable(null); + + function fade(node, { delay = 0, duration = 400, easing = identity } = {}) { + const o = +getComputedStyle(node).opacity; + return { + delay, + duration, + easing, + css: t => `opacity: ${t * o}` + }; + } + + /* Overlay.svelte generated by Svelte v3.32.2 */ + + function add_css() { + var style = element("style"); + style.id = "svelte-1m56lfo-style"; + style.textContent = ".wails-reconnect-overlay.svelte-1m56lfo{position:fixed;top:0;left:0;width:100%;height:100%;backdrop-filter:blur(20px) saturate(160%) contrast(45%) brightness(140%);z-index:999999\n }.wails-reconnect-overlay-content.svelte-1m56lfo{position:relative;top:50%;transform:translateY(-50%);margin:0;background-image:url(data:image/png;base64,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);background-repeat:no-repeat;background-position:center\n }.wails-reconnect-overlay-loadingspinner.svelte-1m56lfo{pointer-events:none;width:2.5em;height:2.5em;border:.4em solid transparent;border-color:#f00 #eee0 #f00 #eee0;border-radius:50%;animation:svelte-1m56lfo-loadingspin 1s linear infinite;margin:auto;padding:2.5em\n }@keyframes svelte-1m56lfo-loadingspin{100%{transform:rotate(360deg)}}"; + append(document.head, style); + } + + // (8:0) {#if $overlayVisible } + function create_if_block(ctx) { + let div2; + let div2_transition; + let current; + + return { + c() { + div2 = element("div"); + div2.innerHTML = `
`; + attr(div2, "class", "wails-reconnect-overlay svelte-1m56lfo"); + }, + m(target, anchor) { + insert(target, div2, anchor); + current = true; + }, + i(local) { + if (current) return; + + add_render_callback(() => { + if (!div2_transition) div2_transition = create_bidirectional_transition(div2, fade, { duration: 200 }, true); + div2_transition.run(1); + }); + + current = true; + }, + o(local) { + if (!div2_transition) div2_transition = create_bidirectional_transition(div2, fade, { duration: 200 }, false); + div2_transition.run(0); + current = false; + }, + d(detaching) { + if (detaching) detach(div2); + if (detaching && div2_transition) div2_transition.end(); + } + }; + } + + function create_fragment(ctx) { + let if_block_anchor; + let current; + let if_block = /*$overlayVisible*/ ctx[0] && create_if_block(); + + return { + c() { + if (if_block) if_block.c(); + if_block_anchor = empty(); + }, + m(target, anchor) { + if (if_block) if_block.m(target, anchor); + insert(target, if_block_anchor, anchor); + current = true; + }, + p(ctx, [dirty]) { + if (/*$overlayVisible*/ ctx[0]) { + if (if_block) { + if (dirty & /*$overlayVisible*/ 1) { + transition_in(if_block, 1); + } + } else { + if_block = create_if_block(); + if_block.c(); + transition_in(if_block, 1); + if_block.m(if_block_anchor.parentNode, if_block_anchor); + } + } else if (if_block) { + group_outros(); + + transition_out(if_block, 1, 1, () => { + if_block = null; + }); + + check_outros(); + } + }, + i(local) { + if (current) return; + transition_in(if_block); + current = true; + }, + o(local) { + transition_out(if_block); + current = false; + }, + d(detaching) { + if (if_block) if_block.d(detaching); + if (detaching) detach(if_block_anchor); + } + }; + } + + function instance($$self, $$props, $$invalidate) { + let $overlayVisible; + component_subscribe($$self, overlayVisible, $$value => $$invalidate(0, $overlayVisible = $$value)); + return [$overlayVisible]; + } + + class Overlay extends SvelteComponent { + constructor(options) { + super(); + if (!document.getElementById("svelte-1m56lfo-style")) add_css(); + init(this, options, instance, create_fragment, safe_not_equal, {}); + } + } + + /* Menu.svelte generated by Svelte v3.32.2 */ + + function add_css$1() { + var style = element("style"); + style.id = "svelte-1oysp7o-style"; + style.textContent = ".menu.svelte-1oysp7o.svelte-1oysp7o{padding:3px;background-color:#0008;color:#EEF;border-radius:5px;margin-top:5px;position:absolute;backdrop-filter:blur(3px) saturate(160%) contrast(45%) brightness(140%);border:1px solid rgb(88,88,88);box-shadow:0 0 1px rgb(146,146,148) inset}.menuitem.svelte-1oysp7o.svelte-1oysp7o{display:flex;align-items:center;padding:1px 5px}.menuitem.svelte-1oysp7o.svelte-1oysp7o:hover{display:flex;align-items:center;background-color:rgb(57,131,223);padding:1px 5px;border-radius:5px}.menuitem.svelte-1oysp7o img.svelte-1oysp7o{padding-right:5px}"; + append(document.head, style); + } + + function get_each_context(ctx, list, i) { + const child_ctx = ctx.slice(); + child_ctx[2] = list[i]; + return child_ctx; + } + + // (8:0) {#if !hidden} + function create_if_block$1(ctx) { + let div; + let if_block = /*menu*/ ctx[0].Menu && create_if_block_1(ctx); + + return { + c() { + div = element("div"); + if (if_block) if_block.c(); + attr(div, "class", "menu svelte-1oysp7o"); + }, + m(target, anchor) { + insert(target, div, anchor); + if (if_block) if_block.m(div, null); + }, + p(ctx, dirty) { + if (/*menu*/ ctx[0].Menu) { + if (if_block) { + if_block.p(ctx, dirty); + } else { + if_block = create_if_block_1(ctx); + if_block.c(); + if_block.m(div, null); + } + } else if (if_block) { + if_block.d(1); + if_block = null; + } + }, + d(detaching) { + if (detaching) detach(div); + if (if_block) if_block.d(); + } + }; + } + + // (10:4) {#if menu.Menu } + function create_if_block_1(ctx) { + let each_1_anchor; + let each_value = /*menu*/ ctx[0].Menu.Items; + let each_blocks = []; + + for (let i = 0; i < each_value.length; i += 1) { + each_blocks[i] = create_each_block(get_each_context(ctx, each_value, i)); + } + + return { + c() { + for (let i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].c(); + } + + each_1_anchor = empty(); + }, + m(target, anchor) { + for (let i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].m(target, anchor); + } + + insert(target, each_1_anchor, anchor); + }, + p(ctx, dirty) { + if (dirty & /*menu*/ 1) { + each_value = /*menu*/ ctx[0].Menu.Items; + let i; + + for (i = 0; i < each_value.length; i += 1) { + const child_ctx = get_each_context(ctx, each_value, i); + + if (each_blocks[i]) { + each_blocks[i].p(child_ctx, dirty); + } else { + each_blocks[i] = create_each_block(child_ctx); + each_blocks[i].c(); + each_blocks[i].m(each_1_anchor.parentNode, each_1_anchor); + } + } + + for (; i < each_blocks.length; i += 1) { + each_blocks[i].d(1); + } + + each_blocks.length = each_value.length; + } + }, + d(detaching) { + destroy_each(each_blocks, detaching); + if (detaching) detach(each_1_anchor); + } + }; + } + + // (13:12) {#if menuItem.Image } + function create_if_block_2(ctx) { + let div; + let img; + let img_src_value; + + return { + c() { + div = element("div"); + img = element("img"); + attr(img, "alt", ""); + if (img.src !== (img_src_value = "data:image/png;base64," + /*menuItem*/ ctx[2].Image)) attr(img, "src", img_src_value); + attr(img, "class", "svelte-1oysp7o"); + }, + m(target, anchor) { + insert(target, div, anchor); + append(div, img); + }, + p(ctx, dirty) { + if (dirty & /*menu*/ 1 && img.src !== (img_src_value = "data:image/png;base64," + /*menuItem*/ ctx[2].Image)) { + attr(img, "src", img_src_value); + } + }, + d(detaching) { + if (detaching) detach(div); + } + }; + } + + // (11:8) {#each menu.Menu.Items as menuItem} + function create_each_block(ctx) { + let div1; + let t0; + let div0; + let t1_value = /*menuItem*/ ctx[2].Label + ""; + let t1; + let t2; + let if_block = /*menuItem*/ ctx[2].Image && create_if_block_2(ctx); + + return { + c() { + div1 = element("div"); + if (if_block) if_block.c(); + t0 = space(); + div0 = element("div"); + t1 = text(t1_value); + t2 = space(); + attr(div0, "class", "menulabel"); + attr(div1, "class", "menuitem svelte-1oysp7o"); + }, + m(target, anchor) { + insert(target, div1, anchor); + if (if_block) if_block.m(div1, null); + append(div1, t0); + append(div1, div0); + append(div0, t1); + append(div1, t2); + }, + p(ctx, dirty) { + if (/*menuItem*/ ctx[2].Image) { + if (if_block) { + if_block.p(ctx, dirty); + } else { + if_block = create_if_block_2(ctx); + if_block.c(); + if_block.m(div1, t0); + } + } else if (if_block) { + if_block.d(1); + if_block = null; + } + + if (dirty & /*menu*/ 1 && t1_value !== (t1_value = /*menuItem*/ ctx[2].Label + "")) set_data(t1, t1_value); + }, + d(detaching) { + if (detaching) detach(div1); + if (if_block) if_block.d(); + } + }; + } + + function create_fragment$1(ctx) { + let if_block_anchor; + let if_block = !/*hidden*/ ctx[1] && create_if_block$1(ctx); + + return { + c() { + if (if_block) if_block.c(); + if_block_anchor = empty(); + }, + m(target, anchor) { + if (if_block) if_block.m(target, anchor); + insert(target, if_block_anchor, anchor); + }, + p(ctx, [dirty]) { + if (!/*hidden*/ ctx[1]) { + if (if_block) { + if_block.p(ctx, dirty); + } else { + if_block = create_if_block$1(ctx); + if_block.c(); + if_block.m(if_block_anchor.parentNode, if_block_anchor); + } + } else if (if_block) { + if_block.d(1); + if_block = null; + } + }, + i: noop, + o: noop, + d(detaching) { + if (if_block) if_block.d(detaching); + if (detaching) detach(if_block_anchor); + } + }; + } + + function instance$1($$self, $$props, $$invalidate) { + let { menu } = $$props; + let { hidden = true } = $$props; + + $$self.$$set = $$props => { + if ("menu" in $$props) $$invalidate(0, menu = $$props.menu); + if ("hidden" in $$props) $$invalidate(1, hidden = $$props.hidden); + }; + + return [menu, hidden]; + } + + class Menu extends SvelteComponent { + constructor(options) { + super(); + if (!document.getElementById("svelte-1oysp7o-style")) add_css$1(); + init(this, options, instance$1, create_fragment$1, safe_not_equal, { menu: 0, hidden: 1 }); + } + } + + /* TrayMenu.svelte generated by Svelte v3.32.2 */ + + const { document: document_1 } = globals; + + function add_css$2() { + var style = element("style"); + style.id = "svelte-esze1k-style"; + style.textContent = ".tray-menu.svelte-esze1k{padding-left:0.5rem;padding-right:0.5rem;overflow:visible;font-size:14px}.label.svelte-esze1k{text-align:right;padding-right:10px}"; + append(document_1.head, style); + } + + // (47:4) {#if tray.ProcessedMenu } + function create_if_block$2(ctx) { + let menu; + let current; + + menu = new Menu({ + props: { + menu: /*tray*/ ctx[0].ProcessedMenu, + hidden: /*hidden*/ ctx[1] + } + }); + + return { + c() { + create_component(menu.$$.fragment); + }, + m(target, anchor) { + mount_component(menu, target, anchor); + current = true; + }, + p(ctx, dirty) { + const menu_changes = {}; + if (dirty & /*tray*/ 1) menu_changes.menu = /*tray*/ ctx[0].ProcessedMenu; + if (dirty & /*hidden*/ 2) menu_changes.hidden = /*hidden*/ ctx[1]; + menu.$set(menu_changes); + }, + i(local) { + if (current) return; + transition_in(menu.$$.fragment, local); + current = true; + }, + o(local) { + transition_out(menu.$$.fragment, local); + current = false; + }, + d(detaching) { + destroy_component(menu, detaching); + } + }; + } + + function create_fragment$2(ctx) { + let span1; + let span0; + let t0_value = /*tray*/ ctx[0].Label + ""; + let t0; + let t1; + let current; + let mounted; + let dispose; + let if_block = /*tray*/ ctx[0].ProcessedMenu && create_if_block$2(ctx); + + return { + c() { + span1 = element("span"); + span0 = element("span"); + t0 = text(t0_value); + t1 = space(); + if (if_block) if_block.c(); + attr(span0, "class", "label svelte-esze1k"); + attr(span1, "class", "tray-menu svelte-esze1k"); + }, + m(target, anchor) { + insert(target, span1, anchor); + append(span1, span0); + append(span0, t0); + append(span1, t1); + if (if_block) if_block.m(span1, null); + current = true; + + if (!mounted) { + dispose = [ + listen(span0, "click", /*trayClicked*/ ctx[3]), + action_destroyer(clickOutside.call(null, span1)), + listen(span1, "click_outside", /*closeMenu*/ ctx[2]) + ]; + + mounted = true; + } + }, + p(ctx, [dirty]) { + if ((!current || dirty & /*tray*/ 1) && t0_value !== (t0_value = /*tray*/ ctx[0].Label + "")) set_data(t0, t0_value); + + if (/*tray*/ ctx[0].ProcessedMenu) { + if (if_block) { + if_block.p(ctx, dirty); + + if (dirty & /*tray*/ 1) { + transition_in(if_block, 1); + } + } else { + if_block = create_if_block$2(ctx); + if_block.c(); + transition_in(if_block, 1); + if_block.m(span1, null); + } + } else if (if_block) { + group_outros(); + + transition_out(if_block, 1, 1, () => { + if_block = null; + }); + + check_outros(); + } + }, + i(local) { + if (current) return; + transition_in(if_block); + current = true; + }, + o(local) { + transition_out(if_block); + current = false; + }, + d(detaching) { + if (detaching) detach(span1); + if (if_block) if_block.d(); + mounted = false; + run_all(dispose); + } + }; + } + + function clickOutside(node) { + const handleClick = event => { + if (node && !node.contains(event.target) && !event.defaultPrevented) { + node.dispatchEvent(new CustomEvent("click_outside", node)); + } + }; + + document.addEventListener("click", handleClick, true); + + return { + destroy() { + document.removeEventListener("click", handleClick, true); + } + }; + } + + function instance$2($$self, $$props, $$invalidate) { + let hidden; + let $selectedMenu; + component_subscribe($$self, selectedMenu, $$value => $$invalidate(4, $selectedMenu = $$value)); + let { tray = null } = $$props; + + function closeMenu() { + selectedMenu.set(null); + } + + function trayClicked() { + if ($selectedMenu !== tray) { + selectedMenu.set(tray); + } else { + selectedMenu.set(null); + } + } + + $$self.$$set = $$props => { + if ("tray" in $$props) $$invalidate(0, tray = $$props.tray); + }; + + $$self.$$.update = () => { + if ($$self.$$.dirty & /*$selectedMenu, tray*/ 17) { + $$invalidate(1, hidden = $selectedMenu !== tray); + } + }; + + return [tray, hidden, closeMenu, trayClicked, $selectedMenu]; + } + + class TrayMenu extends SvelteComponent { + constructor(options) { + super(); + if (!document_1.getElementById("svelte-esze1k-style")) add_css$2(); + init(this, options, instance$2, create_fragment$2, safe_not_equal, { tray: 0 }); + } + } + + /* Menubar.svelte generated by Svelte v3.32.2 */ + + function add_css$3() { + var style = element("style"); + style.id = "svelte-1i0zb4n-style"; + style.textContent = ".tray-menus.svelte-1i0zb4n{display:flex;flex-direction:row;justify-content:flex-end}.wails-menubar.svelte-1i0zb4n{position:relative;display:block;top:0;height:2rem;width:100%;border-bottom:1px solid #b3b3b3;box-shadow:0 0 10px 0 #33333360}.time.svelte-1i0zb4n{padding-left:0.5rem;padding-right:1.5rem;overflow:visible;font-size:14px}"; + append(document.head, style); + } + + function get_each_context$1(ctx, list, i) { + const child_ctx = ctx.slice(); + child_ctx[9] = list[i]; + return child_ctx; + } + + // (38:0) {#if $menuVisible } + function create_if_block$3(ctx) { + let div; + let span1; + let t0; + let span0; + let t1; + let div_transition; + let current; + let each_value = /*$trays*/ ctx[2]; + let each_blocks = []; + + for (let i = 0; i < each_value.length; i += 1) { + each_blocks[i] = create_each_block$1(get_each_context$1(ctx, each_value, i)); + } + + const out = i => transition_out(each_blocks[i], 1, 1, () => { + each_blocks[i] = null; + }); + + return { + c() { + div = element("div"); + span1 = element("span"); + + for (let i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].c(); + } + + t0 = space(); + span0 = element("span"); + t1 = text(/*dateTimeString*/ ctx[0]); + attr(span0, "class", "time svelte-1i0zb4n"); + attr(span1, "class", "tray-menus svelte-1i0zb4n"); + attr(div, "class", "wails-menubar svelte-1i0zb4n"); + }, + m(target, anchor) { + insert(target, div, anchor); + append(div, span1); + + for (let i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].m(span1, null); + } + + append(span1, t0); + append(span1, span0); + append(span0, t1); + current = true; + }, + p(ctx, dirty) { + if (dirty & /*$trays*/ 4) { + each_value = /*$trays*/ ctx[2]; + let i; + + for (i = 0; i < each_value.length; i += 1) { + const child_ctx = get_each_context$1(ctx, each_value, i); + + if (each_blocks[i]) { + each_blocks[i].p(child_ctx, dirty); + transition_in(each_blocks[i], 1); + } else { + each_blocks[i] = create_each_block$1(child_ctx); + each_blocks[i].c(); + transition_in(each_blocks[i], 1); + each_blocks[i].m(span1, t0); + } + } + + group_outros(); + + for (i = each_value.length; i < each_blocks.length; i += 1) { + out(i); + } + + check_outros(); + } + + if (!current || dirty & /*dateTimeString*/ 1) set_data(t1, /*dateTimeString*/ ctx[0]); + }, + i(local) { + if (current) return; + + for (let i = 0; i < each_value.length; i += 1) { + transition_in(each_blocks[i]); + } + + add_render_callback(() => { + if (!div_transition) div_transition = create_bidirectional_transition(div, fade, {}, true); + div_transition.run(1); + }); + + current = true; + }, + o(local) { + each_blocks = each_blocks.filter(Boolean); + + for (let i = 0; i < each_blocks.length; i += 1) { + transition_out(each_blocks[i]); + } + + if (!div_transition) div_transition = create_bidirectional_transition(div, fade, {}, false); + div_transition.run(0); + current = false; + }, + d(detaching) { + if (detaching) detach(div); + destroy_each(each_blocks, detaching); + if (detaching && div_transition) div_transition.end(); + } + }; + } + + // (41:4) {#each $trays as tray} + function create_each_block$1(ctx) { + let traymenu; + let current; + traymenu = new TrayMenu({ props: { tray: /*tray*/ ctx[9] } }); + + return { + c() { + create_component(traymenu.$$.fragment); + }, + m(target, anchor) { + mount_component(traymenu, target, anchor); + current = true; + }, + p(ctx, dirty) { + const traymenu_changes = {}; + if (dirty & /*$trays*/ 4) traymenu_changes.tray = /*tray*/ ctx[9]; + traymenu.$set(traymenu_changes); + }, + i(local) { + if (current) return; + transition_in(traymenu.$$.fragment, local); + current = true; + }, + o(local) { + transition_out(traymenu.$$.fragment, local); + current = false; + }, + d(detaching) { + destroy_component(traymenu, detaching); + } + }; + } + + function create_fragment$3(ctx) { + let if_block_anchor; + let current; + let mounted; + let dispose; + let if_block = /*$menuVisible*/ ctx[1] && create_if_block$3(ctx); + + return { + c() { + if (if_block) if_block.c(); + if_block_anchor = empty(); + }, + m(target, anchor) { + if (if_block) if_block.m(target, anchor); + insert(target, if_block_anchor, anchor); + current = true; + + if (!mounted) { + dispose = listen(window, "keydown", /*handleKeydown*/ ctx[3]); + mounted = true; + } + }, + p(ctx, [dirty]) { + if (/*$menuVisible*/ ctx[1]) { + if (if_block) { + if_block.p(ctx, dirty); + + if (dirty & /*$menuVisible*/ 2) { + transition_in(if_block, 1); + } + } else { + if_block = create_if_block$3(ctx); + if_block.c(); + transition_in(if_block, 1); + if_block.m(if_block_anchor.parentNode, if_block_anchor); + } + } else if (if_block) { + group_outros(); + + transition_out(if_block, 1, 1, () => { + if_block = null; + }); + + check_outros(); + } + }, + i(local) { + if (current) return; + transition_in(if_block); + current = true; + }, + o(local) { + transition_out(if_block); + current = false; + }, + d(detaching) { + if (if_block) if_block.d(detaching); + if (detaching) detach(if_block_anchor); + mounted = false; + dispose(); + } + }; + } + + function instance$3($$self, $$props, $$invalidate) { + let day; + let dom; + let mon; + let currentTime; + let dateTimeString; + let $menuVisible; + let $trays; + component_subscribe($$self, menuVisible, $$value => $$invalidate(1, $menuVisible = $$value)); + component_subscribe($$self, trays, $$value => $$invalidate(2, $trays = $$value)); + let time = new Date(); + + onMount(() => { + const interval = setInterval( + () => { + $$invalidate(4, time = new Date()); + }, + 1000 + ); + + return () => { + clearInterval(interval); + }; + }); + + function handleKeydown(e) { + // Backtick toggle + if (e.keyCode == 192) { + menuVisible.update(current => { + return !current; + }); + } + } + + $$self.$$.update = () => { + if ($$self.$$.dirty & /*time*/ 16) { + $$invalidate(5, day = time.toLocaleString("default", { weekday: "short" })); + } + + if ($$self.$$.dirty & /*time*/ 16) { + $$invalidate(6, dom = time.getDate()); + } + + if ($$self.$$.dirty & /*time*/ 16) { + $$invalidate(7, mon = time.toLocaleString("default", { month: "short" })); + } + + if ($$self.$$.dirty & /*time*/ 16) { + $$invalidate(8, currentTime = time.toLocaleString("en-US", { + hour: "numeric", + minute: "numeric", + hour12: true + }).toLowerCase()); + } + + if ($$self.$$.dirty & /*day, dom, mon, currentTime*/ 480) { + $$invalidate(0, dateTimeString = `${day} ${dom} ${mon} ${currentTime}`); + } + }; + + return [ + dateTimeString, + $menuVisible, + $trays, + handleKeydown, + time, + day, + dom, + mon, + currentTime + ]; + } + + class Menubar extends SvelteComponent { + constructor(options) { + super(); + if (!document.getElementById("svelte-1i0zb4n-style")) add_css$3(); + init(this, options, instance$3, create_fragment$3, safe_not_equal, {}); + } + } + + /* + _ __ _ __ + | | / /___ _(_) /____ + | | /| / / __ `/ / / ___/ + | |/ |/ / /_/ / / (__ ) + |__/|__/\__,_/_/_/____/ + The electron alternative for Go + (c) Lea Anthony 2019-present + */ + + let websocket = null; + let callback = null; + let connectTimer; + + function StartWebsocket(userCallback) { + + callback = userCallback; + + window.onbeforeunload = function() { + if( websocket ) { + websocket.onclose = function () { }; + websocket.close(); + websocket = null; + } + }; + + // ...and attempt to connect + connect(); + + } + + function setupIPCBridge() { + window.wailsInvoke = (message) => { + websocket.send(message); + }; + } + + // Handles incoming websocket connections + function handleConnect() { + log('Connected to backend'); + setupIPCBridge(); + hideOverlay(); + clearInterval(connectTimer); + websocket.onclose = handleDisconnect; + websocket.onmessage = handleMessage; + } + + // Handles websocket disconnects + function handleDisconnect() { + log('Disconnected from backend'); + websocket = null; + showOverlay(); + connect(); + } + + // Try to connect to the backend every 1s (default value). + function connect() { + connectTimer = setInterval(function () { + if (websocket == null) { + websocket = new WebSocket('ws://' + window.location.hostname + ':34115/bridge'); + websocket.onopen = handleConnect; + websocket.onerror = function (e) { + e.stopImmediatePropagation(); + e.stopPropagation(); + e.preventDefault(); + websocket = null; + return false; + }; + } + }, 1000); + } + + // Adds a script to the Dom. + // Removes it if second parameter is true. + function addScript(script, remove) { + const s = document.createElement('script'); + s.setAttribute('type', 'text/javascript'); + s.textContent = script; + document.head.appendChild(s); + + // Remove internal messages from the DOM + if (remove) { + s.parentNode.removeChild(s); + } + } + + function handleMessage(message) { + // As a bridge we ignore js and css injections + switch (message.data[0]) { + // Wails library - inject! + case 'b': + message = message.data.slice(1); + addScript(message); + log('Loaded Wails Runtime'); + + // We need to now send a message to the backend telling it + // we have loaded (System Start) + window.wailsInvoke('SS'); + + // Now wails runtime is loaded, wails for the ready event + // and callback to the main app + // window.wails.Events.On('wails:loaded', function () { + if (callback) { + log('Notifying application'); + callback(window.wails); + } + // }); + break; + // Notifications + case 'n': + window.wails._.Notify(message.data.slice(1)); + break; + // // Binding + // case 'b': + // const binding = message.data.slice(1); + // //log("Binding: " + binding) + // window.wails._.NewBinding(binding); + // break; + // // Call back + case 'c': + const callbackData = message.data.slice(1); + window.wails._.Callback(callbackData); + break; + // Tray + case 'T': + const trayMessage = message.data.slice(1); + switch (trayMessage[0]) { + case 'S': + // Set tray + const trayJSON = trayMessage.slice(1); + let tray = JSON.parse(trayJSON); + setTray(tray); + break; + case 'U': + // Update label + const updateTrayLabelJSON = trayMessage.slice(1); + let trayLabelData = JSON.parse(updateTrayLabelJSON); + updateTrayLabel(trayLabelData); + break; + case 'D': + // Delete Tray Menu + const id = trayMessage.slice(1); + deleteTrayMenu(id); + break; + default: + log('Unknown tray message: ' + message.data); + } + break; + + default: + log('Unknown message: ' + message.data); + } + } + + /* + _ __ _ __ + | | / /___ _(_) /____ + | | /| / / __ `/ / / ___/ + | |/ |/ / /_/ / / (__ ) + |__/|__/\__,_/_/_/____/ + The electron alternative for Go + (c) Lea Anthony 2019-present + */ + + function setupMenuBar() { + new Menubar({ + target: document.body, + }); + } + + // Sets up the overlay + function setupOverlay() { + new Overlay({ + target: document.body, + anchor: document.querySelector('#wails-bridge'), + }); + } + + function InitBridge(callback) { + + setupMenuBar(); + + // Setup the overlay + setupOverlay(); + + // Start by showing the overlay... + showOverlay(); + + // ...and attempt to connect + StartWebsocket(callback); + } + + exports.InitBridge = InitBridge; + + Object.defineProperty(exports, '__esModule', { value: true }); + +}))); diff --git a/v2/internal/runtime/js/runtime/events.js b/v2/internal/runtime/js/runtime/events.js new file mode 100644 index 000000000..4f1f10600 --- /dev/null +++ b/v2/internal/runtime/js/runtime/events.js @@ -0,0 +1,76 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The electron alternative for Go +(c) Lea Anthony 2019-present +*/ + +/* jshint esversion: 6 */ + + +/** + * Registers an event listener that will be invoked `maxCallbacks` times before being destroyed + * + * @export + * @param {string} eventName + * @param {function} callback + * @param {number} maxCallbacks + */ +function OnMultiple(eventName, callback, maxCallbacks) { + window.wails.Events.OnMultiple(eventName, callback, maxCallbacks); +} + +/** + * Registers an event listener that will be invoked every time the event is emitted + * + * @export + * @param {string} eventName + * @param {function} callback + */ +function On(eventName, callback) { + OnMultiple(eventName, callback); +} + +/** + * Registers an event listener that will be invoked once then destroyed + * + * @export + * @param {string} eventName + * @param {function} callback + */ +function Once(eventName, callback) { + OnMultiple(eventName, callback, 1); +} + + +/** + * Emit an event with the given name and data + * + * @export + * @param {string} eventName + */ +function Emit(eventName) { + var args = [eventName].slice.call(arguments); + return window.wails.Events.Emit.apply(null, args); +} + +/** + * Registers listeners for when the system theme changes + * + * @export + * @param {function} callback + */ +function OnThemeChange(callback) { + On('wails:system:themechange', callback); +} + +module.exports = { + OnMultiple: OnMultiple, + On: On, + Once: Once, + Emit: Emit, + OnThemeChange: OnThemeChange, +}; \ No newline at end of file diff --git a/v2/internal/runtime/js/runtime/init.js b/v2/internal/runtime/js/runtime/init.js new file mode 100644 index 000000000..742ee1dc8 --- /dev/null +++ b/v2/internal/runtime/js/runtime/init.js @@ -0,0 +1,33 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The electron alternative for Go +(c) Lea Anthony 2019-present +*/ +/* jshint esversion: 6 */ + +const bridge = require('./bridge'); + +/** + * ready will execute the callback when Wails has loaded + * and initialised. + * + * @param {function} callback + */ +function ready(callback) { + + // If window.wails exists, we are ready + if( window.wails ) { + return callback(); + } + + // If not we need to setup the bridge + bridge.InitBridge(callback); +} + +module.exports = { + ready: ready, +}; \ No newline at end of file diff --git a/v2/internal/runtime/js/runtime/log.js b/v2/internal/runtime/js/runtime/log.js new file mode 100644 index 000000000..9133e2a7a --- /dev/null +++ b/v2/internal/runtime/js/runtime/log.js @@ -0,0 +1,113 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The electron alternative for Go +(c) Lea Anthony 2019-present +*/ + +/* jshint esversion: 6 */ + + +/** + * Log the given message with the backend + * + * @export + * @param {string} message + */ +function Print(message) { + window.wails.Log.Print(message); +} + +/** + * Log the given trace message with the backend + * + * @export + * @param {string} message + */ +function Trace(message) { + window.wails.Log.Trace(message); +} + +/** + * Log the given debug message with the backend + * + * @export + * @param {string} message + */ +function Debug(message) { + window.wails.Log.Debug(message); +} + +/** + * Log the given info message with the backend + * + * @export + * @param {string} message + */ +function Info(message) { + window.wails.Log.Info(message); +} + +/** + * Log the given warning message with the backend + * + * @export + * @param {string} message + */ +function Warning(message) { + window.wails.Log.Warning(message); +} + +/** + * Log the given error message with the backend + * + * @export + * @param {string} message + */ +function Error(message) { + window.wails.Log.Error(message); +} + +/** + * Log the given fatal message with the backend + * + * @param {string} message + */ +function Fatal(message) { + window.wails.Log.Fatal(message); +} + + +/** + * Sets the Log level to the given log level + * + * @param {number} loglevel + */ +function SetLogLevel(loglevel) { + window.wails.Log.SetLogLevel(loglevel); +} + +// Log levels +const Level = { + TRACE: 1, + DEBUG: 2, + INFO: 3, + WARNING: 4, + ERROR: 5, +}; + + +module.exports = { + Print: Print, + Trace: Trace, + Debug: Debug, + Info: Info, + Warning: Warning, + Error: Error, + Fatal: Fatal, + SetLogLevel: SetLogLevel, + Level: Level, +}; diff --git a/v2/internal/runtime/js/runtime/main.js b/v2/internal/runtime/js/runtime/main.js new file mode 100644 index 000000000..25380731f --- /dev/null +++ b/v2/internal/runtime/js/runtime/main.js @@ -0,0 +1,20 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The electron alternative for Go +(c) Lea Anthony 2019-present +*/ +/* jshint esversion: 6 */ + +const Log = require('./log'); +const Events = require('./events'); +const Init = require('./init'); + +module.exports = { + Events: Events, + ready: Init.ready, + Log: Log, +}; \ No newline at end of file diff --git a/v2/internal/runtime/js/runtime/package-lock.json b/v2/internal/runtime/js/runtime/package-lock.json new file mode 100644 index 000000000..ee7ac70e4 --- /dev/null +++ b/v2/internal/runtime/js/runtime/package-lock.json @@ -0,0 +1,517 @@ +{ + "name": "@wails/runtime", + "version": "1.3.15", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "dts-dom": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/dts-dom/-/dts-dom-3.6.0.tgz", + "integrity": "sha512-on5jxTgt+A6r0Zyyz6ZRHXaAO7J1VPnOd6+AmvI1vH440AlAZZNc5rUHzgPuTjGlrVr1rOWQYNl7ZJK6rDohbw==", + "dev": true + }, + "dts-gen": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/dts-gen/-/dts-gen-0.5.8.tgz", + "integrity": "sha512-kIAV6dlHaF7r5J+tIuOC1BJls2P72YM0cyWQUR88zcJEpX2ccRZe+HmXLfkkvfPwjvSO3FEqUiyC8On/grx5qw==", + "dev": true, + "requires": { + "dts-dom": "^3.6.0", + "parse-git-config": "^1.1.1", + "typescript": "^3.5.1", + "yargs": "^4.8.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "fs-exists-sync": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz", + "integrity": "sha1-mC1ok6+RjnLQjeyehnP/K1qNat0=", + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "git-config-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/git-config-path/-/git-config-path-1.0.1.tgz", + "integrity": "sha1-bTP37WPbDQ4RgTFQO6s6ykfVRmQ=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "fs-exists-sync": "^0.1.0", + "homedir-polyfill": "^1.0.0" + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "requires": { + "parse-passwd": "^1.0.0" + } + }, + "hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "dev": true + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-core-module": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", + "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "requires": { + "invert-kv": "^1.0.0" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + } + }, + "lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "dev": true, + "requires": { + "lcid": "^1.0.0" + } + }, + "parse-git-config": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/parse-git-config/-/parse-git-config-1.1.1.tgz", + "integrity": "sha1-06mYQxcTL1c5hxK7pDjhKVkN34w=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "fs-exists-sync": "^0.1.0", + "git-config-path": "^1.0.1", + "ini": "^1.3.4" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, + "resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "dev": true, + "requires": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", + "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", + "dev": true + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + }, + "typescript": { + "version": "3.9.7", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz", + "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", + "dev": true + }, + "window-size": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", + "integrity": "sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU=", + "dev": true + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + } + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "yargs": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", + "integrity": "sha1-wMQpJMpKqmsObaFznfshZDn53cA=", + "dev": true, + "requires": { + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "lodash.assign": "^4.0.3", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.1", + "which-module": "^1.0.0", + "window-size": "^0.2.0", + "y18n": "^3.2.1", + "yargs-parser": "^2.4.1" + } + }, + "yargs-parser": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", + "integrity": "sha1-hVaN488VD/SfpRgl8DqMiA3cxcQ=", + "dev": true, + "requires": { + "camelcase": "^3.0.0", + "lodash.assign": "^4.0.6" + } + } + } +} diff --git a/v2/internal/runtime/js/runtime/package.json b/v2/internal/runtime/js/runtime/package.json new file mode 100644 index 000000000..548838a0f --- /dev/null +++ b/v2/internal/runtime/js/runtime/package.json @@ -0,0 +1,28 @@ +{ + "name": "@wails/runtime", + "version": "1.3.20", + "description": "Wails V2 Javascript runtime library", + "main": "main.js", + "types": "runtime.d.ts", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/wailsapp/wails.git" + }, + "keywords": [ + "Wails", + "Javascript", + "Go" + ], + "author": "Lea Anthony ", + "license": "MIT", + "bugs": { + "url": "https://github.com/wailsapp/wails/issues" + }, + "homepage": "https://github.com/wailsapp/wails#readme", + "devDependencies": { + "dts-gen": "^0.5.8" + } +} diff --git a/v2/internal/runtime/js/runtime/runtime.d.ts b/v2/internal/runtime/js/runtime/runtime.d.ts new file mode 100644 index 000000000..2b112d763 --- /dev/null +++ b/v2/internal/runtime/js/runtime/runtime.d.ts @@ -0,0 +1,26 @@ +export = wailsapp__runtime; + +interface Level { + TRACE: 1, + DEBUG: 2, + INFO: 3, + WARNING: 4, + ERROR: 5, +} + +declare const wailsapp__runtime: { + EventsEmit(eventName: string, data?: any): void; + EventsOn(eventName: string, callback: (data?: any) => void): void; + EventsOnMultiple(eventName: string, callback: (data?: any) => void, maxCallbacks: number): void; + EventsOnce(eventName: string, callback: (data?: any) => void): void; + // Init(callback: () => void): void; + LogTrace(message: string): void; + LogDebug(message: string): void; + LogError(message: string): void; + LogFatal(message: string): void; + LogInfo(message: string): void; + LogWarning(message: string): void; + LogLevel: Level; +}; + + diff --git a/v2/internal/runtime/js/runtime/src/Menu.svelte b/v2/internal/runtime/js/runtime/src/Menu.svelte new file mode 100644 index 000000000..bed890d61 --- /dev/null +++ b/v2/internal/runtime/js/runtime/src/Menu.svelte @@ -0,0 +1,56 @@ +s + + +{#if !hidden} + +{/if} + + \ No newline at end of file diff --git a/v2/internal/runtime/js/runtime/src/Menubar.svelte b/v2/internal/runtime/js/runtime/src/Menubar.svelte new file mode 100644 index 000000000..eeb87b848 --- /dev/null +++ b/v2/internal/runtime/js/runtime/src/Menubar.svelte @@ -0,0 +1,58 @@ + + +{#if $menuVisible } +
+ + + + + + +
+{/if} + + + + \ No newline at end of file diff --git a/v2/internal/runtime/js/runtime/src/Overlay.svelte b/v2/internal/runtime/js/runtime/src/Overlay.svelte new file mode 100644 index 000000000..0600e36b9 --- /dev/null +++ b/v2/internal/runtime/js/runtime/src/Overlay.svelte @@ -0,0 +1,55 @@ + + +{#if $overlayVisible } +
+
+
+
+
+{/if} + + \ No newline at end of file diff --git a/v2/internal/runtime/js/runtime/src/TrayMenu.svelte b/v2/internal/runtime/js/runtime/src/TrayMenu.svelte new file mode 100644 index 000000000..f4c9503c7 --- /dev/null +++ b/v2/internal/runtime/js/runtime/src/TrayMenu.svelte @@ -0,0 +1,65 @@ + + + + + + + {tray.Label} + {#if tray.ProcessedMenu } + + {/if} + + + \ No newline at end of file diff --git a/v2/internal/runtime/js/runtime/src/log.js b/v2/internal/runtime/js/runtime/src/log.js new file mode 100644 index 000000000..256637e8d --- /dev/null +++ b/v2/internal/runtime/js/runtime/src/log.js @@ -0,0 +1,9 @@ + +export function log(message) { + // eslint-disable-next-line + console.log( + '%c wails bridge %c ' + message + ' ', + 'background: #aa0000; color: #fff; border-radius: 3px 0px 0px 3px; padding: 1px; font-size: 0.7rem', + 'background: #009900; color: #fff; border-radius: 0px 3px 3px 0px; padding: 1px; font-size: 0.7rem' + ); +} \ No newline at end of file diff --git a/v2/internal/runtime/js/runtime/src/main.js b/v2/internal/runtime/js/runtime/src/main.js new file mode 100644 index 000000000..bf421990e --- /dev/null +++ b/v2/internal/runtime/js/runtime/src/main.js @@ -0,0 +1,45 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The electron alternative for Go +(c) Lea Anthony 2019-present +*/ +/* jshint esversion: 6 */ + +import Overlay from './Overlay.svelte'; +import MenuBar from './Menubar.svelte'; +import {showOverlay} from "./store"; +import {StartWebsocket} from "./websocket"; + +let components = {}; + +function setupMenuBar() { + components.menubar = new MenuBar({ + target: document.body, + }); +} + +// Sets up the overlay +function setupOverlay() { + components.overlay = new Overlay({ + target: document.body, + anchor: document.querySelector('#wails-bridge'), + }); +} + +export function InitBridge(callback) { + + setupMenuBar() + + // Setup the overlay + setupOverlay(); + + // Start by showing the overlay... + showOverlay(); + + // ...and attempt to connect + StartWebsocket(callback); +} diff --git a/v2/internal/runtime/js/runtime/src/package-lock.json b/v2/internal/runtime/js/runtime/src/package-lock.json new file mode 100644 index 000000000..5397423c9 --- /dev/null +++ b/v2/internal/runtime/js/runtime/src/package-lock.json @@ -0,0 +1,525 @@ +{ + "name": "bridge", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", + "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.12.13" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", + "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.12.13.tgz", + "integrity": "sha512-kocDQvIbgMKlWxXe9fof3TQ+gkIPOUSEYhJjqUjvKMez3krV7vbzYCDq39Oj11UAVK7JqPVGQPlgE85dPNlQww==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.12.11", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@rollup/plugin-commonjs": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-17.1.0.tgz", + "integrity": "sha512-PoMdXCw0ZyvjpCMT5aV4nkL0QywxP29sODQsSGeDpr/oI49Qq9tRtAsb/LbYbDzFlOydVEqHmmZWFtXJEAX9ew==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.1.0", + "commondir": "^1.0.1", + "estree-walker": "^2.0.1", + "glob": "^7.1.6", + "is-reference": "^1.2.1", + "magic-string": "^0.25.7", + "resolve": "^1.17.0" + }, + "dependencies": { + "estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true + } + } + }, + "@rollup/plugin-node-resolve": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.1.1.tgz", + "integrity": "sha512-zlBXR4eRS+2m79TsUZWhsd0slrHUYdRx4JF+aVQm+MI0wsKdlpC2vlDVjmlGvtZY1vsefOT9w3JxvmWSBei+Lg==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "builtin-modules": "^3.1.0", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.19.0" + } + }, + "@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, + "requires": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + } + }, + "@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + }, + "@types/node": { + "version": "14.14.25", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.25.tgz", + "integrity": "sha512-EPpXLOVqDvisVxtlbvzfyqSsFeQxltFbluZNRndIb8tr9KiBnYNLzrc1N3pyKUCww2RNrfHDViqDWWE1LCJQtQ==", + "dev": true + }, + "@types/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "builtin-modules": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz", + "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-core-module": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", + "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", + "dev": true + }, + "is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "dev": true, + "requires": { + "@types/estree": "*" + } + }, + "jest-worker": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "magic-string": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", + "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "dev": true, + "requires": { + "sourcemap-codec": "^1.4.4" + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "require-relative": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz", + "integrity": "sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4=", + "dev": true + }, + "resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "dev": true, + "requires": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + } + }, + "rollup": { + "version": "2.38.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.38.5.tgz", + "integrity": "sha512-VoWt8DysFGDVRGWuHTqZzT02J0ASgjVq/hPs9QcBOGMd7B+jfTr/iqMVEyOi901rE3xq+Deq66GzIT1yt7sGwQ==", + "dev": true, + "requires": { + "fsevents": "~2.3.1" + } + }, + "rollup-plugin-svelte": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-svelte/-/rollup-plugin-svelte-7.1.0.tgz", + "integrity": "sha512-vopCUq3G+25sKjwF5VilIbiY6KCuMNHP1PFvx2Vr3REBNMDllKHFZN2B9jwwC+MqNc3UPKkjXnceLPEjTjXGXg==", + "dev": true, + "requires": { + "require-relative": "^0.8.7", + "rollup-pluginutils": "^2.8.2" + } + }, + "rollup-plugin-terser": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", + "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "jest-worker": "^26.2.1", + "serialize-javascript": "^4.0.0", + "terser": "^5.0.0" + } + }, + "rollup-pluginutils": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", + "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", + "dev": true, + "requires": { + "estree-walker": "^0.6.1" + }, + "dependencies": { + "estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "dev": true + } + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "svelte": { + "version": "3.32.2", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.32.2.tgz", + "integrity": "sha512-Zxh1MQQl/+vnToKbU1Per+PoMN8Jb2MeKJcGxiOsCGR677hXw7jkMfbnNXq33+dxIzV/HfA4xtoSPJrqeB0VUg==", + "dev": true + }, + "terser": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.5.1.tgz", + "integrity": "sha512-6VGWZNVP2KTUcltUQJ25TtNjx/XgdDsBDKGt8nN0MpydU36LmbPPcMBd2kmtZNNGVVDLg44k7GKeHHj+4zPIBQ==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.7.2", + "source-map-support": "~0.5.19" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + } + } +} diff --git a/v2/internal/runtime/js/runtime/src/package.json b/v2/internal/runtime/js/runtime/src/package.json new file mode 100644 index 000000000..1f0d6e224 --- /dev/null +++ b/v2/internal/runtime/js/runtime/src/package.json @@ -0,0 +1,21 @@ +{ + "name": "bridge", + "version": "1.0.0", + "description": "Wails bridge", + "main": "main.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build": "npx rollup -c", + "watch": "npx rollup -c -w" + }, + "author": "", + "license": "ISC", + "devDependencies": { + "@rollup/plugin-commonjs": "^17.1.0", + "@rollup/plugin-node-resolve": "^11.1.1", + "rollup": "^2.38.5", + "rollup-plugin-svelte": "^7.1.0", + "rollup-plugin-terser": "^7.0.2", + "svelte": "^3.32.2" + } +} diff --git a/v2/internal/runtime/js/runtime/src/rollup.config.js b/v2/internal/runtime/js/runtime/src/rollup.config.js new file mode 100644 index 000000000..cbca60af8 --- /dev/null +++ b/v2/internal/runtime/js/runtime/src/rollup.config.js @@ -0,0 +1,37 @@ +import resolve from '@rollup/plugin-node-resolve'; +// import commonjs from '@rollup/plugin-commonjs'; +import svelte from 'rollup-plugin-svelte'; +import { terser } from "rollup-plugin-terser"; + +export default [ + // browser-friendly UMD build + { + input: 'main.js', + output: { + name: 'bridge', + file: '../bridge.js', + format: 'umd', + exports: "named" + }, + plugins: [ + svelte({ + // Optionally, preprocess components with svelte.preprocess: + // https://svelte.dev/docs#svelte_preprocess + // preprocess: { + // style: ({content}) => { + // return transformStyles(content); + // } + // }, + + // Emit CSS as "files" for other plugins to process. default is true + emitCss: false, + + }), + resolve({browser: true}), // so Rollup can find `ms` + // commonjs() // so Rollup can convert `ms` to an ES module + // terser(), + ] + }, + + +]; \ No newline at end of file diff --git a/v2/internal/runtime/js/runtime/src/store.js b/v2/internal/runtime/js/runtime/src/store.js new file mode 100644 index 000000000..a0b4571b5 --- /dev/null +++ b/v2/internal/runtime/js/runtime/src/store.js @@ -0,0 +1,64 @@ + +import { writable } from 'svelte/store'; +import {log} from "./log"; + +/** Overlay */ +export const overlayVisible = writable(false); + +export function showOverlay() { + overlayVisible.set(true); +} +export function hideOverlay() { + overlayVisible.set(false); +} + +/** Menubar **/ +export const menuVisible = writable(false); + +export function showMenuBar() { + menuVisible.set(true); +} +export function hideMenuBar() { + menuVisible.set(false); +} + +/** Trays **/ + +export const trays = writable([]); +export function setTray(tray) { + trays.update((current) => { + // Remove existing if it exists, else add + const index = current.findIndex(item => item.ID === tray.ID); + if ( index === -1 ) { + current.push(tray); + } else { + current[index] = tray; + } + return current; + }) +} +export function updateTrayLabel(tray) { + trays.update((current) => { + // Remove existing if it exists, else add + const index = current.findIndex(item => item.ID === tray.ID); + if ( index === -1 ) { + return log("ERROR: Attempted to update tray index ", tray.ID, "but it doesn't exist") + } + current[index].Label = tray.Label; + return current; + }) +} + +export function deleteTrayMenu(id) { + trays.update((current) => { + // Remove existing if it exists, else add + const index = current.findIndex(item => item.ID === id); + if ( index === -1 ) { + return log("ERROR: Attempted to delete tray index ", id, "but it doesn't exist") + } + current.splice(index, 1); + return current; + }) +} + +export let selectedMenu = writable(null); \ No newline at end of file diff --git a/v2/internal/runtime/js/runtime/src/websocket.js b/v2/internal/runtime/js/runtime/src/websocket.js new file mode 100644 index 000000000..a3e3aeb70 --- /dev/null +++ b/v2/internal/runtime/js/runtime/src/websocket.js @@ -0,0 +1,158 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The electron alternative for Go +(c) Lea Anthony 2019-present +*/ +/* jshint esversion: 6 */ + + +import {deleteTrayMenu, hideOverlay, setTray, showOverlay, updateTrayLabel} from './store'; +import {log} from './log'; + +let websocket = null; +let callback = null; +let connectTimer; + +export function StartWebsocket(userCallback) { + + callback = userCallback; + + window.onbeforeunload = function() { + if( websocket ) { + websocket.onclose = function () { }; + websocket.close(); + websocket = null; + } + }; + + // ...and attempt to connect + connect(); + +} + +function setupIPCBridge() { + window.wailsInvoke = (message) => { + websocket.send(message); + }; +} + +// Handles incoming websocket connections +function handleConnect() { + log('Connected to backend'); + setupIPCBridge(); + hideOverlay(); + clearInterval(connectTimer); + websocket.onclose = handleDisconnect; + websocket.onmessage = handleMessage; +} + +// Handles websocket disconnects +function handleDisconnect() { + log('Disconnected from backend'); + websocket = null; + showOverlay(); + connect(); +} + +// Try to connect to the backend every 1s (default value). +function connect() { + connectTimer = setInterval(function () { + if (websocket == null) { + websocket = new WebSocket('ws://' + window.location.hostname + ':34115/bridge'); + websocket.onopen = handleConnect; + websocket.onerror = function (e) { + e.stopImmediatePropagation(); + e.stopPropagation(); + e.preventDefault(); + websocket = null; + return false; + }; + } + }, 1000); +} + +// Adds a script to the Dom. +// Removes it if second parameter is true. +function addScript(script, remove) { + const s = document.createElement('script'); + s.setAttribute('type', 'text/javascript'); + s.textContent = script; + document.head.appendChild(s); + + // Remove internal messages from the DOM + if (remove) { + s.parentNode.removeChild(s); + } +} + +function handleMessage(message) { + // As a bridge we ignore js and css injections + switch (message.data[0]) { + // Wails library - inject! + case 'b': + message = message.data.slice(1); + addScript(message); + log('Loaded Wails Runtime'); + + // We need to now send a message to the backend telling it + // we have loaded (System Start) + window.wailsInvoke('SS'); + + // Now wails runtime is loaded, wails for the ready event + // and callback to the main app + // window.wails.Events.On('wails:loaded', function () { + if (callback) { + log('Notifying application'); + callback(window.wails); + } + // }); + break; + // Notifications + case 'n': + window.wails._.Notify(message.data.slice(1)); + break; + // // Binding + // case 'b': + // const binding = message.data.slice(1); + // //log("Binding: " + binding) + // window.wails._.NewBinding(binding); + // break; + // // Call back + case 'c': + const callbackData = message.data.slice(1); + window.wails._.Callback(callbackData); + break; + // Tray + case 'T': + const trayMessage = message.data.slice(1); + switch (trayMessage[0]) { + case 'S': + // Set tray + const trayJSON = trayMessage.slice(1); + let tray = JSON.parse(trayJSON); + setTray(tray); + break; + case 'U': + // Update label + const updateTrayLabelJSON = trayMessage.slice(1); + let trayLabelData = JSON.parse(updateTrayLabelJSON); + updateTrayLabel(trayLabelData); + break; + case 'D': + // Delete Tray Menu + const id = trayMessage.slice(1); + deleteTrayMenu(id); + break; + default: + log('Unknown tray message: ' + message.data); + } + break; + + default: + log('Unknown message: ' + message.data); + } +} diff --git a/v2/internal/runtime/js/server/darwin.js b/v2/internal/runtime/js/server/darwin.js new file mode 100644 index 000000000..c2af8faa7 --- /dev/null +++ b/v2/internal/runtime/js/server/darwin.js @@ -0,0 +1,17 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The electron alternative for Go +(c) Lea Anthony 2019-present +*/ + +/* jshint esversion: 6 */ + +/** + * Initialises platform specific code + */ + +export function Init() { } diff --git a/v2/internal/runtime/js/server/ipc.js b/v2/internal/runtime/js/server/ipc.js new file mode 100644 index 000000000..1332dd2c1 --- /dev/null +++ b/v2/internal/runtime/js/server/ipc.js @@ -0,0 +1,52 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The electron alternative for Go +(c) Lea Anthony 2019-present +*/ +/* jshint esversion: 6 */ + +// IPC Listeners +var listeners = []; + +/** + * Adds a listener to IPC messages + * @param {function} callback + */ +export function AddIPCListener(callback) { + listeners.push(callback); +} + +/** + * Invoke sends the given message to the backend + * + * @param {string} message + */ +function Invoke(message) { + if (window.wailsbridge && window.wailsbridge.websocket) { + window.wailsbridge.websocket.send(JSON.stringify(message)); + } else { + console.log('Invoke called with: ' + message + ' but no runtime is available'); + } + + // Also send to listeners + if (listeners.length > 0) { + for (var i = 0; i < listeners.length; i++) { + listeners[i](message); + } + } +} + +/** + * Sends a message to the backend based on the given type, payload and callbackID + * + * @export + * @param {string} message + */ + +export function SendMessage(message) { + Invoke(message); +} diff --git a/v2/internal/runtime/js/server/linux.js b/v2/internal/runtime/js/server/linux.js new file mode 100644 index 000000000..718c01d8f --- /dev/null +++ b/v2/internal/runtime/js/server/linux.js @@ -0,0 +1,17 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The electron alternative for Go +(c) Lea Anthony 2019-present +*/ + +/* jshint esversion: 6 */ + +/** + * Initialises platform specific code + */ + +export function Init() { } \ No newline at end of file diff --git a/v2/internal/runtime/js/webpack.config.js b/v2/internal/runtime/js/webpack.config.js new file mode 100644 index 000000000..62cb81a20 --- /dev/null +++ b/v2/internal/runtime/js/webpack.config.js @@ -0,0 +1,4 @@ +/* eslint-disable */ +module.exports = (env) => { + return require(`./webpack.${env}.js`); +}; \ No newline at end of file diff --git a/v2/internal/runtime/js/webpack.desktop.js b/v2/internal/runtime/js/webpack.desktop.js new file mode 100644 index 000000000..8ad1d61de --- /dev/null +++ b/v2/internal/runtime/js/webpack.desktop.js @@ -0,0 +1,51 @@ +/* eslint-disable */ + +const path = require('path'); + +const platform = process.env.WAILSPLATFORM; +if (!platform) { + console.error("FATAL: Environment variable WAILSPLATFORM not set!"); + process.exit(1); +} + +module.exports = { + entry: './core/desktop', + mode: 'production', + output: { + path: path.resolve(__dirname, '..', 'assets'), + filename: 'desktop_'+platform+'.js', + library: 'Wails' + }, + resolve: { + alias: { + ipc$: path.resolve(__dirname, 'desktop/ipc.js'), + platform$: path.resolve(__dirname, `desktop/${platform}.js`) + } + }, + module: { + rules: [ + { + test: /\.m?js$/, + exclude: /(node_modules|bower_components)/, + use: { + loader: 'babel-loader', + options: { + plugins: ['@babel/plugin-transform-object-assign'], + presets: [ + [ + '@babel/preset-env', + { + 'useBuiltIns': 'entry', + 'corejs': { + 'version': 3, + 'proposals': true + } + } + ] + ] + } + } + } + ] + } +}; diff --git a/v2/internal/runtime/js/webpack.server.js b/v2/internal/runtime/js/webpack.server.js new file mode 100644 index 000000000..58ed73b67 --- /dev/null +++ b/v2/internal/runtime/js/webpack.server.js @@ -0,0 +1,54 @@ +/* eslint-disable */ + +const path = require('path'); + +const platform = process.env.WAILSPLATFORM; +if (!platform) { + console.error("FATAL: Environment variable WAILSPLATFORM not set!"); + process.exit(1); +} + +module.exports = { + entry: './core/server', + mode: 'production', + output: { + path: path.resolve(__dirname, '..', 'assets'), + filename: 'server.js', + library: 'Wails' + }, + resolve: { + alias: { + ipc$: path.resolve(__dirname, 'server/ipc.js'), + platform$: path.resolve(__dirname, `server/${platform}.js`) + } + }, + module: { + rules: [ + { + test: /\.m?js$/, + include: [ + path.resolve(__dirname, "server"), + ], + exclude: /(node_modules|bower_components)/, + use: { + loader: 'babel-loader', + options: { + plugins: ['@babel/plugin-transform-object-assign'], + presets: [ + [ + '@babel/preset-env', + { + 'useBuiltIns': 'entry', + 'corejs': { + 'version': 3, + 'proposals': true + } + } + ] + ] + } + } + } + ] + } +}; diff --git a/v2/internal/runtime/scripts/rebuild.go b/v2/internal/runtime/scripts/rebuild.go new file mode 100644 index 000000000..b16fe3880 --- /dev/null +++ b/v2/internal/runtime/scripts/rebuild.go @@ -0,0 +1,85 @@ +package main + +import ( + "bytes" + "fmt" + "io/ioutil" + "log" + "os" + "strings" + + "github.com/wailsapp/wails/v2/internal/fs" + "github.com/wailsapp/wails/v2/internal/shell" +) + +func main() { + + sourceDir := fs.RelativePath("../../../internal/runtime/js") + + platforms := []string{"darwin", "windows", "linux"} + + for _, platform := range platforms { + println("Building JS Runtime for " + platform) + envvars := []string{"WAILSPLATFORM=" + platform} + + // Split up the InstallCommand and execute it + stdout, stderr, err := shell.RunCommand(sourceDir, "npm", "install") + if err != nil { + for _, l := range strings.Split(stdout, "\n") { + fmt.Printf(" %s\n", l) + } + for _, l := range strings.Split(stderr, "\n") { + fmt.Printf(" %s\n", l) + } + } + + runtimeDir := fs.RelativePath("../js") + cmd := shell.CreateCommand(runtimeDir, "npm", "run", "build:desktop") + cmd.Env = append(os.Environ(), envvars...) + var stdo, stde bytes.Buffer + cmd.Stdout = &stdo + cmd.Stderr = &stde + err = cmd.Run() + if err != nil { + for _, l := range strings.Split(stdo.String(), "\n") { + fmt.Printf(" %s\n", l) + } + for _, l := range strings.Split(stde.String(), "\n") { + fmt.Printf(" %s\n", l) + } + log.Fatal(err) + } + + wailsJS := fs.RelativePath("../assets/desktop_" + platform + ".js") + runtimeData, err := ioutil.ReadFile(wailsJS) + if err != nil { + log.Fatal(err) + } + + // Copy this file to bridge directory for embedding + bridgeDir := fs.RelativePath("../../bridge/" + platform + ".js") + println("Copying", wailsJS, "to", bridgeDir) + err = fs.CopyFile(wailsJS, bridgeDir) + if err != nil { + log.Fatal(err) + } + + // Convert to C structure + runtimeC := ` +// runtime.c (c) 2019-Present Lea Anthony. +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file was auto-generated. DO NOT MODIFY. +const unsigned char runtime[]={` + for _, b := range runtimeData { + runtimeC += fmt.Sprintf("0x%x, ", b) + } + runtimeC += "0x00};" + + // Save file + outputFile := fs.RelativePath(fmt.Sprintf("../../ffenestri/runtime_%s.c", platform)) + + if err := ioutil.WriteFile(outputFile, []byte(runtimeC), 0600); err != nil { + log.Fatal(err) + } + } +} diff --git a/v2/internal/s/s.go b/v2/internal/s/s.go deleted file mode 100644 index adb304178..000000000 --- a/v2/internal/s/s.go +++ /dev/null @@ -1,312 +0,0 @@ -package s - -import ( - "crypto/md5" - "encoding/hex" - "fmt" - "io" - "os" - "path/filepath" - "strings" - - "github.com/bitfield/script" -) - -var ( - Output io.Writer = io.Discard - IndentSize int - originalOutput io.Writer - currentIndent int -) - -func checkError(err error) { - if err != nil { - println("\nERROR:", err.Error()) - os.Exit(1) - } -} - -func mute() { - originalOutput = Output - Output = io.Discard -} - -func unmute() { - Output = originalOutput -} - -func indent() { - currentIndent += IndentSize -} - -func unindent() { - currentIndent -= IndentSize -} - -func log(message string, args ...interface{}) { - indent := strings.Repeat(" ", currentIndent) - _, err := fmt.Fprintf(Output, indent+message+"\n", args...) - checkError(err) -} - -// RENAME a file or directory -func RENAME(source string, target string) { - log("RENAME %s -> %s", source, target) - err := os.Rename(source, target) - checkError(err) -} - -// MUSTDELETE a file. -func MUSTDELETE(filename string) { - log("DELETE %s", filename) - err := os.Remove(filepath.Join(CWD(), filename)) - checkError(err) -} - -// DELETE a file. -func DELETE(filename string) { - log("DELETE %s", filename) - _ = os.Remove(filepath.Join(CWD(), filename)) -} - -func CD(dir string) { - err := os.Chdir(dir) - checkError(err) - log("CD %s [%s]", dir, CWD()) -} - -func MKDIR(path string, mode ...os.FileMode) { - var perms os.FileMode - perms = 0o755 - if len(mode) == 1 { - perms = mode[0] - } - log("MKDIR %s (perms: %v)", path, perms) - err := os.MkdirAll(path, perms) - checkError(err) -} - -// ENDIR ensures that the path gets created if it doesn't exist -func ENDIR(path string, mode ...os.FileMode) { - var perms os.FileMode - perms = 0o755 - if len(mode) == 1 { - perms = mode[0] - } - _ = os.MkdirAll(path, perms) -} - -// COPYDIR recursively copies a directory tree, attempting to preserve permissions. -// Source directory must exist, destination directory must *not* exist. -// Symlinks are ignored and skipped. -// Credit: https://gist.github.com/r0l1/92462b38df26839a3ca324697c8cba04 -func COPYDIR(src string, dst string) { - log("COPYDIR %s -> %s", src, dst) - src = filepath.Clean(src) - dst = filepath.Clean(dst) - - si, err := os.Stat(src) - checkError(err) - if !si.IsDir() { - checkError(fmt.Errorf("source is not a directory")) - } - - _, err = os.Stat(dst) - if err != nil && !os.IsNotExist(err) { - checkError(err) - } - if err == nil { - checkError(fmt.Errorf("destination already exists")) - } - - indent() - MKDIR(dst) - - entries, err := os.ReadDir(src) - checkError(err) - - for _, entry := range entries { - srcPath := filepath.Join(src, entry.Name()) - dstPath := filepath.Join(dst, entry.Name()) - - if entry.IsDir() { - COPYDIR(srcPath, dstPath) - } else { - // Skip symlinks. - if entry.Type()&os.ModeSymlink != 0 { - continue - } - - COPY(srcPath, dstPath) - } - } - unindent() -} - -// COPY file from source to target -func COPY(source string, target string) { - log("COPY %s -> %s", source, target) - src, err := os.Open(source) - checkError(err) - defer closefile(src) - d, err := os.Create(target) - checkError(err) - defer closefile(d) - _, err = io.Copy(d, src) - checkError(err) -} - -func CWD() string { - result, err := os.Getwd() - checkError(err) - log("CWD [%s]", result) - return result -} - -func RMDIR(target string) { - log("RMDIR %s", target) - err := os.RemoveAll(target) - checkError(err) -} - -func RM(target string) { - log("RM %s", target) - err := os.Remove(target) - checkError(err) -} - -func ECHO(message string) { - println(message) -} - -func TOUCH(filepath string) { - log("TOUCH %s", filepath) - f, err := os.Create(filepath) - checkError(err) - closefile(f) -} - -func EXEC(command string) { - log("EXEC %s", command) - gen := script.Exec(command) - gen.Wait() - checkError(gen.Error()) -} - -// EXISTS - Returns true if the given path exists -func EXISTS(path string) bool { - _, err := os.Lstat(path) - log("EXISTS %s (%T)", path, err == nil) - return err == nil -} - -// ISDIR returns true if the given directory exists -func ISDIR(path string) bool { - fi, err := os.Lstat(path) - if err != nil { - return false - } - - return fi.Mode().IsDir() -} - -// ISDIREMPTY returns true if the given directory is empty -func ISDIREMPTY(dir string) bool { - // CREDIT: https://stackoverflow.com/a/30708914/8325411 - f, err := os.Open(dir) - checkError(err) - defer closefile(f) - - _, err = f.Readdirnames(1) // Or f.Readdir(1) - return err == io.EOF -} - -// ISFILE returns true if the given file exists -func ISFILE(path string) bool { - fi, err := os.Lstat(path) - if err != nil { - return false - } - - return fi.Mode().IsRegular() -} - -// SUBDIRS returns a list of subdirectories for the given directory -func SUBDIRS(rootDir string) []string { - var result []string - - // Iterate root dir - err := filepath.Walk(rootDir, func(path string, info os.FileInfo, err error) error { - checkError(err) - // If we have a directory, save it - if info.IsDir() { - result = append(result, path) - } - return nil - }) - checkError(err) - return result -} - -// SAVESTRING will create a file with the given string -func SAVESTRING(filename string, data string) { - log("SAVESTRING %s", filename) - mute() - SAVEBYTES(filename, []byte(data)) - unmute() -} - -// LOADSTRING returns the contents of the given filename as a string -func LOADSTRING(filename string) string { - log("LOADSTRING %s", filename) - mute() - data := LOADBYTES(filename) - unmute() - return string(data) -} - -// SAVEBYTES will create a file with the given string -func SAVEBYTES(filename string, data []byte) { - log("SAVEBYTES %s", filename) - err := os.WriteFile(filename, data, 0o755) - checkError(err) -} - -// LOADBYTES returns the contents of the given filename as a string -func LOADBYTES(filename string) []byte { - log("LOADBYTES %s", filename) - data, err := os.ReadFile(filename) - checkError(err) - return data -} - -func closefile(f *os.File) { - err := f.Close() - checkError(err) -} - -// MD5FILE returns the md5sum of the given file -func MD5FILE(filename string) string { - f, err := os.Open(filename) - checkError(err) - defer closefile(f) - - h := md5.New() - _, err = io.Copy(h, f) - checkError(err) - - return hex.EncodeToString(h.Sum(nil)) -} - -// Sub is the substitution type -type Sub map[string]string - -// REPLACEALL replaces all substitution keys with associated values in the given file -func REPLACEALL(filename string, substitutions Sub) { - log("REPLACEALL %s (%v)", filename, substitutions) - data := LOADSTRING(filename) - for old, newText := range substitutions { - data = strings.ReplaceAll(data, old, newText) - } - SAVESTRING(filename, data) -} diff --git a/v2/internal/servicebus/extract.go b/v2/internal/servicebus/extract.go new file mode 100644 index 000000000..bcd46186c --- /dev/null +++ b/v2/internal/servicebus/extract.go @@ -0,0 +1,17 @@ +package servicebus + +import ( + "context" + "log" + "runtime" +) + +func ExtractBus(ctx context.Context) *ServiceBus { + bus := ctx.Value("bus") + if bus == nil { + pc, _, _, _ := runtime.Caller(1) + funcName := runtime.FuncForPC(pc).Name() + log.Fatalf("cannot call '%s': Application not initialised", funcName) + } + return bus.(*ServiceBus) +} diff --git a/v2/internal/servicebus/message.go b/v2/internal/servicebus/message.go new file mode 100644 index 000000000..aea95f5e3 --- /dev/null +++ b/v2/internal/servicebus/message.go @@ -0,0 +1,43 @@ +package servicebus + +// Message is a service bus message that contains a +// topic and data +type Message struct { + topic string + data interface{} + target string +} + +// NewMessage creates a new message with the given +// topic and data +func NewMessage(topic string, data interface{}) *Message { + return &Message{ + topic: topic, + data: data, + } +} + +// NewMessageForTarget creates a new message with the given +// topic and data +func NewMessageForTarget(topic string, data interface{}, target string) *Message { + return &Message{ + topic: topic, + data: data, + target: target, + } +} + +// Topic returns the message topic +func (m *Message) Topic() string { + return m.topic +} + +// Data returns the message data +func (m *Message) Data() interface{} { + return m.data +} + +// Target returns the message Target +func (m *Message) Target() string { + return m.target +} diff --git a/v2/internal/servicebus/servicebus.go b/v2/internal/servicebus/servicebus.go new file mode 100644 index 000000000..86faa9aed --- /dev/null +++ b/v2/internal/servicebus/servicebus.go @@ -0,0 +1,181 @@ +package servicebus + +import ( + "context" + "fmt" + "strings" + "sync" + + "github.com/wailsapp/wails/v2/internal/logger" +) + +// ServiceBus is a messaging bus for Wails applications +type ServiceBus struct { + listeners map[string][]chan *Message + messageQueue chan *Message + lock sync.RWMutex + closed bool + debug bool + logger logger.CustomLogger + ctx context.Context + cancel context.CancelFunc +} + +// New creates a new ServiceBus +// The internal message queue is set to 100 messages +// Listener queues are set to 10 +func New(logger *logger.Logger) *ServiceBus { + + ctx, cancel := context.WithCancel(context.Background()) + return &ServiceBus{ + listeners: make(map[string][]chan *Message), + messageQueue: make(chan *Message, 100), + logger: logger.CustomLogger("Service Bus"), + ctx: ctx, + cancel: cancel, + } +} + +// dispatch the given message to the listeners +func (s *ServiceBus) dispatchMessage(message *Message) { + + // Lock to prevent additions to the listeners + s.lock.RLock() + defer s.lock.RUnlock() + + // Iterate over listener's topics + for topic := range s.listeners { + + // If the topic matches + if strings.HasPrefix(message.Topic(), topic) { + + // Iterate over the listeners + for _, callback := range s.listeners[topic] { + + // Process the message + callback <- message + } + } + } +} + +// Debug puts the service bus into debug mode. +func (s *ServiceBus) Debug() { + s.debug = true +} + +// Start the service bus +func (s *ServiceBus) Start() error { + + // Prevent starting when closed + if s.closed { + return fmt.Errorf("cannot call start on closed servicebus") + } + + s.logger.Trace("Starting") + + go func() { + defer s.logger.Trace("Stopped") + + // Loop until we get a quit message + for { + + select { + case <-s.ctx.Done(): + return + + // Listen for messages + case message := <-s.messageQueue: + + // Log message if in debug mode + if s.debug { + s.logger.Trace("Got message: { Topic: %s, Interface: %#v }", message.Topic(), message.Data()) + } + // Dispatch message + s.dispatchMessage(message) + } + } + + }() + + return nil +} + +// Stop the service bus +func (s *ServiceBus) Stop() error { + + // Prevent subscribing when closed + if s.closed { + return fmt.Errorf("cannot call stop on closed servicebus") + } + + s.closed = true + + // Send quit message + s.cancel() + + // Close down subscriber channels + s.lock.Lock() + defer s.lock.Unlock() + + for _, subscribers := range s.listeners { + for _, channel := range subscribers { + close(channel) + } + } + + // Close message queue + close(s.messageQueue) + + return nil +} + +// UnSubscribe removes the listeners for the given topic (Use with caution!) +func (s *ServiceBus) UnSubscribe(topic string) { + // Prevent any reads or writes to the listeners whilst + // we create a new one + s.lock.Lock() + defer s.lock.Unlock() + s.listeners[topic] = nil +} + +// Subscribe is used to register a listener's interest in a topic +func (s *ServiceBus) Subscribe(topic string) (<-chan *Message, error) { + + // Prevent subscribing when closed + if s.closed { + return nil, fmt.Errorf("cannot call subscribe on closed servicebus") + } + + // Prevent any reads or writes to the listeners whilst + // we create a new one + s.lock.Lock() + defer s.lock.Unlock() + + // Append the new listener + listener := make(chan *Message, 10) + s.listeners[topic] = append(s.listeners[topic], listener) + return (<-chan *Message)(listener), nil + +} + +// Publish sends the given message on the service bus +func (s *ServiceBus) Publish(topic string, data interface{}) { + // Prevent publish when closed + if s.closed { + return + } + + message := NewMessage(topic, data) + s.messageQueue <- message +} + +// PublishForTarget sends the given message on the service bus for the given target +func (s *ServiceBus) PublishForTarget(topic string, data interface{}, target string) { + // Prevent publish when closed + if s.closed { + return + } + message := NewMessageForTarget(topic, data, target) + s.messageQueue <- message +} diff --git a/v2/internal/servicebus/servicebus_test.go b/v2/internal/servicebus/servicebus_test.go new file mode 100644 index 000000000..750a56aaa --- /dev/null +++ b/v2/internal/servicebus/servicebus_test.go @@ -0,0 +1,230 @@ +package servicebus + +import ( + "sync" + "testing" + + "github.com/matryer/is" + "github.com/wailsapp/wails/v2/internal/logger" +) + +type Person interface { + FullName() string +} + +type person struct { + Firstname string + Lastname string +} + +func newPerson(firstname string, lastname string) *person { + result := &person{} + result.Firstname = firstname + result.Lastname = lastname + return result +} + +func (p *person) FullName() string { + return p.Firstname + " " + p.Lastname +} + +func TestSingleTopic(t *testing.T) { + + is := is.New(t) + + var expected string = "I am a message!" + var actual string + + var wg sync.WaitGroup + + // Create new bus + bus := New(logger.New()) + messageChannel, _ := bus.Subscribe("hello") + + wg.Add(1) + go func() { + message := <-messageChannel + actual = message.Data().(string) + wg.Done() + }() + + bus.Start() + bus.Publish("hello", "I am a message!") + wg.Wait() + bus.Stop() + + is.Equal(actual, expected) + +} +func TestMultipleTopics(t *testing.T) { + + is := is.New(t) + + var hello string + var world string + var expected string = "Hello World!" + + var wg sync.WaitGroup + + // Create new bus + bus := New(logger.New()) + + // Create subscriptions + helloChannel, _ := bus.Subscribe("hello") + worldChannel, _ := bus.Subscribe("world") + + wg.Add(1) + go func() { + counter := 2 + for counter > 0 { + select { + case helloMessage := <-helloChannel: + hello = helloMessage.Data().(string) + counter-- + case worldMessage := <-worldChannel: + world = worldMessage.Data().(string) + counter-- + } + } + wg.Done() + }() + + bus.Start() + bus.Publish("hello", "Hello ") + bus.Publish("world", "World!") + wg.Wait() + bus.Stop() + + is.Equal(hello+world, expected) +} + +func TestSingleTopicWildcard(t *testing.T) { + + is := is.New(t) + + var expected string = "I am a message!" + var actual string + + var wg sync.WaitGroup + + // Create new bus + bus := New(logger.New()) + messageChannel, _ := bus.Subscribe("hello") + + wg.Add(1) + go func() { + message := <-messageChannel + actual = message.Data().(string) + wg.Done() + }() + + bus.Start() + bus.Publish("hello:wildcard:test", "I am a message!") + wg.Wait() + bus.Stop() + + is.Equal(actual, expected) + +} +func TestMultipleTopicsWildcard(t *testing.T) { + + is := is.New(t) + + var hello string + var world string + var expected string = "Hello World!" + + var wg sync.WaitGroup + + // Create new bus + bus := New(logger.New()) + helloChannel, _ := bus.Subscribe("hello") + worldChannel, _ := bus.Subscribe("world") + + wg.Add(1) + go func() { + counter := 2 + for counter > 0 { + select { + case helloMessage := <-helloChannel: + hello = helloMessage.Data().(string) + counter-- + case worldMessage := <-worldChannel: + world = worldMessage.Data().(string) + counter-- + } + } + wg.Done() + }() + + bus.Start() + bus.Publish("hello:wildcard:test", "Hello ") + bus.Publish("world:wildcard:test", "World!") + wg.Wait() + bus.Stop() + + is.Equal(hello+world, expected) +} + +func TestStructData(t *testing.T) { + + is := is.New(t) + + var expected string = "Tom Jones" + var actual string + + var wg sync.WaitGroup + + // Create new bus + bus := New(logger.New()) + messageChannel, _ := bus.Subscribe("person") + + wg.Add(1) + go func() { + message := <-messageChannel + p := message.Data().(*person) + actual = p.FullName() + wg.Done() + }() + + bus.Start() + bus.Publish("person", newPerson("Tom", "Jones")) + wg.Wait() + bus.Stop() + + is.Equal(actual, expected) + +} + +func TestErrors(t *testing.T) { + + is := is.New(t) + + // Create new bus + bus := New(logger.New()) + + _, err := bus.Subscribe("person") + is.NoErr(err) + + err = bus.Start() + is.NoErr(err) + + err = bus.Publish("person", newPerson("Tom", "Jones")) + is.NoErr(err) + + err = bus.Stop() + is.NoErr(err) + + err = bus.Stop() + is.True(err != nil) + + err = bus.Start() + is.True(err != nil) + + _, err = bus.Subscribe("person") + is.True(err != nil) + + err = bus.Publish("person", newPerson("Tom", "Jones")) + is.True(err != nil) + +} diff --git a/v2/internal/shell/env.go b/v2/internal/shell/env.go deleted file mode 100644 index ad6a64360..000000000 --- a/v2/internal/shell/env.go +++ /dev/null @@ -1,40 +0,0 @@ -package shell - -import ( - "fmt" - "strings" -) - -func UpsertEnv(env []string, key string, update func(v string) string) []string { - newEnv := make([]string, len(env), len(env)+1) - found := false - for i := range env { - if strings.HasPrefix(env[i], key+"=") { - eqIndex := strings.Index(env[i], "=") - val := env[i][eqIndex+1:] - newEnv[i] = fmt.Sprintf("%s=%v", key, update(val)) - found = true - continue - } - newEnv[i] = env[i] - } - if !found { - newEnv = append(newEnv, fmt.Sprintf("%s=%v", key, update(""))) - } - return newEnv -} - -func RemoveEnv(env []string, key string) []string { - newEnv := make([]string, 0, len(env)) - for _, e := range env { - if strings.HasPrefix(e, key+"=") { - continue - } - newEnv = append(newEnv, e) - } - return newEnv -} - -func SetEnv(env []string, key string, value string) []string { - return UpsertEnv(env, key, func(_ string) string { return value }) -} diff --git a/v2/internal/shell/env_test.go b/v2/internal/shell/env_test.go deleted file mode 100644 index ca41c84dc..000000000 --- a/v2/internal/shell/env_test.go +++ /dev/null @@ -1,67 +0,0 @@ -package shell - -import "testing" - -func TestUpdateEnv(t *testing.T) { - - env := []string{"one=1", "two=a=b", "three="} - newEnv := UpsertEnv(env, "two", func(v string) string { - return v + "+added" - }) - newEnv = UpsertEnv(newEnv, "newVar", func(v string) string { - return "added" - }) - newEnv = UpsertEnv(newEnv, "three", func(v string) string { - return "3" - }) - newEnv = UpsertEnv(newEnv, "GOARCH", func(v string) string { - return "amd64" - }) - - if len(newEnv) != 5 { - t.Errorf("expected: 5, got: %d", len(newEnv)) - } - if newEnv[1] != "two=a=b+added" { - t.Errorf("expected: \"two=a=b+added\", got: %q", newEnv[1]) - } - if newEnv[2] != "three=3" { - t.Errorf("expected: \"three=3\", got: %q", newEnv[2]) - } - if newEnv[3] != "newVar=added" { - t.Errorf("expected: \"newVar=added\", got: %q", newEnv[3]) - } - if newEnv[4] != "GOARCH=amd64" { - t.Errorf("expected: \"newVar=added\", got: %q", newEnv[4]) - } -} - -func TestSetEnv(t *testing.T) { - env := []string{"one=1", "two=a=b", "three="} - newEnv := SetEnv(env, "two", "set") - newEnv = SetEnv(newEnv, "newVar", "added") - - if len(newEnv) != 4 { - t.Errorf("expected: 4, got: %d", len(newEnv)) - } - if newEnv[1] != "two=set" { - t.Errorf("expected: \"two=set\", got: %q", newEnv[1]) - } - if newEnv[3] != "newVar=added" { - t.Errorf("expected: \"newVar=added\", got: %q", newEnv[3]) - } -} - -func TestRemoveEnv(t *testing.T) { - env := []string{"one=1", "two=a=b", "three=3"} - newEnv := RemoveEnv(env, "two") - - if len(newEnv) != 2 { - t.Errorf("expected: 2, got: %d", len(newEnv)) - } - if newEnv[0] != "one=1" { - t.Errorf("expected: \"one=1\", got: %q", newEnv[1]) - } - if newEnv[1] != "three=3" { - t.Errorf("expected: \"three=3\", got: %q", newEnv[3]) - } -} diff --git a/v2/internal/shell/shell.go b/v2/internal/shell/shell.go index 349e27bff..8c36836fb 100644 --- a/v2/internal/shell/shell.go +++ b/v2/internal/shell/shell.go @@ -42,13 +42,14 @@ func (c *Command) Run() error { func (c *Command) Stdout() string { return c.stdo.String() } - func (c *Command) Stderr() string { return c.stde.String() } func (c *Command) AddArgs(args []string) { - c.args = append(c.args, args...) + for _, arg := range args { + c.args = append(c.args, arg) + } } // CreateCommand returns a *Cmd struct that when run, will run the given command + args in the given directory @@ -61,19 +62,7 @@ func CreateCommand(directory string, command string, args ...string) *exec.Cmd { // RunCommand will run the given command + args in the given directory // Will return stdout, stderr and error func RunCommand(directory string, command string, args ...string) (string, string, error) { - return RunCommandWithEnv(nil, directory, command, args...) -} - -// RunCommandWithEnv will run the given command + args in the given directory and using the specified env. -// -// Env specifies the environment of the process. Each entry is of the form "key=value". -// If Env is nil, the new process uses the current process's environment. -// -// Will return stdout, stderr and error -func RunCommandWithEnv(env []string, directory string, command string, args ...string) (string, string, error) { cmd := CreateCommand(directory, command, args...) - cmd.Env = env - var stdo, stde bytes.Buffer cmd.Stdout = &stdo cmd.Stderr = &stde @@ -94,5 +83,8 @@ func RunCommandVerbose(directory string, command string, args ...string) error { // CommandExists returns true if the given command can be found on the shell func CommandExists(name string) bool { _, err := exec.LookPath(name) - return err == nil + if err != nil { + return false + } + return true } diff --git a/v2/internal/signal/signal.go b/v2/internal/signal/signal.go index fa797453f..6d38d89c9 100644 --- a/v2/internal/signal/signal.go +++ b/v2/internal/signal/signal.go @@ -1,38 +1,73 @@ package signal import ( + "context" "os" gosignal "os/signal" "sync" "syscall" + + "github.com/wailsapp/wails/v2/internal/logger" + "github.com/wailsapp/wails/v2/internal/servicebus" ) -var signalChannel = make(chan os.Signal, 2) +// Manager manages signals such as CTRL-C +type Manager struct { + // Service Bus + bus *servicebus.ServiceBus -var ( - callbacks []func() - lock sync.Mutex -) + // logger + logger logger.CustomLogger -func OnShutdown(callback func()) { - lock.Lock() - defer lock.Unlock() - callbacks = append(callbacks, callback) + // signalChannel + signalchannel chan os.Signal + + // ctx + ctx context.Context + cancel context.CancelFunc + + // Parent waitgroup + wg *sync.WaitGroup +} + +// NewManager creates a new signal manager +func NewManager(ctx context.Context, cancel context.CancelFunc, bus *servicebus.ServiceBus, logger *logger.Logger) (*Manager, error) { + + result := &Manager{ + bus: bus, + logger: logger.CustomLogger("Event Manager"), + signalchannel: make(chan os.Signal, 2), + ctx: ctx, + cancel: cancel, + wg: ctx.Value("waitgroup").(*sync.WaitGroup), + } + + return result, nil } // Start the Signal Manager -func Start() { +func (m *Manager) Start() { + // Hook into interrupts - gosignal.Notify(signalChannel, os.Interrupt, syscall.SIGTERM, syscall.SIGINT) + gosignal.Notify(m.signalchannel, os.Interrupt, syscall.SIGTERM) + + m.wg.Add(1) // Spin off signal listener and wait for either a cancellation // or signal go func() { - <-signalChannel - println("") - println("Ctrl+C detected. Shutting down...") - for _, callback := range callbacks { - callback() + select { + case <-m.signalchannel: + println() + m.logger.Trace("Ctrl+C detected. Shutting down...") + m.bus.Publish("quit", "ctrl-c pressed") + + // Start shutdown of Wails + m.cancel() + + case <-m.ctx.Done(): } + m.logger.Trace("Shutdown") + m.wg.Done() }() } diff --git a/v2/internal/staticanalysis/staticanalysis.go b/v2/internal/staticanalysis/staticanalysis.go deleted file mode 100644 index cde436633..000000000 --- a/v2/internal/staticanalysis/staticanalysis.go +++ /dev/null @@ -1,84 +0,0 @@ -package staticanalysis - -import ( - "go/ast" - "path/filepath" - "strings" - - "golang.org/x/tools/go/packages" -) - -type EmbedDetails struct { - BaseDir string - EmbedPath string - All bool -} - -func (e *EmbedDetails) GetFullPath() string { - return filepath.Join(e.BaseDir, e.EmbedPath) -} - -func GetEmbedDetails(sourcePath string) ([]*EmbedDetails, error) { - // read in project files and determine which directories are used for embedding - // return a list of directories - - absPath, err := filepath.Abs(sourcePath) - if err != nil { - return nil, err - } - pkgs, err := packages.Load(&packages.Config{ - Mode: packages.NeedName | packages.NeedSyntax | packages.NeedTypes | packages.NeedTypesInfo | packages.NeedCompiledGoFiles, - Dir: absPath, - }, "./...") - if err != nil { - return nil, err - } - var result []*EmbedDetails - for _, pkg := range pkgs { - for index, file := range pkg.Syntax { - baseDir := filepath.Dir(pkg.CompiledGoFiles[index]) - embedPaths := GetEmbedDetailsForFile(file, baseDir) - if len(embedPaths) > 0 { - result = append(result, embedPaths...) - } - } - } - return result, nil -} - -func GetEmbedDetailsForFile(file *ast.File, baseDir string) []*EmbedDetails { - var result []*EmbedDetails - for _, comment := range file.Comments { - for _, c := range comment.List { - if strings.HasPrefix(c.Text, "//go:embed") { - sl := strings.Split(c.Text, " ") - if len(sl) == 1 { - continue - } - // support for multiple paths in one comment - for _, arg := range sl[1:] { - embedPath := strings.TrimSpace(arg) - // ignores all pattern matching characters except escape sequence - if strings.Contains(embedPath, "*") || strings.Contains(embedPath, "?") || strings.Contains(embedPath, "[") { - continue - } - if strings.HasPrefix(embedPath, "all:") { - result = append(result, &EmbedDetails{ - EmbedPath: strings.TrimPrefix(embedPath, "all:"), - All: true, - BaseDir: baseDir, - }) - } else { - result = append(result, &EmbedDetails{ - EmbedPath: embedPath, - All: false, - BaseDir: baseDir, - }) - } - - } - } - } - } - return result -} diff --git a/v2/internal/staticanalysis/staticanalysis_test.go b/v2/internal/staticanalysis/staticanalysis_test.go deleted file mode 100644 index 77ad2fa6c..000000000 --- a/v2/internal/staticanalysis/staticanalysis_test.go +++ /dev/null @@ -1,51 +0,0 @@ -package staticanalysis - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -func TestGetEmbedDetails(t *testing.T) { - type args struct { - sourcePath string - } - tests := []struct { - name string - args args - want []*EmbedDetails - wantErr bool - }{ - { - name: "GetEmbedDetails", - args: args{ - sourcePath: "test/standard", - }, - want: []*EmbedDetails{ - { - EmbedPath: "frontend/dist", - All: true, - }, - { - EmbedPath: "frontend/static", - All: false, - }, - }, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := GetEmbedDetails(tt.args.sourcePath) - if (err != nil) != tt.wantErr { - t.Errorf("GetEmbedDetails() error = %v, wantErr %v", err, tt.wantErr) - return - } - require.Equal(t, len(tt.want), len(got)) - for index, g := range got { - require.Equal(t, tt.want[index].EmbedPath, g.EmbedPath) - require.Equal(t, tt.want[index].All, g.All) - } - }) - } -} diff --git a/v2/internal/staticanalysis/test/standard/.gitignore b/v2/internal/staticanalysis/test/standard/.gitignore deleted file mode 100644 index d44c22f8c..000000000 --- a/v2/internal/staticanalysis/test/standard/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -build/bin -node_modules -frontend/dist \ No newline at end of file diff --git a/v2/internal/staticanalysis/test/standard/README.md b/v2/internal/staticanalysis/test/standard/README.md deleted file mode 100644 index 397b08b92..000000000 --- a/v2/internal/staticanalysis/test/standard/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# README - -## About - -This is the official Wails Vanilla template. - -You can configure the project by editing `wails.json`. More information about the project settings can be found -here: https://wails.io/docs/reference/project-config - -## Live Development - -To run in live development mode, run `wails dev` in the project directory. This will run a Vite development -server that will provide very fast hot reload of your frontend changes. If you want to develop in a browser -and have access to your Go methods, there is also a dev server that runs on http://localhost:34115. Connect -to this in your browser, and you can call your Go code from devtools. - -## Building - -To build a redistributable, production mode package, use `wails build`. diff --git a/v2/internal/staticanalysis/test/standard/app.go b/v2/internal/staticanalysis/test/standard/app.go deleted file mode 100644 index af53038a1..000000000 --- a/v2/internal/staticanalysis/test/standard/app.go +++ /dev/null @@ -1,27 +0,0 @@ -package main - -import ( - "context" - "fmt" -) - -// App struct -type App struct { - ctx context.Context -} - -// NewApp creates a new App application struct -func NewApp() *App { - return &App{} -} - -// startup is called when the app starts. The context is saved -// so we can call the runtime methods -func (a *App) startup(ctx context.Context) { - a.ctx = ctx -} - -// Greet returns a greeting for the given name -func (a *App) Greet(name string) string { - return fmt.Sprintf("Hello %s, It's show time!", name) -} diff --git a/v2/internal/staticanalysis/test/standard/go.mod b/v2/internal/staticanalysis/test/standard/go.mod deleted file mode 100644 index c9fe1fb52..000000000 --- a/v2/internal/staticanalysis/test/standard/go.mod +++ /dev/null @@ -1,35 +0,0 @@ -module changeme - -go 1.18 - -require github.com/wailsapp/wails/v2 v2.3.1 - -require ( - github.com/bep/debounce v1.2.1 // indirect - github.com/go-ole/go-ole v1.2.6 // indirect - github.com/google/uuid v1.3.0 // indirect - github.com/imdario/mergo v0.3.13 // indirect - github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect - github.com/labstack/echo/v4 v4.9.1 // indirect - github.com/labstack/gommon v0.4.0 // indirect - github.com/leaanthony/go-ansi-parser v1.6.0 // indirect - github.com/leaanthony/gosod v1.0.3 // indirect - github.com/leaanthony/slicer v1.6.0 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.16 // indirect - github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect - github.com/pkg/errors v0.9.1 // indirect - github.com/rivo/uniseg v0.4.2 // indirect - github.com/samber/lo v1.27.1 // indirect - github.com/tkrajina/go-reflector v0.5.6 // indirect - github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasttemplate v1.2.1 // indirect - github.com/wailsapp/mimetype v1.4.1 // indirect - golang.org/x/crypto v0.21.0 // indirect - golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect - golang.org/x/net v0.23.0 // indirect - golang.org/x/sys v0.18.0 // indirect - golang.org/x/text v0.14.0 // indirect -) - -// replace github.com/wailsapp/wails/v2 v2.0.0 => C:\Users\leaan diff --git a/v2/internal/staticanalysis/test/standard/go.sum b/v2/internal/staticanalysis/test/standard/go.sum deleted file mode 100644 index 2cd0cf773..000000000 --- a/v2/internal/staticanalysis/test/standard/go.sum +++ /dev/null @@ -1,87 +0,0 @@ -github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY= -github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= -github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= -github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= -github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck= -github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs= -github.com/labstack/echo/v4 v4.9.1 h1:GliPYSpzGKlyOhqIbG8nmHBo3i1saKWFOgh41AN3b+Y= -github.com/labstack/echo/v4 v4.9.1/go.mod h1:Pop5HLc+xoc4qhTZ1ip6C0RtP7Z+4VzRLWZZFKqbbjo= -github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= -github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= -github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc= -github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA= -github.com/leaanthony/go-ansi-parser v1.6.0 h1:T8TuMhFB6TUMIUm0oRrSbgJudTFw9csT3ZK09w0t4Pg= -github.com/leaanthony/go-ansi-parser v1.6.0/go.mod h1:+vva/2y4alzVmmIEpk9QDhA7vLC5zKDTRwfZGOp3IWU= -github.com/leaanthony/gosod v1.0.3 h1:Fnt+/B6NjQOVuCWOKYRREZnjGyvg+mEhd1nkkA04aTQ= -github.com/leaanthony/gosod v1.0.3/go.mod h1:BJ2J+oHsQIyIQpnLPjnqFGTMnOZXDbvWtRCSG7jGxs4= -github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY= -github.com/leaanthony/slicer v1.6.0 h1:1RFP5uiPJvT93TAHi+ipd3NACobkW53yUiBqZheE/Js= -github.com/leaanthony/slicer v1.6.0/go.mod h1:o/Iz29g7LN0GqH3aMjWAe90381nyZlDNquK+mtH2Fj8= -github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= -github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= -github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= -github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8= -github.com/rivo/uniseg v0.4.2/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/samber/lo v1.27.1 h1:sTXwkRiIFIQG+G0HeAvOEnGjqWeWtI9cg5/n51KrxPg= -github.com/samber/lo v1.27.1/go.mod h1:it33p9UtPMS7z72fP4gw/EIfQB2eI8ke7GR2wc6+Rhg= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= -github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M= -github.com/tkrajina/go-reflector v0.5.6 h1:hKQ0gyocG7vgMD2M3dRlYN6WBBOmdoOzJ6njQSepKdE= -github.com/tkrajina/go-reflector v0.5.6/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4= -github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4= -github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs= -github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o= -github.com/wailsapp/wails/v2 v2.3.1 h1:ZJz+pyIBKyASkgO8JO31NuHO1gTTHmvwiHYHwei1CqM= -github.com/wailsapp/wails/v2 v2.3.1/go.mod h1:zlNLI0E2c2qA6miiuAHtp0Bac8FaGH0tlhA19OssR/8= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM= -golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= -golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/v2/internal/staticanalysis/test/standard/main.go b/v2/internal/staticanalysis/test/standard/main.go deleted file mode 100644 index 2b6ab33b6..000000000 --- a/v2/internal/staticanalysis/test/standard/main.go +++ /dev/null @@ -1,39 +0,0 @@ -package main - -import ( - "embed" - - "github.com/wailsapp/wails/v2" - "github.com/wailsapp/wails/v2/pkg/options" - "github.com/wailsapp/wails/v2/pkg/options/assetserver" -) - -//go:embed all:frontend/dist frontend/static -var assets embed.FS - -//go:embed frontend/src/*.json -var srcjson embed.FS - -func main() { - // Create an instance of the app structure - app := NewApp() - - // Create application with options - err := wails.Run(&options.App{ - Title: "staticanalysis", - Width: 1024, - Height: 768, - AssetServer: &assetserver.Options{ - Assets: assets, - }, - BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, - OnStartup: app.startup, - Bind: []interface{}{ - app, - }, - }) - - if err != nil { - println("Error:", err.Error()) - } -} diff --git a/v2/internal/staticanalysis/test/standard/wails.json b/v2/internal/staticanalysis/test/standard/wails.json deleted file mode 100644 index 5ab7f3600..000000000 --- a/v2/internal/staticanalysis/test/standard/wails.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "staticanalysis", - "outputfilename": "staticanalysis", - "frontend:install": "npm install", - "frontend:build": "npm run build", - "frontend:dev:watcher": "npm run dev", - "frontend:dev:serverUrl": "auto", - "author": { - "name": "Lea Anthony", - "email": "lea.anthony@gmail.com" - } -} diff --git a/v2/internal/subsystem/binding.go b/v2/internal/subsystem/binding.go new file mode 100644 index 000000000..cfc4bae4f --- /dev/null +++ b/v2/internal/subsystem/binding.go @@ -0,0 +1,64 @@ +package subsystem + +import ( + "github.com/wailsapp/wails/v2/internal/binding" + "github.com/wailsapp/wails/v2/internal/logger" + "github.com/wailsapp/wails/v2/internal/servicebus" +) + +// Binding is the Binding subsystem. It manages all service bus messages +// starting with "binding". +type Binding struct { + bindingChannel <-chan *servicebus.Message + + running bool + + // Binding db + bindings *binding.Bindings + + // logger + logger logger.CustomLogger +} + +// NewBinding creates a new binding subsystem. Uses the given bindings db for reference. +func NewBinding(bus *servicebus.ServiceBus, logger *logger.Logger, bindings *binding.Bindings) (*Binding, error) { + + // Subscribe to event messages + bindingChannel, err := bus.Subscribe("binding") + if err != nil { + return nil, err + } + + result := &Binding{ + bindingChannel: bindingChannel, + logger: logger.CustomLogger("Binding Subsystem"), + bindings: bindings, + } + + return result, nil +} + +// Start the subsystem +func (b *Binding) Start() error { + + b.running = true + + b.logger.Trace("Starting") + + // Spin off a go routine + go func() { + for b.running { + select { + case bindingMessage := <-b.bindingChannel: + b.logger.Trace("Got binding message: %+v", bindingMessage) + } + } + b.logger.Trace("Shutdown") + }() + + return nil +} + +func (b *Binding) Close() { + b.running = false +} diff --git a/v2/internal/subsystem/call.go b/v2/internal/subsystem/call.go new file mode 100644 index 000000000..f9ee4fd47 --- /dev/null +++ b/v2/internal/subsystem/call.go @@ -0,0 +1,202 @@ +package subsystem + +import ( + "context" + "encoding/json" + "fmt" + "github.com/wailsapp/wails/v2/pkg/runtime" + "strings" + "sync" + + "github.com/wailsapp/wails/v2/internal/binding" + "github.com/wailsapp/wails/v2/internal/logger" + "github.com/wailsapp/wails/v2/internal/messagedispatcher/message" + "github.com/wailsapp/wails/v2/internal/servicebus" +) + +// Call is the Call subsystem. It manages all service bus messages +// starting with "call". +type Call struct { + callChannel <-chan *servicebus.Message + + // quit flag + shouldQuit bool + + // bindings DB + DB *binding.DB + + // ServiceBus + bus *servicebus.ServiceBus + + // logger + logger logger.CustomLogger + + // context + ctx context.Context + + // parent waitgroup + wg *sync.WaitGroup +} + +// NewCall creates a new call subsystem +func NewCall(ctx context.Context, bus *servicebus.ServiceBus, logger *logger.Logger, DB *binding.DB) (*Call, error) { + + // Subscribe to event messages + callChannel, err := bus.Subscribe("call:invoke") + if err != nil { + return nil, err + } + + result := &Call{ + callChannel: callChannel, + logger: logger.CustomLogger("Call Subsystem"), + DB: DB, + bus: bus, + ctx: ctx, + wg: ctx.Value("waitgroup").(*sync.WaitGroup), + } + + return result, nil +} + +// Start the subsystem +func (c *Call) Start() error { + + c.wg.Add(1) + + // Spin off a go routine + go func() { + defer c.logger.Trace("Shutdown") + for { + select { + case <-c.ctx.Done(): + c.wg.Done() + return + case callMessage := <-c.callChannel: + c.processCall(callMessage) + } + } + + }() + + return nil +} + +func (c *Call) processCall(callMessage *servicebus.Message) { + + c.logger.Trace("Got message: %+v", callMessage) + + // Extract payload + payload := callMessage.Data().(*message.CallMessage) + + // Lookup method + registeredMethod := c.DB.GetMethod(payload.Name) + + // Check if it's a system call + if strings.HasPrefix(payload.Name, ".wails.") { + c.processSystemCall(payload, callMessage.Target()) + return + } + + // Check we have it + if registeredMethod == nil { + c.sendError(fmt.Errorf("Method not registered"), payload, callMessage.Target()) + return + } + c.logger.Trace("Got registered method: %+v", registeredMethod) + + args, err := registeredMethod.ParseArgs(payload.Args) + if err != nil { + c.sendError(fmt.Errorf("Error parsing arguments: %s", err.Error()), payload, callMessage.Target()) + } + + result, err := registeredMethod.Call(args) + if err != nil { + c.sendError(err, payload, callMessage.Target()) + return + } + c.logger.Trace("registeredMethod.Call: %+v, %+v", result, err) + // process result + c.sendResult(result, payload, callMessage.Target()) + +} + +func (c *Call) processSystemCall(payload *message.CallMessage, clientID string) { + c.logger.Trace("Got internal System call: %+v", payload) + callName := strings.TrimPrefix(payload.Name, ".wails.") + switch callName { + case "Dialog.Open": + var dialogOptions runtime.OpenDialogOptions + err := json.Unmarshal(payload.Args[0], &dialogOptions) + if err != nil { + c.logger.Error("Error decoding: %s", err) + } + result, err := runtime.OpenFileDialog(c.ctx, dialogOptions) + if err != nil { + c.logger.Error("Error: %s", err) + } + c.sendResult(result, payload, clientID) + case "Dialog.Save": + var dialogOptions runtime.SaveDialogOptions + err := json.Unmarshal(payload.Args[0], &dialogOptions) + if err != nil { + c.logger.Error("Error decoding: %s", err) + } + result, err := runtime.SaveFileDialog(c.ctx, dialogOptions) + if err != nil { + c.logger.Error("Error: %s", err) + } + c.sendResult(result, payload, clientID) + case "Dialog.Message": + var dialogOptions runtime.MessageDialogOptions + err := json.Unmarshal(payload.Args[0], &dialogOptions) + if err != nil { + c.logger.Error("Error decoding: %s", err) + } + result, err := runtime.MessageDialog(c.ctx, dialogOptions) + if err != nil { + c.logger.Error("Error: %s", err) + } + c.sendResult(result, payload, clientID) + default: + c.logger.Error("Unknown system call: %+v", callName) + } +} + +func (c *Call) sendResult(result interface{}, payload *message.CallMessage, clientID string) { + c.logger.Trace("Sending success result with CallbackID '%s' : %+v\n", payload.CallbackID, result) + incomingMessage := &CallbackMessage{ + Result: result, + CallbackID: payload.CallbackID, + } + messageData, err := json.Marshal(incomingMessage) + c.logger.Trace("json incomingMessage data: %+v\n", string(messageData)) + if err != nil { + // what now? + c.logger.Fatal(err.Error()) + } + c.bus.PublishForTarget("call:result", string(messageData), clientID) +} + +func (c *Call) sendError(err error, payload *message.CallMessage, clientID string) { + c.logger.Trace("Sending error result with CallbackID '%s' : %+v\n", payload.CallbackID, err.Error()) + incomingMessage := &CallbackMessage{ + Err: err.Error(), + CallbackID: payload.CallbackID, + } + + messageData, err := json.Marshal(incomingMessage) + c.logger.Trace("json incomingMessage data: %+v\n", string(messageData)) + if err != nil { + // what now? + c.logger.Fatal(err.Error()) + } + c.bus.PublishForTarget("call:result", string(messageData), clientID) +} + +// CallbackMessage defines a message that contains the result of a call +type CallbackMessage struct { + Result interface{} `json:"result"` + Err string `json:"error"` + CallbackID string `json:"callbackid"` +} diff --git a/v2/internal/subsystem/event.go b/v2/internal/subsystem/event.go new file mode 100644 index 000000000..988bec7dd --- /dev/null +++ b/v2/internal/subsystem/event.go @@ -0,0 +1,191 @@ +package subsystem + +import ( + "context" + "strings" + "sync" + + "github.com/wailsapp/wails/v2/internal/logger" + "github.com/wailsapp/wails/v2/internal/messagedispatcher/message" + "github.com/wailsapp/wails/v2/internal/servicebus" +) + +// eventListener holds a callback function which is invoked when +// the event listened for is emitted. It has a counter which indicates +// how the total number of events it is interested in. A value of zero +// means it does not expire (default). +type eventListener struct { + callback func(...interface{}) // Function to call with emitted event data + counter int // The number of times this callback may be called. -1 = infinite + delete bool // Flag to indicate that this listener should be deleted +} + +// Event is the Eventing subsystem. It manages all service bus messages +// starting with "event". +type Event struct { + eventChannel <-chan *servicebus.Message + + // Event listeners + listeners map[string][]*eventListener + notifyLock sync.RWMutex + + // logger + logger logger.CustomLogger + + // ctx + ctx context.Context + + // parent waitgroup + wg *sync.WaitGroup +} + +// NewEvent creates a new log subsystem +func NewEvent(ctx context.Context, bus *servicebus.ServiceBus, logger *logger.Logger) (*Event, error) { + + // Subscribe to event messages + eventChannel, err := bus.Subscribe("event") + if err != nil { + return nil, err + } + + result := &Event{ + eventChannel: eventChannel, + logger: logger.CustomLogger("Event Subsystem"), + listeners: make(map[string][]*eventListener), + ctx: ctx, + wg: ctx.Value("waitgroup").(*sync.WaitGroup), + } + + return result, nil +} + +// RegisterListener provides a means of subscribing to events of type "eventName" +func (e *Event) RegisterListener(eventName string, callback func(...interface{}), counter int) { + + // Create new eventListener + thisListener := &eventListener{ + callback: callback, + counter: counter, + delete: false, + } + + e.notifyLock.Lock() + // Append the new listener to the listeners slice + e.listeners[eventName] = append(e.listeners[eventName], thisListener) + e.notifyLock.Unlock() +} + +// Start the subsystem +func (e *Event) Start() error { + + e.logger.Trace("Starting") + + e.wg.Add(1) + + // Spin off a go routine + go func() { + defer e.logger.Trace("OnShutdown") + for { + select { + case <-e.ctx.Done(): + e.wg.Done() + return + case eventMessage := <-e.eventChannel: + splitTopic := strings.Split(eventMessage.Topic(), ":") + eventType := splitTopic[1] + switch eventType { + case "emit": + if len(splitTopic) != 4 { + e.logger.Error("Received emit message with invalid topic format. Expected 4 sections in topic, got %s", splitTopic) + continue + } + eventSource := splitTopic[3] + e.logger.Trace("Got Event Message: %s %+v", eventMessage.Topic(), eventMessage.Data()) + event := eventMessage.Data().(*message.EventMessage) + eventName := event.Name + switch eventSource { + + case "j": + // Notify Go Subscribers + e.logger.Trace("Notify Go subscribers to event '%s'", eventName) + go e.notifyListeners(eventName, event) + case "g": + // Notify Go listeners + e.logger.Trace("Got Go Event: %s", eventName) + go e.notifyListeners(eventName, event) + default: + e.logger.Error("unknown emit event message: %+v", eventMessage) + } + case "on": + // We wish to subscribe to an event channel + var message *message.OnEventMessage = eventMessage.Data().(*message.OnEventMessage) + eventName := message.Name + callback := message.Callback + e.RegisterListener(eventName, callback, message.Counter) + e.logger.Trace("Registered listener for event '%s' with callback %p", eventName, callback) + default: + e.logger.Error("unknown event message: %+v", eventMessage) + } + } + } + + }() + + return nil +} + +// Notifies listeners for the given event name +func (e *Event) notifyListeners(eventName string, message *message.EventMessage) { + + // Get list of event listeners + listeners := e.listeners[eventName] + if listeners == nil { + e.logger.Trace("No listeners for event '%s'", eventName) + return + } + + // Lock the listeners + e.notifyLock.Lock() + + // We have a dirty flag to indicate that there are items to delete + itemsToDelete := false + + // Callback in goroutine + for _, listener := range listeners { + if listener.counter > 0 { + listener.counter-- + } + + go listener.callback(message.Data...) + + if listener.counter == 0 { + listener.delete = true + itemsToDelete = true + } + } + + // Do we have items to delete? + if itemsToDelete == true { + + // Create a new Listeners slice + var newListeners = []*eventListener{} + + // Iterate over current listeners + for _, listener := range listeners { + // If we aren't deleting the listener, add it to the new list + if !listener.delete { + newListeners = append(newListeners, listener) + } + } + + // Save new listeners or remove entry + if len(newListeners) > 0 { + e.listeners[eventName] = newListeners + } else { + delete(e.listeners, eventName) + } + } + + // Unlock + e.notifyLock.Unlock() +} diff --git a/v2/internal/subsystem/event_test.go b/v2/internal/subsystem/event_test.go new file mode 100644 index 000000000..99219948c --- /dev/null +++ b/v2/internal/subsystem/event_test.go @@ -0,0 +1,50 @@ +package subsystem + +import ( + "os" + "sync" + "testing" + + "github.com/matryer/is" + "github.com/wailsapp/wails/v2/internal/logger" + "github.com/wailsapp/wails/v2/internal/messagedispatcher/message" + "github.com/wailsapp/wails/v2/internal/servicebus" +) + +func TestSingleTopic(t *testing.T) { + + is := is.New(t) + + var expected string = "I am a message!" + var actual string + + var wg sync.WaitGroup + + // Create new bus + myLogger := logger.New(os.Stdout) + myLogger.SetLogLevel(logger.TRACE) + bus := servicebus.New(myLogger) + eventSubsystem, _ := NewEvent(bus, myLogger) + eventSubsystem.Start() + + eventSubsystem.RegisterListener("test", func(data ...interface{}) { + is.Equal(len(data), 1) + actual = data[0].(string) + wg.Done() + }) + + wg.Add(1) + + eventMessage := &message.EventMessage{ + Name: "test", + Data: []interface{}{"I am a message!"}, + } + + bus.Start() + bus.Publish("event:test:from:j", eventMessage) + wg.Wait() + bus.Stop() + + is.Equal(actual, expected) + +} diff --git a/v2/internal/subsystem/log.go b/v2/internal/subsystem/log.go new file mode 100644 index 000000000..36f5abfd6 --- /dev/null +++ b/v2/internal/subsystem/log.go @@ -0,0 +1,111 @@ +package subsystem + +import ( + "context" + "strconv" + "strings" + "sync" + + "github.com/wailsapp/wails/v2/internal/logger" + "github.com/wailsapp/wails/v2/internal/servicebus" +) + +// Log is the Logging subsystem. It handles messages with topics starting +// with "log:" +type Log struct { + logChannel <-chan *servicebus.Message + + // quit flag + shouldQuit bool + + // Logger! + logger *logger.Logger + + // Context for shutdown + ctx context.Context + cancel context.CancelFunc + + // internal waitgroup + wg sync.WaitGroup +} + +// NewLog creates a new log subsystem +func NewLog(bus *servicebus.ServiceBus, logger *logger.Logger) (*Log, error) { + + // Subscribe to log messages + logChannel, err := bus.Subscribe("log") + if err != nil { + return nil, err + } + + ctx, cancel := context.WithCancel(context.Background()) + + result := &Log{ + logChannel: logChannel, + logger: logger, + ctx: ctx, + cancel: cancel, + } + + return result, nil +} + +// Start the subsystem +func (l *Log) Start() error { + + l.wg.Add(1) + + // Spin off a go routine + go func() { + defer l.logger.Trace("Logger Shutdown") + + for l.shouldQuit == false { + select { + case <-l.ctx.Done(): + l.wg.Done() + return + case logMessage := <-l.logChannel: + logType := strings.TrimPrefix(logMessage.Topic(), "log:") + switch logType { + case "print": + l.logger.Print(logMessage.Data().(string)) + case "trace": + l.logger.Trace(logMessage.Data().(string)) + case "debug": + l.logger.Debug(logMessage.Data().(string)) + case "info": + l.logger.Info(logMessage.Data().(string)) + case "warning": + l.logger.Warning(logMessage.Data().(string)) + case "error": + l.logger.Error(logMessage.Data().(string)) + case "fatal": + l.logger.Fatal(logMessage.Data().(string)) + case "setlevel": + switch inLevel := logMessage.Data().(type) { + case logger.LogLevel: + l.logger.SetLogLevel(inLevel) + case string: + uint64level, err := strconv.ParseUint(inLevel, 10, 8) + if err != nil { + l.logger.Error("Error parsing log level: %+v", inLevel) + continue + } + level := logger.LogLevel(uint64level) + l.logger.SetLogLevel(level) + } + + default: + l.logger.Error("unknown log message: %+v", logMessage) + } + } + } + }() + + return nil +} + +func (l *Log) Close() { + l.cancel() + l.wg.Wait() +} diff --git a/v2/internal/subsystem/menu.go b/v2/internal/subsystem/menu.go new file mode 100644 index 000000000..2a6552769 --- /dev/null +++ b/v2/internal/subsystem/menu.go @@ -0,0 +1,176 @@ +package subsystem + +import ( + "context" + "encoding/json" + "strings" + "sync" + + "github.com/wailsapp/wails/v2/pkg/menu" + + "github.com/wailsapp/wails/v2/internal/logger" + "github.com/wailsapp/wails/v2/internal/menumanager" + "github.com/wailsapp/wails/v2/internal/servicebus" +) + +// Menu is the subsystem that handles the operation of menus. It manages all service bus messages +// starting with "menu". +type Menu struct { + menuChannel <-chan *servicebus.Message + + // shutdown flag + shouldQuit bool + + // logger + logger logger.CustomLogger + + // Service Bus + bus *servicebus.ServiceBus + + // Menu Manager + menuManager *menumanager.Manager + + // ctx + ctx context.Context + + // parent waitgroup + wg *sync.WaitGroup +} + +// NewMenu creates a new menu subsystem +func NewMenu(ctx context.Context, bus *servicebus.ServiceBus, logger *logger.Logger, menuManager *menumanager.Manager) (*Menu, error) { + + // Subscribe to menu messages + menuChannel, err := bus.Subscribe("menu:") + if err != nil { + return nil, err + } + + result := &Menu{ + menuChannel: menuChannel, + logger: logger.CustomLogger("Menu Subsystem"), + bus: bus, + menuManager: menuManager, + ctx: ctx, + wg: ctx.Value("waitgroup").(*sync.WaitGroup), + } + + return result, nil +} + +// Start the subsystem +func (m *Menu) Start() error { + + m.logger.Trace("Starting") + + m.wg.Add(1) + + // Spin off a go routine + go func() { + defer m.logger.Trace("Shutdown") + for { + select { + case <-m.ctx.Done(): + m.wg.Done() + return + case menuMessage := <-m.menuChannel: + splitTopic := strings.Split(menuMessage.Topic(), ":") + menuMessageType := splitTopic[1] + switch menuMessageType { + case "ontrayopen": + trayID := menuMessage.Data().(string) + m.menuManager.OnTrayMenuOpen(trayID) + case "ontrayclose": + trayID := menuMessage.Data().(string) + m.menuManager.OnTrayMenuClose(trayID) + case "clicked": + if len(splitTopic) != 2 { + m.logger.Error("Received clicked message with invalid topic format. Expected 2 sections in topic, got %s", splitTopic) + continue + } + m.logger.Trace("Got Menu clicked Message: %s %+v", menuMessage.Topic(), menuMessage.Data()) + + type ClickCallbackMessage struct { + MenuItemID string `json:"menuItemID"` + MenuType string `json:"menuType"` + Data string `json:"data"` + ParentID string `json:"parentID"` + } + + var callbackData ClickCallbackMessage + payload := []byte(menuMessage.Data().(string)) + err := json.Unmarshal(payload, &callbackData) + if err != nil { + m.logger.Error("%s", err.Error()) + return + } + + err = m.menuManager.ProcessClick(callbackData.MenuItemID, callbackData.Data, callbackData.MenuType, callbackData.ParentID) + if err != nil { + m.logger.Trace("%s", err.Error()) + } + + // Make sure we catch any menu updates + case "updateappmenu": + updatedMenu, err := m.menuManager.UpdateApplicationMenu() + if err != nil { + m.logger.Trace("%s", err.Error()) + return + } + + // Notify frontend of menu change + m.bus.Publish("menufrontend:updateappmenu", updatedMenu) + + case "updatecontextmenu": + contextMenu := menuMessage.Data().(*menu.ContextMenu) + updatedMenu, err := m.menuManager.UpdateContextMenu(contextMenu) + if err != nil { + m.logger.Trace("%s", err.Error()) + return + } + + // Notify frontend of menu change + m.bus.Publish("menufrontend:updatecontextmenu", updatedMenu) + + case "settraymenu": + trayMenu := menuMessage.Data().(*menu.TrayMenu) + updatedMenu, err := m.menuManager.SetTrayMenu(trayMenu) + if err != nil { + m.logger.Trace("%s", err.Error()) + return + } + + // Notify frontend of menu change + m.bus.Publish("menufrontend:settraymenu", updatedMenu) + + case "deletetraymenu": + trayMenu := menuMessage.Data().(*menu.TrayMenu) + trayID, err := m.menuManager.GetTrayID(trayMenu) + if err != nil { + m.logger.Trace("%s", err.Error()) + return + } + + // Notify frontend of menu change + m.bus.Publish("menufrontend:deletetraymenu", trayID) + + case "updatetraymenulabel": + trayMenu := menuMessage.Data().(*menu.TrayMenu) + updatedLabel, err := m.menuManager.UpdateTrayMenuLabel(trayMenu) + if err != nil { + m.logger.Trace("%s", err.Error()) + return + } + + // Notify frontend of menu change + m.bus.Publish("menufrontend:updatetraymenulabel", updatedLabel) + + default: + m.logger.Error("unknown menu message: %+v", menuMessage) + } + } + } + }() + + return nil +} diff --git a/v2/internal/subsystem/runtime.go b/v2/internal/subsystem/runtime.go new file mode 100644 index 000000000..1719de96f --- /dev/null +++ b/v2/internal/subsystem/runtime.go @@ -0,0 +1,103 @@ +package subsystem + +import ( + "context" + "fmt" + "github.com/wailsapp/wails/v2/internal/logger" + "github.com/wailsapp/wails/v2/internal/servicebus" + "strings" + "sync" +) + +// Runtime is the Runtime subsystem. It handles messages with topics starting +// with "runtime:" +type Runtime struct { + runtimeChannel <-chan *servicebus.Message + + // The hooks channel allows us to hook into frontend startup + hooksChannel <-chan *servicebus.Message + startupCallback func(ctx context.Context) + shutdownCallback func() + + // quit flag + shouldQuit bool + + logger logger.CustomLogger + + //ctx + ctx context.Context + + // OnStartup Hook + startupOnce sync.Once + + // Service bus + bus *servicebus.ServiceBus +} + +// NewRuntime creates a new runtime subsystem +func NewRuntime(ctx context.Context, bus *servicebus.ServiceBus, logger *logger.Logger, startupCallback func(context.Context)) (*Runtime, error) { + + // Subscribe to log messages + runtimeChannel, err := bus.Subscribe("runtime:") + if err != nil { + return nil, err + } + + // Subscribe to log messages + hooksChannel, err := bus.Subscribe("hooks:") + if err != nil { + return nil, err + } + + result := &Runtime{ + runtimeChannel: runtimeChannel, + hooksChannel: hooksChannel, + logger: logger.CustomLogger("Runtime Subsystem"), + startupCallback: startupCallback, + bus: bus, + } + result.ctx = context.WithValue(ctx, "bus", bus) + + return result, nil +} + +// Start the subsystem +func (r *Runtime) Start() error { + + // Spin off a go routine + go func() { + defer r.logger.Trace("OnShutdown") + for { + select { + case hooksMessage := <-r.hooksChannel: + r.logger.Trace(fmt.Sprintf("Received hooksmessage: %+v", hooksMessage)) + messageSlice := strings.Split(hooksMessage.Topic(), ":") + hook := messageSlice[1] + switch hook { + case "startup": + if r.startupCallback != nil { + r.startupOnce.Do(func() { + go func() { + r.startupCallback(r.ctx) + // If we got a url, publish it now startup completed + url, ok := hooksMessage.Data().(string) + if ok && len(url) > 0 { + r.bus.Publish("url:handler", url) + } + }() + }) + } else { + r.logger.Warning("no startup callback registered!") + } + default: + r.logger.Error("unknown hook message: %+v", hooksMessage) + continue + } + case <-r.ctx.Done(): + return + } + } + }() + + return nil +} diff --git a/v2/internal/subsystem/url.go b/v2/internal/subsystem/url.go new file mode 100644 index 000000000..83cde87ce --- /dev/null +++ b/v2/internal/subsystem/url.go @@ -0,0 +1,98 @@ +package subsystem + +import ( + "context" + "strings" + "sync" + + "github.com/wailsapp/wails/v2/internal/logger" + "github.com/wailsapp/wails/v2/internal/servicebus" +) + +// URL is the URL Handler subsystem. It handles messages with topics starting +// with "url:" +type URL struct { + urlChannel <-chan *servicebus.Message + + // quit flag + shouldQuit bool + + // Logger! + logger *logger.Logger + + // Context for shutdown + ctx context.Context + cancel context.CancelFunc + + // internal waitgroup + wg sync.WaitGroup + + // Handlers + handlers map[string]func(string) +} + +// NewURL creates a new log subsystem +func NewURL(bus *servicebus.ServiceBus, logger *logger.Logger, handlers map[string]func(string)) (*URL, error) { + + // Subscribe to log messages + urlChannel, err := bus.Subscribe("url") + if err != nil { + return nil, err + } + + ctx, cancel := context.WithCancel(context.Background()) + + result := &URL{ + urlChannel: urlChannel, + logger: logger, + ctx: ctx, + cancel: cancel, + handlers: handlers, + } + + return result, nil +} + +// Start the subsystem +func (u *URL) Start() error { + + u.wg.Add(1) + + // Spin off a go routine + go func() { + defer u.logger.Trace("URL Shutdown") + + for u.shouldQuit == false { + select { + case <-u.ctx.Done(): + u.wg.Done() + return + case urlMessage := <-u.urlChannel: + // Guard against nil messages + if urlMessage == nil { + continue + } + messageType := strings.TrimPrefix(urlMessage.Topic(), "url:") + switch messageType { + case "handler": + url := urlMessage.Data().(string) + splitURL := strings.Split(url, ":") + protocol := splitURL[0] + callback, ok := u.handlers[protocol] + if ok { + go callback(url) + } + default: + u.logger.Error("unknown url message: %+v", urlMessage) + } + } + } + }() + + return nil +} + +func (u *URL) Close() { + u.cancel() + u.wg.Wait() +} diff --git a/v2/internal/system/operatingsystem/os.go b/v2/internal/system/operatingsystem/os.go index 028a97b2e..39f1de8e0 100644 --- a/v2/internal/system/operatingsystem/os.go +++ b/v2/internal/system/operatingsystem/os.go @@ -2,10 +2,9 @@ package operatingsystem // OS contains information about the operating system type OS struct { - ID string - Name string - Version string - Branding string + ID string + Name string + Version string } // Info retrieves information about the current platform diff --git a/v2/internal/system/operatingsystem/os_darwin.go b/v2/internal/system/operatingsystem/os_darwin.go index 8083e1aed..adc808773 100644 --- a/v2/internal/system/operatingsystem/os_darwin.go +++ b/v2/internal/system/operatingsystem/os_darwin.go @@ -1,9 +1,8 @@ package operatingsystem import ( - "strings" - "github.com/wailsapp/wails/v2/internal/shell" + "strings" ) func getSysctlValue(key string) (string, error) { @@ -27,7 +26,7 @@ func platformInfo() (*OS, error) { return nil, err } result.Version = version - ID, err := getSysctlValue("kern.osversion") + ID, err := getSysctlValue("kern.osrevision") if err != nil { return nil, err } diff --git a/v2/internal/system/operatingsystem/os_linux.go b/v2/internal/system/operatingsystem/os_linux.go index 49e00c02c..090bba2ac 100644 --- a/v2/internal/system/operatingsystem/os_linux.go +++ b/v2/internal/system/operatingsystem/os_linux.go @@ -1,10 +1,10 @@ -//go:build linux // +build linux package operatingsystem import ( "fmt" + "io/ioutil" "os" "strings" ) @@ -16,7 +16,7 @@ func platformInfo() (*OS, error) { return nil, fmt.Errorf("unable to read system information") } - osRelease, _ := os.ReadFile("/etc/os-release") + osRelease, _ := ioutil.ReadFile("/etc/os-release") return parseOsRelease(string(osRelease)), nil } diff --git a/v2/internal/system/operatingsystem/os_windows.go b/v2/internal/system/operatingsystem/os_windows.go index a9aa05a92..0f294ba9c 100644 --- a/v2/internal/system/operatingsystem/os_windows.go +++ b/v2/internal/system/operatingsystem/os_windows.go @@ -1,47 +1,11 @@ -//go:build windows - package operatingsystem import ( "fmt" - "strings" - "syscall" - "unsafe" - "golang.org/x/sys/windows" "golang.org/x/sys/windows/registry" ) -func stripNulls(str string) string { - // Split the string into substrings at each null character - substrings := strings.Split(str, "\x00") - - // Join the substrings back into a single string - strippedStr := strings.Join(substrings, "") - - return strippedStr -} - -func mustStringToUTF16Ptr(input string) *uint16 { - input = stripNulls(input) - result, err := syscall.UTF16PtrFromString(input) - if err != nil { - panic(err) - } - return result -} - -func getBranding() string { - var modBranding = syscall.NewLazyDLL("winbrand.dll") - var brandingFormatString = modBranding.NewProc("BrandingFormatString") - - windowsLong := mustStringToUTF16Ptr("%WINDOWS_LONG%\x00") - ret, _, _ := brandingFormatString.Call( - uintptr(unsafe.Pointer(windowsLong)), - ) - return windows.UTF16PtrToString((*uint16)(unsafe.Pointer(ret))) -} - func platformInfo() (*OS, error) { // Default value var result OS @@ -61,7 +25,6 @@ func platformInfo() (*OS, error) { result.Name = productName result.Version = fmt.Sprintf("%s (Build: %s)", releaseId, currentBuild) result.ID = displayVersion - result.Branding = getBranding() return &result, key.Close() } diff --git a/v2/internal/system/operatingsystem/version_windows.go b/v2/internal/system/operatingsystem/version_windows.go deleted file mode 100644 index a8f53d134..000000000 --- a/v2/internal/system/operatingsystem/version_windows.go +++ /dev/null @@ -1,62 +0,0 @@ -//go:build windows - -package operatingsystem - -import ( - "strconv" - - "golang.org/x/sys/windows/registry" -) - -type WindowsVersionInfo struct { - Major int - Minor int - Build int - DisplayVersion string -} - -func (w *WindowsVersionInfo) IsWindowsVersionAtLeast(major, minor, buildNumber int) bool { - return w.Major >= major && w.Minor >= minor && w.Build >= buildNumber -} - -func GetWindowsVersionInfo() (*WindowsVersionInfo, error) { - key, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE) - if err != nil { - return nil, err - } - - return &WindowsVersionInfo{ - Major: regDWORDKeyAsInt(key, "CurrentMajorVersionNumber"), - Minor: regDWORDKeyAsInt(key, "CurrentMinorVersionNumber"), - Build: regStringKeyAsInt(key, "CurrentBuildNumber"), - DisplayVersion: regKeyAsString(key, "DisplayVersion"), - }, nil -} - -func regDWORDKeyAsInt(key registry.Key, name string) int { - result, _, err := key.GetIntegerValue(name) - if err != nil { - return -1 - } - return int(result) -} - -func regStringKeyAsInt(key registry.Key, name string) int { - resultStr, _, err := key.GetStringValue(name) - if err != nil { - return -1 - } - result, err := strconv.Atoi(resultStr) - if err != nil { - return -1 - } - return result -} - -func regKeyAsString(key registry.Key, name string) string { - resultStr, _, err := key.GetStringValue(name) - if err != nil { - return "" - } - return resultStr -} diff --git a/v2/internal/system/packagemanager/apt.go b/v2/internal/system/packagemanager/apt.go index 806d08f2d..cc37e55bb 100644 --- a/v2/internal/system/packagemanager/apt.go +++ b/v2/internal/system/packagemanager/apt.go @@ -1,12 +1,8 @@ -//go:build linux // +build linux package packagemanager import ( - "bytes" - "os" - "os/exec" "regexp" "strings" @@ -49,9 +45,6 @@ func (a *Apt) Packages() packagemap { "docker": []*Package{ {Name: "docker.io", SystemPackage: true, Optional: true}, }, - "nsis": []*Package{ - {Name: "nsis", SystemPackage: true, Optional: true}, - }, } } @@ -65,13 +58,8 @@ func (a *Apt) PackageInstalled(pkg *Package) (bool, error) { if pkg.SystemPackage == false { return false, nil } - cmd := exec.Command("apt", "list", "-qq", pkg.Name) - var stdo, stde bytes.Buffer - cmd.Stdout = &stdo - cmd.Stderr = &stde - cmd.Env = append(os.Environ(), "LANGUAGE=en") - err := cmd.Run() - return strings.Contains(stdo.String(), "[installed]"), err + stdout, _, err := shell.RunCommand(".", "apt", "-qq", "list", pkg.Name) + return strings.Contains(stdout, "[installed]"), err } // PackageAvailable tests if the given package is available for installation @@ -79,7 +67,7 @@ func (a *Apt) PackageAvailable(pkg *Package) (bool, error) { if pkg.SystemPackage == false { return false, nil } - stdout, _, err := shell.RunCommand(".", "apt", "list", "-qq", pkg.Name) + stdout, _, err := shell.RunCommand(".", "apt", "-qq", "list", pkg.Name) // We add a space to ensure we get a full match, not partial match output := a.removeEscapeSequences(stdout) installed := strings.HasPrefix(output, pkg.Name) diff --git a/v2/internal/system/packagemanager/dnf.go b/v2/internal/system/packagemanager/dnf.go index fec676f11..b7a760f2c 100644 --- a/v2/internal/system/packagemanager/dnf.go +++ b/v2/internal/system/packagemanager/dnf.go @@ -1,4 +1,3 @@ -//go:build linux // +build linux package packagemanager @@ -32,7 +31,6 @@ func (y *Dnf) Packages() packagemap { {Name: "gtk3-devel", SystemPackage: true, Library: true}, }, "libwebkit": []*Package{ - {Name: "webkit2gtk4.0-devel", SystemPackage: true, Library: true}, {Name: "webkit2gtk3-devel", SystemPackage: true, Library: true}, // {Name: "webkitgtk3-devel", SystemPackage: true, Library: true}, }, @@ -44,7 +42,6 @@ func (y *Dnf) Packages() packagemap { }, "npm": []*Package{ {Name: "npm", SystemPackage: true}, - {Name: "nodejs-npm", SystemPackage: true}, }, "upx": []*Package{ {Name: "upx", SystemPackage: true, Optional: true}, @@ -58,7 +55,6 @@ func (y *Dnf) Packages() packagemap { "fedora": "Follow the guide: https://docs.docker.com/engine/install/fedora/", }, }, - {Name: "moby-engine", SystemPackage: true, Optional: true}, }, } } diff --git a/v2/internal/system/packagemanager/emerge.go b/v2/internal/system/packagemanager/emerge.go index 7497d580a..0caa3117c 100644 --- a/v2/internal/system/packagemanager/emerge.go +++ b/v2/internal/system/packagemanager/emerge.go @@ -1,4 +1,3 @@ -//go:build linux // +build linux package packagemanager diff --git a/v2/internal/system/packagemanager/eopkg.go b/v2/internal/system/packagemanager/eopkg.go index 936127eac..6a7a8fd95 100644 --- a/v2/internal/system/packagemanager/eopkg.go +++ b/v2/internal/system/packagemanager/eopkg.go @@ -1,4 +1,3 @@ -//go:build linux // +build linux package packagemanager @@ -40,7 +39,7 @@ func (e *Eopkg) Packages() packagemap { {Name: "gcc", SystemPackage: true}, }, "pkg-config": []*Package{ - {Name: "pkgconf", SystemPackage: true}, + {Name: "pkg-config", SystemPackage: true}, }, "npm": []*Package{ {Name: "nodejs", SystemPackage: true}, diff --git a/v2/internal/system/packagemanager/nixpkgs.go b/v2/internal/system/packagemanager/nixpkgs.go deleted file mode 100644 index 360473d24..000000000 --- a/v2/internal/system/packagemanager/nixpkgs.go +++ /dev/null @@ -1,159 +0,0 @@ -//go:build linux -// +build linux - -package packagemanager - -import ( - "encoding/json" - "github.com/wailsapp/wails/v2/internal/shell" -) - -// Nixpkgs represents the Nixpkgs manager -type Nixpkgs struct { - name string - osid string -} - -type NixPackageDetail struct { - Name string - Pname string - Version string -} - -var available map[string]NixPackageDetail - -// NewNixpkgs creates a new Nixpkgs instance -func NewNixpkgs(osid string) *Nixpkgs { - available = map[string]NixPackageDetail{} - - return &Nixpkgs{ - name: "nixpkgs", - osid: osid, - } -} - -// Packages returns the libraries that we need for Wails to compile -// They will potentially differ on different distributions or versions -func (n *Nixpkgs) Packages() packagemap { - // Currently, only support checking the default channel. - channel := "nixpkgs" - if n.osid == "nixos" { - channel = "nixos" - } - - return packagemap{ - "libgtk-3": []*Package{ - {Name: channel + ".gtk3", SystemPackage: true, Library: true}, - }, - "libwebkit": []*Package{ - {Name: channel + ".webkitgtk", SystemPackage: true, Library: true}, - }, - "gcc": []*Package{ - {Name: channel + ".gcc", SystemPackage: true}, - }, - "pkg-config": []*Package{ - {Name: channel + ".pkg-config", SystemPackage: true}, - }, - "npm": []*Package{ - {Name: channel + ".nodejs", SystemPackage: true}, - }, - "upx": []*Package{ - {Name: channel + ".upx", SystemPackage: true, Optional: true}, - }, - "docker": []*Package{ - {Name: channel + ".docker", SystemPackage: true, Optional: true}, - }, - "nsis": []*Package{ - {Name: channel + ".nsis", SystemPackage: true, Optional: true}, - }, - } -} - -// Name returns the name of the package manager -func (n *Nixpkgs) Name() string { - return n.name -} - -// PackageInstalled tests if the given package name is installed -func (n *Nixpkgs) PackageInstalled(pkg *Package) (bool, error) { - if pkg.SystemPackage == false { - return false, nil - } - - stdout, _, err := shell.RunCommand(".", "nix-env", "--json", "-qA", pkg.Name) - if err != nil { - return false, nil - } - - var attributes map[string]NixPackageDetail - err = json.Unmarshal([]byte(stdout), &attributes) - if err != nil { - return false, err - } - - // Did we get one? - installed := false - for attribute, detail := range attributes { - if attribute == pkg.Name { - installed = true - pkg.Version = detail.Version - } - break - } - - // If on NixOS, package may be installed via system config, so check the nix store. - detail, ok := available[pkg.Name] - if !installed && n.osid == "nixos" && ok { - cmd := "nix-store --query --requisites /run/current-system | cut -d- -f2- | sort | uniq | grep '^" + detail.Pname + "'" - - if pkg.Library { - cmd += " | grep 'dev$'" - } - - stdout, _, err = shell.RunCommand(".", "sh", "-c", cmd) - if err != nil { - return false, nil - } - - if len(stdout) > 0 { - installed = true - } - } - - return installed, nil -} - -// PackageAvailable tests if the given package is available for installation -func (n *Nixpkgs) PackageAvailable(pkg *Package) (bool, error) { - if pkg.SystemPackage == false { - return false, nil - } - - stdout, _, err := shell.RunCommand(".", "nix-env", "--json", "-qaA", pkg.Name) - if err != nil { - return false, nil - } - - var attributes map[string]NixPackageDetail - err = json.Unmarshal([]byte(stdout), &attributes) - if err != nil { - return false, err - } - - // Grab first version. - for attribute, detail := range attributes { - pkg.Version = detail.Version - available[attribute] = detail - break - } - - return len(pkg.Version) > 0, nil -} - -// InstallCommand returns the package manager specific command to install a package -func (n *Nixpkgs) InstallCommand(pkg *Package) string { - if pkg.SystemPackage == false { - return pkg.InstallCommand[n.osid] - } - return "nix-env -iA " + pkg.Name -} diff --git a/v2/internal/system/packagemanager/packagemanager.go b/v2/internal/system/packagemanager/packagemanager.go index 043c8e3cf..7e15594aa 100644 --- a/v2/internal/system/packagemanager/packagemanager.go +++ b/v2/internal/system/packagemanager/packagemanager.go @@ -1,4 +1,3 @@ -//go:build linux // +build linux package packagemanager @@ -18,7 +17,6 @@ var pmcommands = []string{ "pacman", "emerge", "zypper", - "nix-env", } // Find will attempt to find the system package manager @@ -47,21 +45,19 @@ func newPackageManager(pmname string, osid string) PackageManager { return NewEmerge(osid) case "zypper": return NewZypper(osid) - case "nix-env": - return NewNixpkgs(osid) } return nil } -// Dependencies scans the system for required dependencies -// Returns a list of dependencies search for, whether they were found +// Dependancies scans the system for required dependancies +// Returns a list of dependancies search for, whether they were found // and whether they were installed -func Dependencies(p PackageManager) (DependencyList, error) { +func Dependancies(p PackageManager) (DependencyList, error) { var dependencies DependencyList for name, packages := range p.Packages() { - dependency := &Dependency{Name: name} + dependency := &Dependancy{Name: name} for _, pkg := range packages { dependency.Optional = pkg.Optional dependency.External = !pkg.SystemPackage diff --git a/v2/internal/system/packagemanager/pacman.go b/v2/internal/system/packagemanager/pacman.go index 1fbecf781..6378c324d 100644 --- a/v2/internal/system/packagemanager/pacman.go +++ b/v2/internal/system/packagemanager/pacman.go @@ -1,4 +1,3 @@ -//go:build linux // +build linux package packagemanager diff --git a/v2/internal/system/packagemanager/pm.go b/v2/internal/system/packagemanager/pm.go index bba45cd05..c66d0d364 100644 --- a/v2/internal/system/packagemanager/pm.go +++ b/v2/internal/system/packagemanager/pm.go @@ -16,13 +16,13 @@ type packagemap = map[string][]*Package type PackageManager interface { Name() string Packages() packagemap - PackageInstalled(pkg *Package) (bool, error) - PackageAvailable(pkg *Package) (bool, error) - InstallCommand(pkg *Package) string + PackageInstalled(*Package) (bool, error) + PackageAvailable(*Package) (bool, error) + InstallCommand(*Package) string } -// Dependency represents a system package that we require -type Dependency struct { +// Dependancy represents a system package that we require +type Dependancy struct { Name string PackageName string Installed bool @@ -33,10 +33,11 @@ type Dependency struct { } // DependencyList is a list of Dependency instances -type DependencyList []*Dependency +type DependencyList []*Dependancy // InstallAllRequiredCommand returns the command you need to use to install all required dependencies func (d DependencyList) InstallAllRequiredCommand() string { + result := "" for _, dependency := range d { if !dependency.Installed && !dependency.Optional { @@ -49,6 +50,7 @@ func (d DependencyList) InstallAllRequiredCommand() string { // InstallAllOptionalCommand returns the command you need to use to install all optional dependencies func (d DependencyList) InstallAllOptionalCommand() string { + result := "" for _, dependency := range d { if !dependency.Installed && dependency.Optional { diff --git a/v2/internal/system/packagemanager/zypper.go b/v2/internal/system/packagemanager/zypper.go index efaeb0b1b..af9d2e3d1 100644 --- a/v2/internal/system/packagemanager/zypper.go +++ b/v2/internal/system/packagemanager/zypper.go @@ -1,4 +1,3 @@ -//go:build linux // +build linux package packagemanager @@ -33,7 +32,6 @@ func (z *Zypper) Packages() packagemap { {Name: "gtk3-devel", SystemPackage: true, Library: true}, }, "libwebkit": []*Package{ - {Name: "webkit2gtk3-soup2-devel", SystemPackage: true, Library: true}, {Name: "webkit2gtk3-devel", SystemPackage: true, Library: true}, }, "gcc": []*Package{ @@ -41,11 +39,9 @@ func (z *Zypper) Packages() packagemap { }, "pkg-config": []*Package{ {Name: "pkg-config", SystemPackage: true}, - {Name: "pkgconf-pkg-config", SystemPackage: true}, }, "npm": []*Package{ {Name: "npm10", SystemPackage: true}, - {Name: "npm20", SystemPackage: true}, }, "docker": []*Package{ {Name: "docker", SystemPackage: true, Optional: true}, @@ -63,9 +59,7 @@ func (z *Zypper) PackageInstalled(pkg *Package) (bool, error) { if pkg.SystemPackage == false { return false, nil } - var env []string - env = shell.SetEnv(env, "LANGUAGE", "en_US.utf-8") - stdout, _, err := shell.RunCommandWithEnv(env, ".", "zypper", "info", pkg.Name) + stdout, _, err := shell.RunCommand(".", "zypper", "info", pkg.Name) if err != nil { _, ok := err.(*exec.ExitError) if ok { @@ -88,9 +82,7 @@ func (z *Zypper) PackageAvailable(pkg *Package) (bool, error) { if pkg.SystemPackage == false { return false, nil } - var env []string - env = shell.SetEnv(env, "LANGUAGE", "en_US.utf-8") - stdout, _, err := shell.RunCommandWithEnv(env, ".", "zypper", "info", pkg.Name) + stdout, _, err := shell.RunCommand(".", "zypper", "info", pkg.Name) // We add a space to ensure we get a full match, not partial match if err != nil { _, ok := err.(*exec.ExitError) diff --git a/v2/internal/system/system.go b/v2/internal/system/system.go index 67453538f..9d7650622 100644 --- a/v2/internal/system/system.go +++ b/v2/internal/system/system.go @@ -1,18 +1,18 @@ package system import ( - "os/exec" - "strings" - - "github.com/wailsapp/wails/v2/internal/shell" "github.com/wailsapp/wails/v2/internal/system/operatingsystem" "github.com/wailsapp/wails/v2/internal/system/packagemanager" + "os/exec" + "strings" ) -var IsAppleSilicon bool +var ( + IsAppleSilicon bool +) // Info holds information about the current operating system, -// package manager and required dependencies +// package manager and required dependancies type Info struct { OS *operatingsystem.OS PM packagemanager.PackageManager @@ -21,7 +21,7 @@ type Info struct { // GetInfo scans the system for operating system details, // the system package manager and the status of required -// dependencies. +// dependancies. func GetInfo() (*Info, error) { var result Info err := result.discover() @@ -31,30 +31,8 @@ func GetInfo() (*Info, error) { return &result, nil } -func checkNodejs() *packagemanager.Dependency { - // Check for Nodejs - output, err := exec.Command("node", "-v").Output() - installed := true - version := "" - if err != nil { - installed = false - } else { - if len(output) > 0 { - version = strings.TrimSpace(strings.Split(string(output), "\n")[0])[1:] - } - } - return &packagemanager.Dependency{ - Name: "Nodejs", - PackageName: "N/A", - Installed: installed, - InstallCommand: "Available at https://nodejs.org/en/download/", - Version: version, - Optional: false, - External: false, - } -} +func checkNPM() *packagemanager.Dependancy { -func checkNPM() *packagemanager.Dependency { // Check for npm output, err := exec.Command("npm", "-version").Output() installed := true @@ -64,7 +42,7 @@ func checkNPM() *packagemanager.Dependency { } else { version = strings.TrimSpace(strings.Split(string(output), "\n")[0]) } - return &packagemanager.Dependency{ + return &packagemanager.Dependancy{ Name: "npm ", PackageName: "N/A", Installed: installed, @@ -75,7 +53,8 @@ func checkNPM() *packagemanager.Dependency { } } -func checkUPX() *packagemanager.Dependency { +func checkUPX() *packagemanager.Dependancy { + // Check for npm output, err := exec.Command("upx", "-V").Output() installed := true @@ -85,7 +64,7 @@ func checkUPX() *packagemanager.Dependency { } else { version = strings.TrimSpace(strings.Split(string(output), "\n")[0]) } - return &packagemanager.Dependency{ + return &packagemanager.Dependancy{ Name: "upx ", PackageName: "N/A", Installed: installed, @@ -96,45 +75,8 @@ func checkUPX() *packagemanager.Dependency { } } -func checkNSIS() *packagemanager.Dependency { - // Check for nsis installer - output, err := exec.Command("makensis", "-VERSION").Output() - installed := true - version := "" - if err != nil { - installed = false - } else { - version = strings.TrimSpace(strings.Split(string(output), "\n")[0]) - } - return &packagemanager.Dependency{ - Name: "nsis ", - PackageName: "N/A", - Installed: installed, - InstallCommand: "More info at https://wails.io/docs/guides/windows-installer/", - Version: version, - Optional: true, - External: false, - } -} +func checkDocker() *packagemanager.Dependancy { -func checkLibrary(name string) func() *packagemanager.Dependency { - return func() *packagemanager.Dependency { - output, _, _ := shell.RunCommand(".", "pkg-config", "--cflags", name) - installed := len(strings.TrimSpace(output)) > 0 - - return &packagemanager.Dependency{ - Name: "lib" + name + " ", - PackageName: "N/A", - Installed: installed, - InstallCommand: "Install via your package manager", - Version: "N/A", - Optional: false, - External: false, - } - } -} - -func checkDocker() *packagemanager.Dependency { // Check for npm output, err := exec.Command("docker", "version").Output() installed := true @@ -157,7 +99,7 @@ func checkDocker() *packagemanager.Dependency { } } } - return &packagemanager.Dependency{ + return &packagemanager.Dependancy{ Name: "docker ", PackageName: "N/A", Installed: installed, diff --git a/v2/internal/system/system_darwin.go b/v2/internal/system/system_darwin.go index 16dfd8873..671c6bd76 100644 --- a/v2/internal/system/system_darwin.go +++ b/v2/internal/system/system_darwin.go @@ -4,13 +4,12 @@ package system import ( - "fmt" + "github.com/wailsapp/wails/v2/internal/system/packagemanager" "os/exec" "strings" "syscall" "github.com/wailsapp/wails/v2/internal/system/operatingsystem" - "github.com/wailsapp/wails/v2/internal/system/packagemanager" ) // Determine if the app is running on Apple Silicon @@ -32,16 +31,6 @@ func (i *Info) discover() error { } i.OS = osinfo - i.Dependencies = append(i.Dependencies, checkXCodeSelect()) - i.Dependencies = append(i.Dependencies, checkNodejs()) - i.Dependencies = append(i.Dependencies, checkNPM()) - i.Dependencies = append(i.Dependencies, checkXCodeBuild()) - i.Dependencies = append(i.Dependencies, checkUPX()) - i.Dependencies = append(i.Dependencies, checkNSIS()) - return nil -} - -func checkXCodeSelect() *packagemanager.Dependency { // Check for xcode command line tools output, err := exec.Command("xcode-select", "-v").Output() installed := true @@ -53,8 +42,8 @@ func checkXCodeSelect() *packagemanager.Dependency { version = strings.TrimSpace(version) version = strings.TrimSuffix(version, ".") } - return &packagemanager.Dependency{ - Name: "Xcode command line tools ", + xcodeDep := &packagemanager.Dependancy{ + Name: "xcode command line tools ", PackageName: "N/A", Installed: installed, InstallCommand: "xcode-select --install", @@ -62,30 +51,8 @@ func checkXCodeSelect() *packagemanager.Dependency { Optional: false, External: false, } -} - -func checkXCodeBuild() *packagemanager.Dependency { - // Check for xcode - output, err := exec.Command("xcodebuild", "-version").Output() - installed := true - version := "" - if err != nil { - installed = false - } else if l := strings.Split(string(output), "\n"); len(l) >= 2 { - version = fmt.Sprintf("%s (%s)", - strings.TrimPrefix(l[0], "Xcode "), - strings.TrimPrefix(l[1], "Build version ")) - } else { - version = "N/A" - } - - return &packagemanager.Dependency{ - Name: "Xcode", - PackageName: "N/A", - Installed: installed, - InstallCommand: "Available at https://apps.apple.com/us/app/xcode/id497799835", - Version: version, - Optional: true, - External: false, - } + i.Dependencies = append(i.Dependencies, xcodeDep) + i.Dependencies = append(i.Dependencies, checkNPM()) + i.Dependencies = append(i.Dependencies, checkUPX()) + return nil } diff --git a/v2/internal/system/system_linux.go b/v2/internal/system/system_linux.go index 703e978eb..5a08d96b7 100644 --- a/v2/internal/system/system_linux.go +++ b/v2/internal/system/system_linux.go @@ -8,57 +8,6 @@ import ( "github.com/wailsapp/wails/v2/internal/system/packagemanager" ) -func checkGCC() *packagemanager.Dependency { - - version := packagemanager.AppVersion("gcc") - - return &packagemanager.Dependency{ - Name: "gcc ", - PackageName: "N/A", - Installed: version != "", - InstallCommand: "Install via your package manager", - Version: version, - Optional: false, - External: false, - } -} - -func checkPkgConfig() *packagemanager.Dependency { - - version := packagemanager.AppVersion("pkg-config") - - return &packagemanager.Dependency{ - Name: "pkg-config ", - PackageName: "N/A", - Installed: version != "", - InstallCommand: "Install via your package manager", - Version: version, - Optional: false, - External: false, - } -} - -func checkLocallyInstalled(checker func() *packagemanager.Dependency, dependency *packagemanager.Dependency) { - if !dependency.Installed { - locallyInstalled := checker() - if locallyInstalled.Installed { - dependency.Installed = true - dependency.Version = locallyInstalled.Version - } - } -} - -var checkerFunctions = map[string]func() *packagemanager.Dependency{ - "Nodejs": checkNodejs, - "npm": checkNPM, - "docker": checkDocker, - "upx": checkUPX, - "gcc": checkGCC, - "pkg-config": checkPkgConfig, - "libgtk-3": checkLibrary("libgtk-3"), - "libwebkit": checkLibrary("libwebkit"), -} - func (i *Info) discover() error { var err error @@ -70,23 +19,10 @@ func (i *Info) discover() error { i.PM = packagemanager.Find(osinfo.ID) if i.PM != nil { - dependencies, err := packagemanager.Dependencies(i.PM) + dependencies, err := packagemanager.Dependancies(i.PM) if err != nil { return err } - for _, dep := range dependencies { - checker := checkerFunctions[dep.Name] - if checker != nil { - checkLocallyInstalled(checker, dep) - } - if dep.Name == "nsis" { - locallyInstalled := checkNSIS() - if locallyInstalled.Installed { - dep.Installed = true - dep.Version = locallyInstalled.Version - } - } - } i.Dependencies = dependencies } diff --git a/v2/internal/system/system_windows.go b/v2/internal/system/system_windows.go index 40b8f0340..94c3b23a2 100644 --- a/v2/internal/system/system_windows.go +++ b/v2/internal/system/system_windows.go @@ -4,7 +4,7 @@ package system import ( - "github.com/wailsapp/go-webview2/webviewloader" + "github.com/leaanthony/webview2runtime" "github.com/wailsapp/wails/v2/internal/system/operatingsystem" "github.com/wailsapp/wails/v2/internal/system/packagemanager" ) @@ -19,20 +19,23 @@ func (i *Info) discover() error { i.OS = osinfo i.Dependencies = append(i.Dependencies, checkWebView2()) - i.Dependencies = append(i.Dependencies, checkNodejs()) i.Dependencies = append(i.Dependencies, checkNPM()) i.Dependencies = append(i.Dependencies, checkUPX()) - i.Dependencies = append(i.Dependencies, checkNSIS()) - // i.Dependencies = append(i.Dependencies, checkDocker()) + //i.Dependencies = append(i.Dependencies, checkDocker()) return nil } -func checkWebView2() *packagemanager.Dependency { - version, _ := webviewloader.GetAvailableCoreWebView2BrowserVersionString("") +func checkWebView2() *packagemanager.Dependancy { + + info := webview2runtime.GetInstalledVersion() + version := "" + if info != nil { + version = info.Version + } installed := version != "" - return &packagemanager.Dependency{ + return &packagemanager.Dependancy{ Name: "WebView2 ", PackageName: "N/A", Installed: installed, diff --git a/v2/internal/typescriptify/README.md b/v2/internal/typescriptify/README.md deleted file mode 100644 index b5c961835..000000000 --- a/v2/internal/typescriptify/README.md +++ /dev/null @@ -1,2 +0,0 @@ -Based on: https://github.com/tkrajina/typescriptify-golang-structs -License: LICENSE.txt \ No newline at end of file diff --git a/v2/internal/typescriptify/js-reserved-keywords.go b/v2/internal/typescriptify/js-reserved-keywords.go deleted file mode 100644 index 4f9aa09f4..000000000 --- a/v2/internal/typescriptify/js-reserved-keywords.go +++ /dev/null @@ -1,69 +0,0 @@ -package typescriptify - -var jsReservedKeywords []string = []string{ - "abstract", - "arguments", - "await", - "boolean", - "break", - "byte", - "case", - "catch", - "char", - "class", - "const", - "continue", - "debugger", - "default", - "delete", - "do", - "double", - "else", - "enum", - "eval", - "export", - "extends", - "false", - "final", - "finally", - "float", - "for", - "function", - "goto", - "if", - "implements", - "import", - "in", - "instanceof", - "int", - "interface", - "let", - "long", - "native", - "new", - "null", - "package", - "private", - "protected", - "public", - "return", - "short", - "static", - "super", - "switch", - "synchronized", - "this", - "throw", - "throws", - "transient", - "true", - "try", - "typeof", - "var", - "void", - "volatile", - "while", - "with", - "yield", - "object", -} diff --git a/v2/internal/typescriptify/typescriptify.go b/v2/internal/typescriptify/typescriptify.go deleted file mode 100644 index e732c5976..000000000 --- a/v2/internal/typescriptify/typescriptify.go +++ /dev/null @@ -1,1011 +0,0 @@ -package typescriptify - -import ( - "bufio" - "cmp" - "fmt" - "io" - "log" - "os" - "path" - "reflect" - "regexp" - "slices" - "strings" - "time" - - "github.com/leaanthony/slicer" - - "github.com/tkrajina/go-reflector/reflector" -) - -const ( - tsTransformTag = "ts_transform" - tsType = "ts_type" - tsConvertValuesFunc = `convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; -}` - jsVariableNameRegex = `^([A-Z]|[a-z]|\$|_)([A-Z]|[a-z]|[0-9]|\$|_)*$` -) - -var jsVariableUnsafeChars = regexp.MustCompile(`[^A-Za-z0-9_]`) - -func nameTypeOf(typeOf reflect.Type) string { - tname := typeOf.Name() - gidx := strings.IndexRune(tname, '[') - if gidx > 0 { // its a generic type - rem := strings.SplitN(tname, "[", 2) - tname = rem[0] + "_" + jsVariableUnsafeChars.ReplaceAllLiteralString(rem[1], "_") - } - return tname -} - -// TypeOptions overrides options set by `ts_*` tags. -type TypeOptions struct { - TSType string - TSTransform string -} - -// StructType stores settings for transforming one Golang struct. -type StructType struct { - Type reflect.Type - FieldOptions map[reflect.Type]TypeOptions -} - -func NewStruct(i interface{}) *StructType { - return &StructType{ - Type: reflect.TypeOf(i), - } -} - -func (st *StructType) WithFieldOpts(i interface{}, opts TypeOptions) *StructType { - if st.FieldOptions == nil { - st.FieldOptions = map[reflect.Type]TypeOptions{} - } - var typ reflect.Type - if ty, is := i.(reflect.Type); is { - typ = ty - } else { - typ = reflect.TypeOf(i) - } - st.FieldOptions[typ] = opts - return st -} - -type EnumType struct { - Type reflect.Type -} - -type enumElement struct { - value interface{} - name string -} - -type TypeScriptify struct { - Prefix string - Suffix string - Indent string - CreateFromMethod bool - CreateConstructor bool - BackupDir string // If empty no backup - DontExport bool - CreateInterface bool - customImports []string - - structTypes []StructType - enumTypes []EnumType - enums map[reflect.Type][]enumElement - kinds map[reflect.Kind]string - - fieldTypeOptions map[reflect.Type]TypeOptions - - // throwaway, used when converting - alreadyConverted map[string]bool - - Namespace string - KnownStructs *slicer.StringSlicer - KnownEnums *slicer.StringSlicer -} - -func New() *TypeScriptify { - result := new(TypeScriptify) - result.Indent = "\t" - result.BackupDir = "." - - kinds := make(map[reflect.Kind]string) - - kinds[reflect.Bool] = "boolean" - kinds[reflect.Interface] = "any" - - kinds[reflect.Int] = "number" - kinds[reflect.Int8] = "number" - kinds[reflect.Int16] = "number" - kinds[reflect.Int32] = "number" - kinds[reflect.Int64] = "number" - kinds[reflect.Uint] = "number" - kinds[reflect.Uint8] = "number" - kinds[reflect.Uint16] = "number" - kinds[reflect.Uint32] = "number" - kinds[reflect.Uint64] = "number" - kinds[reflect.Float32] = "number" - kinds[reflect.Float64] = "number" - - kinds[reflect.String] = "string" - - result.kinds = kinds - - result.Indent = " " - result.CreateFromMethod = true - result.CreateConstructor = true - - return result -} - -func (t *TypeScriptify) deepFields(typeOf reflect.Type) []reflect.StructField { - fields := make([]reflect.StructField, 0) - - if typeOf.Kind() == reflect.Ptr { - typeOf = typeOf.Elem() - } - - if typeOf.Kind() != reflect.Struct { - return fields - } - - for i := 0; i < typeOf.NumField(); i++ { - f := typeOf.Field(i) - kind := f.Type.Kind() - isPointer := kind == reflect.Ptr && f.Type.Elem().Kind() == reflect.Struct - if f.Anonymous && kind == reflect.Struct { - // fmt.Println(v.Interface()) - fields = append(fields, t.deepFields(f.Type)...) - } else if f.Anonymous && isPointer { - // fmt.Println(v.Interface()) - fields = append(fields, t.deepFields(f.Type.Elem())...) - } else { - // Check we have a json tag - jsonTag := t.getJSONFieldName(f, isPointer) - if jsonTag != "" { - fields = append(fields, f) - } - } - } - - return fields -} - -func (ts TypeScriptify) logf(depth int, s string, args ...interface{}) { - fmt.Printf(strings.Repeat(" ", depth)+s+"\n", args...) -} - -// ManageType can define custom options for fields of a specified type. -// -// This can be used instead of setting ts_type and ts_transform for all fields of a certain type. -func (t *TypeScriptify) ManageType(fld interface{}, opts TypeOptions) *TypeScriptify { - var typ reflect.Type - switch t := fld.(type) { - case reflect.Type: - typ = t - default: - typ = reflect.TypeOf(fld) - } - if t.fieldTypeOptions == nil { - t.fieldTypeOptions = map[reflect.Type]TypeOptions{} - } - t.fieldTypeOptions[typ] = opts - return t -} - -func (t *TypeScriptify) GetGeneratedStructs() []string { - var result []string - for key := range t.alreadyConverted { - result = append(result, key) - } - return result -} - -func (t *TypeScriptify) WithCreateFromMethod(b bool) *TypeScriptify { - t.CreateFromMethod = b - return t -} - -func (t *TypeScriptify) WithInterface(b bool) *TypeScriptify { - t.CreateInterface = b - return t -} - -func (t *TypeScriptify) WithConstructor(b bool) *TypeScriptify { - t.CreateConstructor = b - return t -} - -func (t *TypeScriptify) WithIndent(i string) *TypeScriptify { - t.Indent = i - return t -} - -func (t *TypeScriptify) WithBackupDir(b string) *TypeScriptify { - t.BackupDir = b - return t -} - -func (t *TypeScriptify) WithPrefix(p string) *TypeScriptify { - t.Prefix = p - return t -} - -func (t *TypeScriptify) WithSuffix(s string) *TypeScriptify { - t.Suffix = s - return t -} - -func (t *TypeScriptify) Add(obj interface{}) *TypeScriptify { - switch ty := obj.(type) { - case StructType: - t.structTypes = append(t.structTypes, ty) - case *StructType: - t.structTypes = append(t.structTypes, *ty) - case reflect.Type: - t.AddType(ty) - default: - t.AddType(reflect.TypeOf(obj)) - } - return t -} - -func (t *TypeScriptify) AddType(typeOf reflect.Type) *TypeScriptify { - t.structTypes = append(t.structTypes, StructType{Type: typeOf}) - return t -} - -func (t *typeScriptClassBuilder) AddMapField(fieldName string, field reflect.StructField) { - keyType := field.Type.Key() - valueType := field.Type.Elem() - valueTypeName := nameTypeOf(valueType) - valueTypeSuffix := "" - valueTypePrefix := "" - if valueType.Kind() == reflect.Ptr { - valueType = valueType.Elem() - valueTypeName = nameTypeOf(valueType) - } - if valueType.Kind() == reflect.Array || valueType.Kind() == reflect.Slice { - arrayDepth := 1 - for valueType.Elem().Kind() == reflect.Array || valueType.Elem().Kind() == reflect.Slice { - valueType = valueType.Elem() - arrayDepth++ - } - valueType = valueType.Elem() - valueTypeName = nameTypeOf(valueType) - valueTypeSuffix = strings.Repeat(">", arrayDepth) - valueTypePrefix = strings.Repeat("Array<", arrayDepth) - } - if valueType.Kind() == reflect.Ptr { - valueType = valueType.Elem() - valueTypeName = nameTypeOf(valueType) - } - if name, ok := t.types[valueType.Kind()]; ok { - valueTypeName = name - } - if valueType.Kind() == reflect.Map { - // TODO: support nested maps - valueTypeName = "any" // valueType.Elem().Name() - } - if valueType.Kind() == reflect.Struct && differentNamespaces(t.namespace, valueType) { - valueTypeName = valueType.String() - } - strippedFieldName := strings.ReplaceAll(fieldName, "?", "") - isOptional := strings.HasSuffix(fieldName, "?") - - keyTypeStr := "" - // Key should always be a JS primitive. JS will read it as a string either way. - if typeStr, isSimple := t.types[keyType.Kind()]; isSimple { - keyTypeStr = typeStr - } else { - keyTypeStr = t.types[reflect.String] - } - - var dotField string - if regexp.MustCompile(jsVariableNameRegex).Match([]byte(strippedFieldName)) { - dotField = fmt.Sprintf(".%s", strippedFieldName) - } else { - dotField = fmt.Sprintf(`["%s"]`, strippedFieldName) - if isOptional { - fieldName = fmt.Sprintf(`"%s"?`, strippedFieldName) - } - } - t.fields = append(t.fields, fmt.Sprintf("%s%s: Record<%s, %s>;", t.indent, fieldName, keyTypeStr, valueTypePrefix+valueTypeName+valueTypeSuffix)) - if valueType.Kind() == reflect.Struct { - t.constructorBody = append(t.constructorBody, fmt.Sprintf("%s%sthis%s = this.convertValues(source[\"%s\"], %s, true);", - t.indent, t.indent, dotField, strippedFieldName, t.prefix+valueTypePrefix+valueTypeName+valueTypeSuffix+t.suffix)) - } else { - t.constructorBody = append(t.constructorBody, fmt.Sprintf("%s%sthis%s = source[\"%s\"];", - t.indent, t.indent, dotField, strippedFieldName)) - } -} - -func (t *TypeScriptify) AddEnum(values interface{}) *TypeScriptify { - if t.enums == nil { - t.enums = map[reflect.Type][]enumElement{} - } - items := reflect.ValueOf(values) - if items.Kind() != reflect.Slice { - panic(fmt.Sprintf("Values for %T isn't a slice", values)) - } - - var elements []enumElement - for i := 0; i < items.Len(); i++ { - item := items.Index(i) - - var el enumElement - if item.Kind() == reflect.Struct { - r := reflector.New(item.Interface()) - val, err := r.Field("Value").Get() - if err != nil { - panic(fmt.Sprint("missing Type field in ", item.Type().String())) - } - name, err := r.Field("TSName").Get() - if err != nil { - panic(fmt.Sprint("missing TSName field in ", item.Type().String())) - } - el.value = val - el.name = name.(string) - } else { - el.value = item.Interface() - if tsNamer, is := item.Interface().(TSNamer); is { - el.name = tsNamer.TSName() - } else { - panic(fmt.Sprint(item.Type().String(), " has no TSName method")) - } - } - - elements = append(elements, el) - } - slices.SortFunc(elements, func(a, b enumElement) int { - return cmp.Compare(a.name, b.name) - }) - ty := reflect.TypeOf(elements[0].value) - t.enums[ty] = elements - t.enumTypes = append(t.enumTypes, EnumType{Type: ty}) - - return t -} - -// AddEnumValues is deprecated, use `AddEnum()` -func (t *TypeScriptify) AddEnumValues(typeOf reflect.Type, values interface{}) *TypeScriptify { - t.AddEnum(values) - return t -} - -func (t *TypeScriptify) Convert(customCode map[string]string) (string, error) { - t.alreadyConverted = make(map[string]bool) - depth := 0 - - result := "" - if len(t.customImports) > 0 { - // Put the custom imports, i.e.: `import Decimal from 'decimal.js'` - for _, cimport := range t.customImports { - result += cimport + "\n" - } - } - - for _, enumTyp := range t.enumTypes { - elements := t.enums[enumTyp.Type] - typeScriptCode, err := t.convertEnum(depth, enumTyp.Type, elements) - if err != nil { - return "", err - } - result += "\n" + strings.Trim(typeScriptCode, " "+t.Indent+"\r\n") - } - - for _, strctTyp := range t.structTypes { - typeScriptCode, err := t.convertType(depth, strctTyp.Type, customCode) - if err != nil { - return "", err - } - result += "\n" + strings.Trim(typeScriptCode, " "+t.Indent+"\r\n") - } - return result, nil -} - -func loadCustomCode(fileName string) (map[string]string, error) { - result := make(map[string]string) - f, err := os.Open(fileName) - if err != nil { - if os.IsNotExist(err) { - return result, nil - } - return result, err - } - defer f.Close() - - bytes, err := io.ReadAll(f) - if err != nil { - return result, err - } - - var currentName string - var currentValue string - lines := strings.Split(string(bytes), "\n") - for _, line := range lines { - trimmedLine := strings.TrimSpace(line) - if strings.HasPrefix(trimmedLine, "//[") && strings.HasSuffix(trimmedLine, ":]") { - currentName = strings.Replace(strings.Replace(trimmedLine, "//[", "", -1), ":]", "", -1) - currentValue = "" - } else if trimmedLine == "//[end]" { - result[currentName] = strings.TrimRight(currentValue, " \t\r\n") - currentName = "" - currentValue = "" - } else if len(currentName) > 0 { - currentValue += line + "\n" - } - } - - return result, nil -} - -func (t TypeScriptify) backup(fileName string) error { - fileIn, err := os.Open(fileName) - if err != nil { - if !os.IsNotExist(err) { - return err - } - // No neet to backup, just return: - return nil - } - defer fileIn.Close() - - bytes, err := io.ReadAll(fileIn) - if err != nil { - return err - } - - _, backupFn := path.Split(fmt.Sprintf("%s-%s.backup", fileName, time.Now().Format("2006-01-02T15_04_05.99"))) - if t.BackupDir != "" { - backupFn = path.Join(t.BackupDir, backupFn) - } - - return os.WriteFile(backupFn, bytes, os.FileMode(0o700)) -} - -func (t TypeScriptify) ConvertToFile(fileName string, packageName string) error { - if len(t.BackupDir) > 0 { - err := t.backup(fileName) - if err != nil { - return err - } - } - - customCode, err := loadCustomCode(fileName) - if err != nil { - return err - } - - f, err := os.Create(fileName) - if err != nil { - return err - } - defer f.Close() - - converted, err := t.Convert(customCode) - if err != nil { - return err - } - - var lines []string - sc := bufio.NewScanner(strings.NewReader(converted)) - for sc.Scan() { - lines = append(lines, "\t"+sc.Text()) - } - - converted = "export namespace " + packageName + " {\n" - converted += strings.Join(lines, "\n") - converted += "\n}\n" - - if _, err := f.WriteString("/* Do not change, this code is generated from Golang structs */\n\n"); err != nil { - return err - } - if _, err := f.WriteString(converted); err != nil { - return err - } - - return nil -} - -type TSNamer interface { - TSName() string -} - -func (t *TypeScriptify) convertEnum(depth int, typeOf reflect.Type, elements []enumElement) (string, error) { - t.logf(depth, "Converting enum %s", typeOf.String()) - if _, found := t.alreadyConverted[typeOf.String()]; found { // Already converted - return "", nil - } - t.alreadyConverted[typeOf.String()] = true - - entityName := t.Prefix + nameTypeOf(typeOf) + t.Suffix - result := "enum " + entityName + " {\n" - - for _, val := range elements { - result += fmt.Sprintf("%s%s = %#v,\n", t.Indent, val.name, val.value) - } - - result += "}" - - if !t.DontExport { - result = "export " + result - } - - return result, nil -} - -func (t *TypeScriptify) getFieldOptions(structType reflect.Type, field reflect.StructField) TypeOptions { - // By default use options defined by tags: - opts := TypeOptions{TSTransform: field.Tag.Get(tsTransformTag), TSType: field.Tag.Get(tsType)} - - overrides := []TypeOptions{} - - // But there is maybe an struct-specific override: - for _, strct := range t.structTypes { - if strct.FieldOptions == nil { - continue - } - if strct.Type == structType { - if fldOpts, found := strct.FieldOptions[field.Type]; found { - overrides = append(overrides, fldOpts) - } - } - } - - if fldOpts, found := t.fieldTypeOptions[field.Type]; found { - overrides = append(overrides, fldOpts) - } - - for _, o := range overrides { - if o.TSTransform != "" { - opts.TSTransform = o.TSTransform - } - if o.TSType != "" { - opts.TSType = o.TSType - } - } - - return opts -} - -func (t *TypeScriptify) getJSONFieldName(field reflect.StructField, isPtr bool) string { - jsonFieldName := "" - // function, complex, and channel types cannot be json-encoded - if field.Type.Kind() == reflect.Chan || - field.Type.Kind() == reflect.Func || - field.Type.Kind() == reflect.UnsafePointer || - field.Type.Kind() == reflect.Complex128 || - field.Type.Kind() == reflect.Complex64 { - return "" - } - jsonTag, hasTag := field.Tag.Lookup("json") - if !hasTag && field.IsExported() { - jsonFieldName = field.Name - if isPtr { - jsonFieldName += "?" - } - } - if len(jsonTag) > 0 { - jsonTagParts := strings.Split(jsonTag, ",") - if len(jsonTagParts) > 0 { - jsonFieldName = strings.Trim(jsonTagParts[0], t.Indent) - } - hasOmitEmpty := false - ignored := false - for _, t := range jsonTagParts { - if t == "" { - break - } - if t == "omitempty" { - hasOmitEmpty = true - break - } - if t == "-" { - ignored = true - break - } - } - if !ignored && isPtr || hasOmitEmpty { - jsonFieldName = fmt.Sprintf("%s?", jsonFieldName) - } - } - return jsonFieldName -} - -func (t *TypeScriptify) convertType(depth int, typeOf reflect.Type, customCode map[string]string) (string, error) { - if _, found := t.alreadyConverted[typeOf.String()]; found { // Already converted - return "", nil - } - fields := t.deepFields(typeOf) - t.logf(depth, "Converting type %s", typeOf.String()) - if differentNamespaces(t.Namespace, typeOf) { - return "", nil - } - - t.alreadyConverted[typeOf.String()] = true - - entityName := t.Prefix + nameTypeOf(typeOf) + t.Suffix - - if typeClashWithReservedKeyword(entityName) { - warnAboutTypesClash(entityName) - } - - result := "" - if t.CreateInterface { - result += fmt.Sprintf("interface %s {\n", entityName) - } else { - result += fmt.Sprintf("class %s {\n", entityName) - } - if !t.DontExport { - result = "export " + result - } - builder := typeScriptClassBuilder{ - types: t.kinds, - indent: t.Indent, - prefix: t.Prefix, - suffix: t.Suffix, - namespace: t.Namespace, - } - - for _, field := range fields { - isPtr := field.Type.Kind() == reflect.Ptr - if isPtr { - field.Type = field.Type.Elem() - } - jsonFieldName := t.getJSONFieldName(field, isPtr) - if len(jsonFieldName) == 0 || jsonFieldName == "-" { - continue - } - - var err error - fldOpts := t.getFieldOptions(typeOf, field) - if fldOpts.TSTransform != "" { - t.logf(depth, "- simple field %s.%s", typeOf.Name(), field.Name) - err = builder.AddSimpleField(jsonFieldName, field, fldOpts) - } else if _, isEnum := t.enums[field.Type]; isEnum { - t.logf(depth, "- enum field %s.%s", typeOf.Name(), field.Name) - builder.AddEnumField(jsonFieldName, field) - } else if fldOpts.TSType != "" { // Struct: - t.logf(depth, "- simple field %s.%s", typeOf.Name(), field.Name) - err = builder.AddSimpleField(jsonFieldName, field, fldOpts) - } else if field.Type.Kind() == reflect.Struct { // Struct: - t.logf(depth, "- struct %s.%s (%s)", typeOf.Name(), field.Name, field.Type.String()) - - // Anonymous structures is ignored - // It is possible to generate them but hard to generate correct name - if field.Type.Name() != "" { - typeScriptChunk, err := t.convertType(depth+1, field.Type, customCode) - if err != nil { - return "", err - } - if typeScriptChunk != "" { - result = typeScriptChunk + "\n" + result - } - } - - isKnownType := t.KnownStructs.Contains(getStructFQN(field.Type.String())) - if !isKnownType { - println("KnownStructs:", t.KnownStructs.Join("\t")) - println("Not found:", getStructFQN(field.Type.String())) - } - builder.AddStructField(jsonFieldName, field, !isKnownType) - } else if field.Type.Kind() == reflect.Map { - t.logf(depth, "- map field %s.%s", typeOf.Name(), field.Name) - // Also convert map key types if needed - var keyTypeToConvert reflect.Type - switch field.Type.Key().Kind() { - case reflect.Struct: - keyTypeToConvert = field.Type.Key() - case reflect.Ptr: - keyTypeToConvert = field.Type.Key().Elem() - } - if keyTypeToConvert != nil { - typeScriptChunk, err := t.convertType(depth+1, keyTypeToConvert, customCode) - if err != nil { - return "", err - } - if typeScriptChunk != "" { - result = typeScriptChunk + "\n" + result - } - } - // Also convert map value types if needed - var valueTypeToConvert reflect.Type - switch field.Type.Elem().Kind() { - case reflect.Struct: - valueTypeToConvert = field.Type.Elem() - case reflect.Ptr: - valueTypeToConvert = field.Type.Elem().Elem() - } - if valueTypeToConvert != nil { - typeScriptChunk, err := t.convertType(depth+1, valueTypeToConvert, customCode) - if err != nil { - return "", err - } - if typeScriptChunk != "" { - result = typeScriptChunk + "\n" + result - } - } - - builder.AddMapField(jsonFieldName, field) - } else if field.Type.Kind() == reflect.Slice || field.Type.Kind() == reflect.Array { // Slice: - if field.Type.Elem().Kind() == reflect.Ptr { // extract ptr type - field.Type = field.Type.Elem() - } - - arrayDepth := 1 - for field.Type.Elem().Kind() == reflect.Slice || field.Type.Elem().Kind() == reflect.Array { // Slice of slices: - field.Type = field.Type.Elem() - arrayDepth++ - } - - if field.Type.Elem().Kind() == reflect.Ptr { // extract ptr type - field.Type = field.Type.Elem() - } - - if field.Type.Elem().Kind() == reflect.Struct { // Slice of structs: - t.logf(depth, "- struct slice %s.%s (%s)", typeOf.Name(), field.Name, field.Type.String()) - typeScriptChunk, err := t.convertType(depth+1, field.Type.Elem(), customCode) - if err != nil { - return "", err - } - if typeScriptChunk != "" { - result = typeScriptChunk + "\n" + result - } - builder.AddArrayOfStructsField(jsonFieldName, field, arrayDepth) - } else { // Slice of simple fields: - t.logf(depth, "- slice field %s.%s", typeOf.Name(), field.Name) - err = builder.AddSimpleArrayField(jsonFieldName, field, arrayDepth, fldOpts) - } - } else { // Simple field: - t.logf(depth, "- simple field %s.%s", typeOf.Name(), field.Name) - // check if type is in known enum. If so, then replace TStype with enum name to avoid missing types - isKnownEnum := t.KnownEnums.Contains(getStructFQN(field.Type.String())) - if isKnownEnum { - err = builder.AddSimpleField(jsonFieldName, field, TypeOptions{ - TSType: getStructFQN(field.Type.String()), - TSTransform: fldOpts.TSTransform, - }) - } else { - err = builder.AddSimpleField(jsonFieldName, field, fldOpts) - } - } - if err != nil { - return "", err - } - } - - if t.CreateFromMethod { - t.CreateConstructor = true - } - - result += strings.Join(builder.fields, "\n") + "\n" - if !t.CreateInterface { - constructorBody := strings.Join(builder.constructorBody, "\n") - needsConvertValue := strings.Contains(constructorBody, "this.convertValues") - if t.CreateFromMethod { - result += fmt.Sprintf("\n%sstatic createFrom(source: any = {}) {\n", t.Indent) - result += fmt.Sprintf("%s%sreturn new %s(source);\n", t.Indent, t.Indent, entityName) - result += fmt.Sprintf("%s}\n", t.Indent) - } - if t.CreateConstructor { - result += fmt.Sprintf("\n%sconstructor(source: any = {}) {\n", t.Indent) - result += t.Indent + t.Indent + "if ('string' === typeof source) source = JSON.parse(source);\n" - result += constructorBody + "\n" - result += fmt.Sprintf("%s}\n", t.Indent) - } - if needsConvertValue && (t.CreateConstructor || t.CreateFromMethod) { - result += "\n" + indentLines(strings.ReplaceAll(tsConvertValuesFunc, "\t", t.Indent), 1) + "\n" - } - } - - if customCode != nil { - code := customCode[entityName] - if len(code) != 0 { - result += t.Indent + "//[" + entityName + ":]\n" + code + "\n\n" + t.Indent + "//[end]\n" - } - } - - result += "}" - - return result, nil -} - -func (t *TypeScriptify) AddImport(i string) { - for _, cimport := range t.customImports { - if cimport == i { - return - } - } - - t.customImports = append(t.customImports, i) -} - -type typeScriptClassBuilder struct { - types map[reflect.Kind]string - indent string - fields []string - createFromMethodBody []string - constructorBody []string - prefix, suffix string - namespace string -} - -func (t *typeScriptClassBuilder) AddSimpleArrayField(fieldName string, field reflect.StructField, arrayDepth int, opts TypeOptions) error { - fieldType := nameTypeOf(field.Type.Elem()) - kind := field.Type.Elem().Kind() - typeScriptType, ok := t.types[kind] - if !ok { - typeScriptType = "any" - } - - if len(fieldName) > 0 { - strippedFieldName := strings.ReplaceAll(fieldName, "?", "") - if len(opts.TSType) > 0 { - t.addField(fieldName, opts.TSType, false) - t.addInitializerFieldLine(strippedFieldName, fmt.Sprintf("source[\"%s\"]", strippedFieldName)) - return nil - } else if len(typeScriptType) > 0 { - t.addField(fieldName, fmt.Sprint(typeScriptType, strings.Repeat("[]", arrayDepth)), false) - t.addInitializerFieldLine(strippedFieldName, fmt.Sprintf("source[\"%s\"]", strippedFieldName)) - return nil - } - } - - return fmt.Errorf("cannot find type for %s (%s/%s)", kind.String(), fieldName, fieldType) -} - -func (t *typeScriptClassBuilder) AddSimpleField(fieldName string, field reflect.StructField, opts TypeOptions) error { - fieldType := nameTypeOf(field.Type) - kind := field.Type.Kind() - - typeScriptType, ok := t.types[kind] - if !ok { - typeScriptType = "any" - } - - if len(opts.TSType) > 0 { - typeScriptType = opts.TSType - } - - if len(typeScriptType) > 0 && len(fieldName) > 0 { - strippedFieldName := strings.ReplaceAll(fieldName, "?", "") - t.addField(fieldName, typeScriptType, false) - if opts.TSTransform == "" { - t.addInitializerFieldLine(strippedFieldName, fmt.Sprintf("source[\"%s\"]", strippedFieldName)) - } else { - val := fmt.Sprintf(`source["%s"]`, strippedFieldName) - expression := strings.Replace(opts.TSTransform, "__VALUE__", val, -1) - t.addInitializerFieldLine(strippedFieldName, expression) - } - return nil - } - - return fmt.Errorf("cannot find type for %s (%s/%s)", kind.String(), fieldName, fieldType) -} - -func (t *typeScriptClassBuilder) AddEnumField(fieldName string, field reflect.StructField) { - fieldType := nameTypeOf(field.Type) - t.addField(fieldName, t.prefix+fieldType+t.suffix, false) - strippedFieldName := strings.ReplaceAll(fieldName, "?", "") - t.addInitializerFieldLine(strippedFieldName, fmt.Sprintf("source[\"%s\"]", strippedFieldName)) -} - -func (t *typeScriptClassBuilder) AddStructField(fieldName string, field reflect.StructField, isAnyType bool) { - strippedFieldName := strings.ReplaceAll(fieldName, "?", "") - classname := "null" - namespace := strings.Split(field.Type.String(), ".")[0] - fqname := t.prefix + nameTypeOf(field.Type) + t.suffix - if namespace != t.namespace { - fqname = namespace + "." + fqname - } - - if !isAnyType { - classname = fqname - } - - // Anonymous struct - if field.Type.Name() == "" { - classname = "Object" - } - - t.addField(fieldName, fqname, isAnyType) - t.addInitializerFieldLine(strippedFieldName, fmt.Sprintf("this.convertValues(source[\"%s\"], %s)", strippedFieldName, classname)) -} - -func (t *typeScriptClassBuilder) AddArrayOfStructsField(fieldName string, field reflect.StructField, arrayDepth int) { - fieldType := nameTypeOf(field.Type.Elem()) - if differentNamespaces(t.namespace, field.Type.Elem()) { - fieldType = field.Type.Elem().String() - } - strippedFieldName := strings.ReplaceAll(fieldName, "?", "") - t.addField(fieldName, fmt.Sprint(t.prefix+fieldType+t.suffix, strings.Repeat("[]", arrayDepth)), false) - t.addInitializerFieldLine(strippedFieldName, fmt.Sprintf("this.convertValues(source[\"%s\"], %s)", strippedFieldName, t.prefix+fieldType+t.suffix)) -} - -func (t *typeScriptClassBuilder) addInitializerFieldLine(fld, initializer string) { - var dotField string - if regexp.MustCompile(jsVariableNameRegex).Match([]byte(fld)) { - dotField = fmt.Sprintf(".%s", fld) - } else { - dotField = fmt.Sprintf(`["%s"]`, fld) - } - t.createFromMethodBody = append(t.createFromMethodBody, fmt.Sprint(t.indent, t.indent, "result", dotField, " = ", initializer, ";")) - t.constructorBody = append(t.constructorBody, fmt.Sprint(t.indent, t.indent, "this", dotField, " = ", initializer, ";")) -} - -func (t *typeScriptClassBuilder) addField(fld, fldType string, isAnyType bool) { - isOptional := strings.HasSuffix(fld, "?") - strippedFieldName := strings.ReplaceAll(fld, "?", "") - if !regexp.MustCompile(jsVariableNameRegex).Match([]byte(strippedFieldName)) { - fld = fmt.Sprintf(`"%s"`, strippedFieldName) - if isOptional { - fld += "?" - } - } - if isAnyType { - fldType = strings.Split(fldType, ".")[0] - t.fields = append(t.fields, fmt.Sprint(t.indent, "// Go type: ", fldType, "\n", t.indent, fld, ": any;")) - } else { - t.fields = append(t.fields, fmt.Sprint(t.indent, fld, ": ", fldType, ";")) - } -} - -func indentLines(str string, i int) string { - lines := strings.Split(str, "\n") - for n := range lines { - lines[n] = strings.Repeat("\t", i) + lines[n] - } - return strings.Join(lines, "\n") -} - -func getStructFQN(in string) string { - result := strings.ReplaceAll(in, "[]", "") - result = strings.ReplaceAll(result, "*", "") - return result -} - -func differentNamespaces(namespace string, typeOf reflect.Type) bool { - if strings.ContainsRune(typeOf.String(), '.') { - typeNamespace := strings.Split(typeOf.String(), ".")[0] - if namespace != typeNamespace { - return true - } - } - return false -} - -func typeClashWithReservedKeyword(input string) bool { - in := strings.ToLower(strings.TrimSpace(input)) - for _, v := range jsReservedKeywords { - if in == v { - return true - } - } - - return false -} - -func warnAboutTypesClash(entity string) { - // TODO: Refactor logging - l := log.New(os.Stderr, "", 0) - l.Printf("Usage of reserved keyword found and not supported: %s", entity) - log.Println("Please rename returned type or consider adding bindings config to your wails.json") -} diff --git a/v2/internal/webserver/routes.go b/v2/internal/webserver/routes.go new file mode 100644 index 000000000..3b65b2e79 --- /dev/null +++ b/v2/internal/webserver/routes.go @@ -0,0 +1,49 @@ +package webserver + +import ( + "encoding/json" + "fmt" + "net/http" + "strings" +) + +func (w *WebServer) setUpRoutes() error { + // Handle Index + assets + http.HandleFunc("/", w.serveAssets) + + // Handle Bindings + http.HandleFunc("/bindings.js", w.serveBindings) + + // Handle Wails + http.HandleFunc("/wails.js", w.serveWails) + + // Handle websocket connection + http.HandleFunc("/ws", w.websocketConnection) + + return nil +} + +func (w *WebServer) serveAssets(resp http.ResponseWriter, req *http.Request) { + fileserver := http.FileServer(w.assets) + fileserver.ServeHTTP(resp, req) +} + +func (w *WebServer) serveBindings(resp http.ResponseWriter, req *http.Request) { + resp.Header().Add("content-type", "application/javascript") + bindings, err := w.bindings.ToJSON() + if err != nil { + w.logger.Error("Failed to convert bindings to JSON: %v", err) + fmt.Fprintf(resp, "") + return + } + w.logger.Debug("Sending bindings to webclient: %v", bindings) + b, _ := json.Marshal(bindings) + fmt.Fprintf(resp, fmt.Sprintf("window.wailsbindings=%s; window.SetBindings(window.wailsbindings);", b)) +} + +func (w *WebServer) serveWails(resp http.ResponseWriter, req *http.Request) { + resp.Header().Add("content-type", "application/javascript") + if data, err := w.assets.String("/wails.js"); err == nil { + fmt.Fprintf(resp, strings.Replace(data, ":8080", fmt.Sprintf(":%d", w.port), 1)) + } +} diff --git a/v2/internal/webserver/webassets.go b/v2/internal/webserver/webassets.go new file mode 100644 index 000000000..9f73c8f77 --- /dev/null +++ b/v2/internal/webserver/webassets.go @@ -0,0 +1,9 @@ +package webserver + +import "github.com/wailsapp/wails/v2/internal/assetdb" + +var ( + // WebAssets is our single asset db instance. + // It will be constructed by a dynamically generated method in this directory. + WebAssets *assetdb.AssetDB = assetdb.NewAssetDB() +) diff --git a/v2/internal/webserver/webserver.go b/v2/internal/webserver/webserver.go new file mode 100644 index 000000000..4b143d250 --- /dev/null +++ b/v2/internal/webserver/webserver.go @@ -0,0 +1,87 @@ +package webserver + +import ( + "fmt" + "net/http" + "sync" + + "github.com/wailsapp/wails/v2/internal/assetdb" + "github.com/wailsapp/wails/v2/internal/binding" + "github.com/wailsapp/wails/v2/internal/logger" + "github.com/wailsapp/wails/v2/internal/messagedispatcher" + "github.com/wailsapp/wails/v2/internal/subsystem" +) + +// WebServer serves the application over http +type WebServer struct { + port int + ip string + assets *assetdb.AssetDB + logger *logger.Logger + dispatcher *messagedispatcher.Dispatcher + event *subsystem.Event + server *http.Server + bindings *binding.Bindings + + lock sync.Mutex + connections map[string]*WebClient +} + +// NewWebServer creates a new WebServer +func NewWebServer(logger *logger.Logger) *WebServer { + + // Return a WebServer with default values + return &WebServer{ + assets: db, + connections: make(map[string]*WebClient), + logger: logger, + } +} + +// URL returns the URL that the server is serving from +func (w *WebServer) URL() string { + return fmt.Sprintf("http://%s:%d", w.ip, w.port) +} + +// SetPort sets the server port to listen on +func (w *WebServer) SetPort(port int) { + w.port = port +} + +// SetIP sets the server ip to listen on +func (w *WebServer) SetIP(ip string) { + w.ip = ip +} + +// SetBindings provides the webserver with the mapping of bindings to provide to a client +func (w *WebServer) SetBindings(bindings *binding.Bindings) { + w.bindings = bindings +} + +// Start the webserver +func (w *WebServer) Start(dispatcher *messagedispatcher.Dispatcher, event *subsystem.Event) error { + var err error + + // Create the server + w.server = &http.Server{Addr: fmt.Sprintf("%s:%d", w.ip, w.port)} + w.event = event + + // Set up the Web Server's routes + err = w.setUpRoutes() + if err != nil { + return err + } + + // Save the dispatcher + w.dispatcher = dispatcher + + // Start the WebServer + err = w.server.ListenAndServe() + + // Return any error except http.ErrServerClosed + if err != nil && err != http.ErrServerClosed { + return err + } + + return nil +} diff --git a/v2/internal/webserver/websockets.go b/v2/internal/webserver/websockets.go new file mode 100644 index 000000000..474ccfded --- /dev/null +++ b/v2/internal/webserver/websockets.go @@ -0,0 +1,238 @@ +package webserver + +import ( + "context" + "github.com/wailsapp/wails/v2/pkg/menu" + "github.com/wailsapp/wails/v2/pkg/runtime" + "net/http" + "strings" + + "github.com/wailsapp/wails/v2/internal/logger" + ws "nhooyr.io/websocket" + "nhooyr.io/websocket/wsjson" +) + +// WebClient represents an individual web session +type WebClient struct { + conn *ws.Conn + identifier string + logger *logger.Logger + running bool +} + +func (wc *WebClient) WindowSetMinSize(width int, height int) { + wc.logger.Info("Not implemented in server build") +} + +func (wc *WebClient) WindowSetMaxSize(width int, height int) { + wc.logger.Info("Not implemented in server build") +} + +func (wc *WebClient) DeleteTrayMenuByID(id string) { + wc.logger.Info("Not implemented in server build") +} + +func (wc *WebClient) SetTrayMenu(trayMenuJSON string) { + wc.logger.Info("Not implemented in server build") +} + +func (wc *WebClient) UpdateTrayMenuLabel(trayMenuJSON string) { + wc.logger.Info("Not implemented in server build") +} + +func (wc *WebClient) MessageDialog(dialogOptions runtime.MessageDialogOptions, callbackID string) { + wc.logger.Info("Not implemented in server build") +} + +func (wc *WebClient) SetApplicationMenu(menuJSON string) { + wc.logger.Info("Not implemented in server build") +} + +func (wc *WebClient) UpdateTrayMenu(trayMenuJSON string) { + wc.logger.Info("Not implemented in server build") +} + +func (wc *WebClient) UpdateContextMenu(contextMenuJSON string) { + wc.logger.Info("Not implemented in server build") +} + +func (wc *WebClient) OpenFileDialog(dialogOptions runtime.OpenDialogOptions, callbackID string) { + wc.logger.Info("Not implemented in server build") +} + +func (wc *WebClient) OpenMultipleFilesDialog(dialogOptions runtime.OpenDialogOptions, callbackID string) { + wc.logger.Info("Not implemented in server build") +} + +func (wc *WebClient) OpenDirectoryDialog(dialogOptions runtime.OpenDialogOptions, callbackID string) { + wc.logger.Info("Not implemented in server build") +} + +func (wc *WebClient) SaveDialog(dialogOptions runtime.SaveDialogOptions, callbackID string) { + wc.logger.Info("Not implemented in server build") +} + +func (wc *WebClient) WindowShow() { + wc.logger.Info("Not implemented in server build") +} + +func (wc *WebClient) WindowHide() { + wc.logger.Info("Not implemented in server build") +} + +func (wc *WebClient) WindowCenter() { + wc.logger.Info("Not implemented in server build") +} + +func (wc *WebClient) WindowMaximise() { + wc.logger.Info("Not implemented in server build") +} + +func (wc *WebClient) WindowUnmaximise() { + wc.logger.Info("Not implemented in server build") +} + +func (wc *WebClient) WindowMinimise() { + wc.logger.Info("Not implemented in server build") +} + +func (wc *WebClient) WindowUnminimise() { + wc.logger.Info("Not implemented in server build") +} + +func (wc *WebClient) WindowPosition(x int, y int) { + wc.logger.Info("Not implemented in server build") +} + +func (wc *WebClient) WindowSize(width int, height int) { + wc.logger.Info("Not implemented in server build") +} + +func (wc *WebClient) DarkModeEnabled(callbackID string) { + wc.logger.Info("Not implemented in server build") +} + +func (wc *WebClient) UpdateMenu(menu *menu.Menu) { + wc.logger.Info("Not implemented in server build") +} + +func (wc *WebClient) UpdateTray(menu *menu.Menu) { + wc.logger.Info("Not implemented in server build") +} + +func (wc *WebClient) UpdateTrayLabel(label string) { + wc.logger.Info("Not implemented in server build") +} + +func (wc *WebClient) UpdateTrayIcon(name string) { + wc.logger.Info("Not implemented in server build") +} + +// Quit terminates the webclient session +func (wc *WebClient) Quit() { + wc.running = false +} + +// NotifyEvent sends the event +func (wc *WebClient) NotifyEvent(message string) { + wc.SendMessage("E" + message) +} + +// CallResult sends the result of the Go function call back to the +// originator in the frontend +func (wc *WebClient) CallResult(message string) { + wc.SendMessage("R" + message) +} + +// WindowSetTitle is a noop in the webclient +func (wc *WebClient) WindowSetTitle(title string) {} + +// WindowFullscreen is a noop in the webclient +func (wc *WebClient) WindowFullscreen() {} + +// WindowUnFullscreen is a noop in the webclient +func (wc *WebClient) WindowUnFullscreen() {} + +// WindowSetColour is a noop in the webclient +func (wc *WebClient) WindowSetColour(colour int) { +} + +// Run processes messages from the remote webclient +func (wc *WebClient) Run(w *WebServer) { + dispatcher := w.dispatcher.RegisterClient(wc) + defer w.dispatcher.RemoveClient(dispatcher) + defer w.unregisterClient(wc.identifier) + + for wc.running { + var v interface{} + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + if err := wsjson.Read(ctx, wc.conn, &v); err != nil { + if ws.CloseStatus(err) == ws.StatusNormalClosure || ws.CloseStatus(err) == ws.StatusGoingAway { + break + } + if ws.CloseStatus(err) != -1 { + w.logger.Debug("Connection error: %s - %s", wc.identifier, err) + break + } + + if !strings.Contains(err.Error(), "status = Status") { + w.logger.Debug("Error encountered on socket: %v", err) + break + } + } + dispatcher.DispatchMessage(v.(string)) + } + + err := wc.conn.Close(ws.StatusNormalClosure, "Goodbye") + if err != nil { + w.logger.Error("Error encountered on socket: %v", err) + return + } + w.logger.Debug("Connection closed: %v", wc.identifier) +} + +// SendMessage converts the string to a []byte and passes it to +// the connection's Writer to send to the remote client +// The Writer itself prevents multiple users at the same time. +func (wc *WebClient) SendMessage(message string) { + wc.logger.Debug("WebClient.SendMessage() - %s", message) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + err := wc.conn.Write(ctx, ws.MessageText, []byte(message)) + if err != nil { + wc.logger.Error("Error encountered writing to webclient: %v", err) + } +} + +// unregisterClient is called automatically by a WebClient session during termination +// so that it's registration can be removed +func (w *WebServer) unregisterClient(identifier string) { + w.logger.Debug("Removing WebClient : %v", identifier) + w.lock.Lock() + delete(w.connections, identifier) + w.lock.Unlock() +} + +func (w *WebServer) websocketConnection(resp http.ResponseWriter, req *http.Request) { + conn, err := ws.Accept(resp, req, nil) + if err != nil { + w.logger.Debug("Failed to upgrade websocket connection") + return + } + wc := &WebClient{ + conn: conn, + identifier: req.RemoteAddr, + logger: w.logger, + running: true, + } + w.lock.Lock() + w.connections[wc.identifier] = wc + w.lock.Unlock() + + w.logger.Debug("Connection from: %v", wc.identifier) + + go wc.Run(w) + +} diff --git a/v2/internal/webview2runtime/MicrosoftEdgeWebview2Setup.exe b/v2/internal/webview2runtime/MicrosoftEdgeWebview2Setup.exe deleted file mode 100644 index 89a56ec16..000000000 Binary files a/v2/internal/webview2runtime/MicrosoftEdgeWebview2Setup.exe and /dev/null differ diff --git a/v2/internal/webview2runtime/webview2installer.go b/v2/internal/webview2runtime/webview2installer.go deleted file mode 100644 index 3645dae02..000000000 --- a/v2/internal/webview2runtime/webview2installer.go +++ /dev/null @@ -1,21 +0,0 @@ -package webview2runtime - -import ( - _ "embed" - "os" - "path/filepath" -) - -//go:embed MicrosoftEdgeWebview2Setup.exe -var setupexe []byte - -// WriteInstallerToFile writes the installer file to the given file. -func WriteInstallerToFile(targetFile string) error { - return os.WriteFile(targetFile, setupexe, 0o755) -} - -// WriteInstaller writes the installer exe file to the given directory and returns the path to it. -func WriteInstaller(targetPath string) (string, error) { - installer := filepath.Join(targetPath, `MicrosoftEdgeWebview2Setup.exe`) - return installer, WriteInstallerToFile(installer) -} diff --git a/v2/internal/webview2runtime/webview2runtime.go b/v2/internal/webview2runtime/webview2runtime.go deleted file mode 100644 index c5f6c0d53..000000000 --- a/v2/internal/webview2runtime/webview2runtime.go +++ /dev/null @@ -1,169 +0,0 @@ -//go:build windows -// +build windows - -package webview2runtime - -import ( - _ "embed" - "io" - "net/http" - "os" - "os/exec" - "path/filepath" - "syscall" - "unsafe" -) - -// Info contains all the information about an installation of the webview2 runtime. -type Info struct { - Location string - Name string - Version string - SilentUninstall string -} - -// IsOlderThan returns true if the installed version is older than the given required version. -// Returns error if something goes wrong. -func (i *Info) IsOlderThan(requiredVersion string) (bool, error) { - var mod = syscall.NewLazyDLL("WebView2Loader.dll") - var CompareBrowserVersions = mod.NewProc("CompareBrowserVersions") - v1, err := syscall.UTF16PtrFromString(i.Version) - if err != nil { - return false, err - } - v2, err := syscall.UTF16PtrFromString(requiredVersion) - if err != nil { - return false, err - } - var result int = 9 - _, _, err = CompareBrowserVersions.Call(uintptr(unsafe.Pointer(v1)), uintptr(unsafe.Pointer(v2)), uintptr(unsafe.Pointer(&result))) - if result < -1 || result > 1 { - return false, err - } - return result == -1, nil -} - -func downloadBootstrapper() (string, error) { - bootstrapperURL := `https://go.microsoft.com/fwlink/p/?LinkId=2124703` - installer := filepath.Join(os.TempDir(), `MicrosoftEdgeWebview2Setup.exe`) - - // Download installer - out, err := os.Create(installer) - defer out.Close() - if err != nil { - return "", err - } - resp, err := http.Get(bootstrapperURL) - defer resp.Body.Close() - if err != nil { - err = out.Close() - return "", err - } - _, err = io.Copy(out, resp.Body) - if err != nil { - return "", err - } - - return installer, nil -} - -// InstallUsingEmbeddedBootstrapper will download the bootstrapper from Microsoft and run it to install -// the latest version of the runtime. -// Returns true if the installer ran successfully. -// Returns an error if something goes wrong -func InstallUsingEmbeddedBootstrapper() (bool, error) { - installer, err := WriteInstaller(os.TempDir()) - if err != nil { - return false, err - } - result, err := runInstaller(installer) - if err != nil { - return false, err - } - - return result, os.Remove(installer) - -} - -// InstallUsingBootstrapper will extract the embedded bootstrapper from Microsoft and run it to install -// the latest version of the runtime. -// Returns true if the installer ran successfully. -// Returns an error if something goes wrong -func InstallUsingBootstrapper() (bool, error) { - - installer, err := downloadBootstrapper() - if err != nil { - return false, err - } - - result, err := runInstaller(installer) - if err != nil { - return false, err - } - - return result, os.Remove(installer) - -} - -func runInstaller(installer string) (bool, error) { - // Credit: https://stackoverflow.com/a/10385867 - cmd := exec.Command(installer) - if err := cmd.Start(); err != nil { - return false, err - } - if err := cmd.Wait(); err != nil { - if exiterr, ok := err.(*exec.ExitError); ok { - if status, ok := exiterr.Sys().(syscall.WaitStatus); ok { - return status.ExitStatus() == 0, nil - } - } - } - return true, nil -} - -// Confirm will prompt the user with a message and OK / CANCEL buttons. -// Returns true if OK is selected by the user. -// Returns an error if something went wrong. -func Confirm(caption string, title string) (bool, error) { - var flags uint = 0x00000001 // MB_OKCANCEL - result, err := MessageBox(caption, title, flags) - if err != nil { - return false, err - } - return result == 1, nil -} - -// Error will an error message to the user. -// Returns an error if something went wrong. -func Error(caption string, title string) error { - var flags uint = 0x00000010 // MB_ICONERROR - _, err := MessageBox(caption, title, flags) - return err -} - -// MessageBox prompts the user with the given caption and title. -// Flags may be provided to customise the dialog. -// Returns an error if something went wrong. -func MessageBox(caption string, title string, flags uint) (int, error) { - captionUTF16, err := syscall.UTF16PtrFromString(caption) - if err != nil { - return -1, err - } - titleUTF16, err := syscall.UTF16PtrFromString(title) - if err != nil { - return -1, err - } - ret, _, _ := syscall.NewLazyDLL("user32.dll").NewProc("MessageBoxW").Call( - uintptr(0), - uintptr(unsafe.Pointer(captionUTF16)), - uintptr(unsafe.Pointer(titleUTF16)), - uintptr(flags)) - - return int(ret), nil -} - -// OpenInstallerDownloadWebpage will open the browser on the WebView2 download page -func OpenInstallerDownloadWebpage() error { - cmd := exec.Command("rundll32", "url.dll,FileProtocolHandler", "https://developer.microsoft.com/en-us/microsoft-edge/webview2/") - return cmd.Run() -} diff --git a/v2/internal/wv2installer/browser.go b/v2/internal/wv2installer/browser.go deleted file mode 100644 index 2597bde6b..000000000 --- a/v2/internal/wv2installer/browser.go +++ /dev/null @@ -1,25 +0,0 @@ -//go:build windows && wv2runtime.browser -// +build windows,wv2runtime.browser - -package wv2installer - -import ( - "fmt" - "github.com/wailsapp/wails/v2/internal/webview2runtime" - "github.com/wailsapp/wails/v2/pkg/options/windows" -) - -func doInstallationStrategy(installStatus installationStatus, messages *windows.Messages) error { - confirmed, err := webview2runtime.Confirm(messages.DownloadPage+MinimumRuntimeVersion, messages.MissingRequirements) - if err != nil { - return err - } - if confirmed { - err = webview2runtime.OpenInstallerDownloadWebpage() - if err != nil { - return err - } - } - - return fmt.Errorf(messages.FailedToInstall) -} diff --git a/v2/internal/wv2installer/download.go b/v2/internal/wv2installer/download.go deleted file mode 100644 index 0a054d661..000000000 --- a/v2/internal/wv2installer/download.go +++ /dev/null @@ -1,35 +0,0 @@ -//go:build windows && !wv2runtime.error && !wv2runtime.browser && !wv2runtime.embed -// +build windows,!wv2runtime.error,!wv2runtime.browser,!wv2runtime.embed - -package wv2installer - -import ( - "fmt" - - "github.com/wailsapp/wails/v2/internal/webview2runtime" - "github.com/wailsapp/wails/v2/pkg/options/windows" -) - -func doInstallationStrategy(installStatus installationStatus, messages *windows.Messages) error { - message := messages.InstallationRequired - if installStatus == needsUpdating { - message = messages.UpdateRequired - } - confirmed, err := webview2runtime.Confirm(message, messages.MissingRequirements) - if err != nil { - return err - } - if !confirmed { - return fmt.Errorf(messages.Webview2NotInstalled) - } - installedCorrectly, err := webview2runtime.InstallUsingBootstrapper() - if err != nil { - _ = webview2runtime.Error(err.Error(), messages.Error) - return err - } - if !installedCorrectly { - err = webview2runtime.Error(messages.FailedToInstall, messages.Error) - return err - } - return nil -} diff --git a/v2/internal/wv2installer/embed.go b/v2/internal/wv2installer/embed.go deleted file mode 100644 index 942d6b51a..000000000 --- a/v2/internal/wv2installer/embed.go +++ /dev/null @@ -1,35 +0,0 @@ -//go:build windows && wv2runtime.embed -// +build windows,wv2runtime.embed - -package wv2installer - -import ( - "fmt" - "github.com/wailsapp/wails/v2/internal/webview2runtime" - "github.com/wailsapp/wails/v2/pkg/options/windows" -) - -func doInstallationStrategy(installStatus installationStatus, messages *windows.Messages) error { - message := messages.InstallationRequired - if installStatus == needsUpdating { - message = messages.UpdateRequired - } - message += messages.PressOKToInstall - confirmed, err := webview2runtime.Confirm(message, messages.MissingRequirements) - if err != nil { - return err - } - if !confirmed { - return fmt.Errorf(messages.Webview2NotInstalled) - } - installedCorrectly, err := webview2runtime.InstallUsingEmbeddedBootstrapper() - if err != nil { - _ = webview2runtime.Error(err.Error(), messages.Error) - return err - } - if !installedCorrectly { - err = webview2runtime.Error(messages.FailedToInstall, messages.Error) - return err - } - return nil -} diff --git a/v2/internal/wv2installer/error.go b/v2/internal/wv2installer/error.go deleted file mode 100644 index ec48ef990..000000000 --- a/v2/internal/wv2installer/error.go +++ /dev/null @@ -1,15 +0,0 @@ -//go:build windows && wv2runtime.error -// +build windows,wv2runtime.error - -package wv2installer - -import ( - "fmt" - "github.com/wailsapp/wails/v2/internal/webview2runtime" - "github.com/wailsapp/wails/v2/pkg/options/windows" -) - -func doInstallationStrategy(installStatus installationStatus, messages *windows.Messages) error { - _ = webview2runtime.Error(messages.ContactAdmin, messages.Error) - return fmt.Errorf(messages.Webview2NotInstalled) -} diff --git a/v2/internal/wv2installer/wv2installer.go b/v2/internal/wv2installer/wv2installer.go deleted file mode 100644 index c89ad196f..000000000 --- a/v2/internal/wv2installer/wv2installer.go +++ /dev/null @@ -1,60 +0,0 @@ -//go:build windows - -package wv2installer - -import ( - "fmt" - - "github.com/wailsapp/go-webview2/webviewloader" - "github.com/wailsapp/wails/v2/pkg/options" - "github.com/wailsapp/wails/v2/pkg/options/windows" -) - -const MinimumRuntimeVersion string = "94.0.992.31" // WebView2 SDK 1.0.992.28 - -type installationStatus int - -const ( - needsInstalling installationStatus = iota - needsUpdating -) - -func Process(appoptions *options.App) (string, error) { - messages := windows.DefaultMessages() - if appoptions.Windows != nil && appoptions.Windows.Messages != nil { - messages = appoptions.Windows.Messages - } - - installStatus := needsInstalling - - // Override version check for manually specified webview path if present - var webviewPath = "" - if opts := appoptions.Windows; opts != nil && opts.WebviewBrowserPath != "" { - webviewPath = opts.WebviewBrowserPath - } - - installedVersion, err := webviewloader.GetAvailableCoreWebView2BrowserVersionString(webviewPath) - if err != nil { - return "", err - } - - if installedVersion != "" { - installStatus = needsUpdating - compareResult, err := webviewloader.CompareBrowserVersions(installedVersion, MinimumRuntimeVersion) - if err != nil { - return "", err - } - updateRequired := compareResult < 0 - // Installed and does not require updating - if !updateRequired { - return installedVersion, nil - } - } - - // Force error strategy if webview is manually specified - if webviewPath != "" { - return installedVersion, fmt.Errorf(messages.InvalidFixedWebview2) - } - - return installedVersion, doInstallationStrategy(installStatus, messages) -} diff --git a/v2/pkg/application/application.go b/v2/pkg/application/application.go deleted file mode 100644 index 8ba586969..000000000 --- a/v2/pkg/application/application.go +++ /dev/null @@ -1,102 +0,0 @@ -package application - -import ( - "context" - "sync" - - "github.com/wailsapp/wails/v2/internal/app" - "github.com/wailsapp/wails/v2/internal/signal" - "github.com/wailsapp/wails/v2/pkg/menu" - "github.com/wailsapp/wails/v2/pkg/options" -) - -// Application is the main Wails application -type Application struct { - application *app.App - options *options.App - - // running flag - running bool - - shutdown sync.Once -} - -// NewWithOptions creates a new Application with the given options -func NewWithOptions(options *options.App) *Application { - if options == nil { - return New() - } - return &Application{ - options: options, - } -} - -// New creates a new Application with the default options -func New() *Application { - return &Application{ - options: &options.App{}, - } -} - -// SetApplicationMenu sets the application menu -func (a *Application) SetApplicationMenu(appMenu *menu.Menu) { - if a.running { - a.application.SetApplicationMenu(appMenu) - return - } - - a.options.Menu = appMenu -} - -// Run starts the application -func (a *Application) Run() error { - err := applicationInit() - if err != nil { - return err - } - - application, err := app.CreateApp(a.options) - if err != nil { - return err - } - - a.application = application - - // Control-C handlers - signal.OnShutdown(func() { - a.application.Shutdown() - }) - signal.Start() - - a.running = true - - err = a.application.Run() - return err -} - -// Quit will shut down the application -func (a *Application) Quit() { - a.shutdown.Do(func() { - a.application.Shutdown() - }) -} - -// Bind the given struct to the application -func (a *Application) Bind(boundStruct any) { - a.options.Bind = append(a.options.Bind, boundStruct) -} - -func (a *Application) On(eventType EventType, callback func()) { - c := func(ctx context.Context) { - callback() - } - - switch eventType { - case StartUp: - a.options.OnStartup = c - case ShutDown: - a.options.OnShutdown = c - case DomReady: - a.options.OnDomReady = c - } -} diff --git a/v2/pkg/application/events.go b/v2/pkg/application/events.go deleted file mode 100644 index 3896e9e75..000000000 --- a/v2/pkg/application/events.go +++ /dev/null @@ -1,9 +0,0 @@ -package application - -type EventType int - -const ( - StartUp EventType = iota - ShutDown - DomReady -) diff --git a/v2/pkg/application/init.go b/v2/pkg/application/init.go deleted file mode 100644 index 0fc48cb05..000000000 --- a/v2/pkg/application/init.go +++ /dev/null @@ -1,8 +0,0 @@ -//go:build !windows -// +build !windows - -package application - -func applicationInit() error { - return nil -} diff --git a/v2/pkg/application/init_windows.go b/v2/pkg/application/init_windows.go deleted file mode 100644 index 7d2900d3d..000000000 --- a/v2/pkg/application/init_windows.go +++ /dev/null @@ -1,16 +0,0 @@ -//go:build windows - -package application - -import ( - "fmt" - "syscall" -) - -func applicationInit() error { - status, r, err := syscall.NewLazyDLL("user32.dll").NewProc("SetProcessDPIAware").Call() - if status == 0 { - return fmt.Errorf("exit status %d: %v %v", status, r, err) - } - return nil -} diff --git a/v2/pkg/assetserver/assethandler.go b/v2/pkg/assetserver/assethandler.go deleted file mode 100644 index b8e2df076..000000000 --- a/v2/pkg/assetserver/assethandler.go +++ /dev/null @@ -1,205 +0,0 @@ -package assetserver - -import ( - "bytes" - "embed" - "errors" - "fmt" - "io" - iofs "io/fs" - "net/http" - "os" - "path" - "strconv" - "strings" - - "github.com/wailsapp/wails/v2/pkg/options/assetserver" -) - -type Logger interface { - Debug(message string, args ...interface{}) - Error(message string, args ...interface{}) -} - -//go:embed defaultindex.html -var defaultHTML []byte - -const ( - indexHTML = "index.html" -) - -type assetHandler struct { - fs iofs.FS - handler http.Handler - - logger Logger - - retryMissingFiles bool -} - -func NewAssetHandler(options assetserver.Options, log Logger) (http.Handler, error) { - vfs := options.Assets - if vfs != nil { - if _, err := vfs.Open("."); err != nil { - return nil, err - } - - subDir, err := FindPathToFile(vfs, indexHTML) - if err != nil { - if errors.Is(err, os.ErrNotExist) { - msg := "no `index.html` could be found in your Assets fs.FS" - if embedFs, isEmbedFs := vfs.(embed.FS); isEmbedFs { - rootFolder, _ := FindEmbedRootPath(embedFs) - msg += fmt.Sprintf(", please make sure the embedded directory '%s' is correct and contains your assets", rootFolder) - } - - return nil, fmt.Errorf(msg) - } - - return nil, err - } - - vfs, err = iofs.Sub(vfs, path.Clean(subDir)) - if err != nil { - return nil, err - } - } - - var result http.Handler = &assetHandler{ - fs: vfs, - handler: options.Handler, - logger: log, - } - - if middleware := options.Middleware; middleware != nil { - result = middleware(result) - } - - return result, nil -} - -func (d *assetHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { - url := req.URL.Path - handler := d.handler - if strings.EqualFold(req.Method, http.MethodGet) { - filename := path.Clean(strings.TrimPrefix(url, "/")) - - d.logDebug("Handling request '%s' (file='%s')", url, filename) - if err := d.serveFSFile(rw, req, filename); err != nil { - if os.IsNotExist(err) { - if handler != nil { - d.logDebug("File '%s' not found, serving '%s' by AssetHandler", filename, url) - handler.ServeHTTP(rw, req) - err = nil - } else { - rw.WriteHeader(http.StatusNotFound) - err = nil - } - } - - if err != nil { - d.logError("Unable to handle request '%s': %s", url, err) - http.Error(rw, err.Error(), http.StatusInternalServerError) - } - } - } else if handler != nil { - d.logDebug("No GET request, serving '%s' by AssetHandler", url) - handler.ServeHTTP(rw, req) - } else { - rw.WriteHeader(http.StatusMethodNotAllowed) - } -} - -// serveFSFile will try to load the file from the fs.FS and write it to the response -func (d *assetHandler) serveFSFile(rw http.ResponseWriter, req *http.Request, filename string) error { - if d.fs == nil { - return os.ErrNotExist - } - - file, err := d.fs.Open(filename) - if err != nil { - return err - } - defer file.Close() - - statInfo, err := file.Stat() - if err != nil { - return err - } - - url := req.URL.Path - isDirectoryPath := url == "" || url[len(url)-1] == '/' - if statInfo.IsDir() { - if !isDirectoryPath { - // If the URL doesn't end in a slash normally a http.redirect should be done, but that currently doesn't work on - // WebKit WebViews (macOS/Linux). - // So we handle this as a specific error - return fmt.Errorf("a directory has been requested without a trailing slash, please add a trailing slash to your request") - } - - filename = path.Join(filename, indexHTML) - - file, err = d.fs.Open(filename) - if err != nil { - return err - } - defer file.Close() - - statInfo, err = file.Stat() - if err != nil { - return err - } - } else if isDirectoryPath { - return fmt.Errorf("a file has been requested with a trailing slash, please remove the trailing slash from your request") - } - - var buf [512]byte - var n int - if _, haveType := rw.Header()[HeaderContentType]; !haveType { - // Detect MimeType by sniffing the first 512 bytes - n, err = file.Read(buf[:]) - if err != nil && err != io.EOF { - return err - } - - // Do the custom MimeType sniffing even though http.ServeContent would do it in case - // of an io.ReadSeeker. We would like to have a consistent behaviour in both cases. - if contentType := GetMimetype(filename, buf[:n]); contentType != "" { - rw.Header().Set(HeaderContentType, contentType) - } - } - - if fileSeeker, _ := file.(io.ReadSeeker); fileSeeker != nil { - if _, err := fileSeeker.Seek(0, io.SeekStart); err != nil { - return fmt.Errorf("seeker can't seek") - } - - http.ServeContent(rw, req, statInfo.Name(), statInfo.ModTime(), fileSeeker) - return nil - } - - size := strconv.FormatInt(statInfo.Size(), 10) - rw.Header().Set(HeaderContentLength, size) - - // Write the first 512 bytes used for MimeType sniffing - _, err = io.Copy(rw, bytes.NewReader(buf[:n])) - if err != nil { - return err - } - - // Copy the remaining content of the file - _, err = io.Copy(rw, file) - return err -} - -func (d *assetHandler) logDebug(message string, args ...interface{}) { - if d.logger != nil { - d.logger.Debug("[AssetHandler] "+message, args...) - } -} - -func (d *assetHandler) logError(message string, args ...interface{}) { - if d.logger != nil { - d.logger.Error("[AssetHandler] "+message, args...) - } -} diff --git a/v2/pkg/assetserver/assethandler_external.go b/v2/pkg/assetserver/assethandler_external.go deleted file mode 100644 index 98b3404e9..000000000 --- a/v2/pkg/assetserver/assethandler_external.go +++ /dev/null @@ -1,84 +0,0 @@ -package assetserver - -import ( - "errors" - "fmt" - "github.com/wailsapp/wails/v2/pkg/options/assetserver" - "net/http" - "net/http/httputil" - "net/url" -) - -func NewProxyServer(proxyURL string) http.Handler { - parsedURL, err := url.Parse(proxyURL) - if err != nil { - panic(err) - } - return httputil.NewSingleHostReverseProxy(parsedURL) -} - -func NewExternalAssetsHandler(logger Logger, options assetserver.Options, url *url.URL) http.Handler { - baseHandler := options.Handler - - errSkipProxy := fmt.Errorf("skip proxying") - - proxy := httputil.NewSingleHostReverseProxy(url) - baseDirector := proxy.Director - proxy.Director = func(r *http.Request) { - baseDirector(r) - if logger != nil { - logger.Debug("[ExternalAssetHandler] Loading '%s'", r.URL) - } - } - - proxy.ModifyResponse = func(res *http.Response) error { - if baseHandler == nil { - return nil - } - - if res.StatusCode == http.StatusSwitchingProtocols { - return nil - } - - if res.StatusCode == http.StatusNotFound || res.StatusCode == http.StatusMethodNotAllowed { - return errSkipProxy - } - - return nil - } - - proxy.ErrorHandler = func(rw http.ResponseWriter, r *http.Request, err error) { - if baseHandler != nil && errors.Is(err, errSkipProxy) { - if logger != nil { - logger.Debug("[ExternalAssetHandler] '%s' returned not found, using AssetHandler", r.URL) - } - baseHandler.ServeHTTP(rw, r) - } else { - if logger != nil { - logger.Error("[ExternalAssetHandler] Proxy error: %v", err) - } - rw.WriteHeader(http.StatusBadGateway) - } - } - - var result http.Handler = http.HandlerFunc( - func(rw http.ResponseWriter, req *http.Request) { - if req.Method == http.MethodGet { - proxy.ServeHTTP(rw, req) - return - } - - if baseHandler != nil { - baseHandler.ServeHTTP(rw, req) - return - } - - rw.WriteHeader(http.StatusMethodNotAllowed) - }) - - if middleware := options.Middleware; middleware != nil { - result = middleware(result) - } - - return result -} diff --git a/v2/pkg/assetserver/assetserver.go b/v2/pkg/assetserver/assetserver.go deleted file mode 100644 index 59665c091..000000000 --- a/v2/pkg/assetserver/assetserver.go +++ /dev/null @@ -1,255 +0,0 @@ -package assetserver - -import ( - "bytes" - "fmt" - "math/rand" - "net/http" - "strings" - - "golang.org/x/net/html" - "html/template" - - "github.com/wailsapp/wails/v2/pkg/options" - "github.com/wailsapp/wails/v2/pkg/options/assetserver" -) - -const ( - runtimeJSPath = "/wails/runtime.js" - ipcJSPath = "/wails/ipc.js" - runtimePath = "/wails/runtime" -) - -type RuntimeAssets interface { - DesktopIPC() []byte - WebsocketIPC() []byte - RuntimeDesktopJS() []byte -} - -type RuntimeHandler interface { - HandleRuntimeCall(w http.ResponseWriter, r *http.Request) -} - -type AssetServer struct { - handler http.Handler - runtimeJS []byte - ipcJS func(*http.Request) []byte - - logger Logger - runtime RuntimeAssets - - servingFromDisk bool - appendSpinnerToBody bool - - // Use http based runtime - runtimeHandler RuntimeHandler - - // plugin scripts - pluginScripts map[string]string - - assetServerWebView -} - -func NewAssetServerMainPage(bindingsJSON string, options *options.App, servingFromDisk bool, logger Logger, runtime RuntimeAssets) (*AssetServer, error) { - assetOptions, err := BuildAssetServerConfig(options) - if err != nil { - return nil, err - } - return NewAssetServer(bindingsJSON, assetOptions, servingFromDisk, logger, runtime) -} - -func NewAssetServer(bindingsJSON string, options assetserver.Options, servingFromDisk bool, logger Logger, runtime RuntimeAssets) (*AssetServer, error) { - handler, err := NewAssetHandler(options, logger) - if err != nil { - return nil, err - } - - return NewAssetServerWithHandler(handler, bindingsJSON, servingFromDisk, logger, runtime) -} - -func NewAssetServerWithHandler(handler http.Handler, bindingsJSON string, servingFromDisk bool, logger Logger, runtime RuntimeAssets) (*AssetServer, error) { - - var buffer bytes.Buffer - if bindingsJSON != "" { - escapedBindingsJSON := template.JSEscapeString(bindingsJSON) - buffer.WriteString(`window.wailsbindings='` + escapedBindingsJSON + `';` + "\n") - } - buffer.Write(runtime.RuntimeDesktopJS()) - - result := &AssetServer{ - handler: handler, - runtimeJS: buffer.Bytes(), - - // Check if we have been given a directory to serve assets from. - // If so, this means we are in dev mode and are serving assets off disk. - // We indicate this through the `servingFromDisk` flag to ensure requests - // aren't cached in dev mode. - servingFromDisk: servingFromDisk, - logger: logger, - runtime: runtime, - } - - return result, nil -} - -func (d *AssetServer) UseRuntimeHandler(handler RuntimeHandler) { - d.runtimeHandler = handler -} - -func (d *AssetServer) AddPluginScript(pluginName string, script string) { - if d.pluginScripts == nil { - d.pluginScripts = make(map[string]string) - } - pluginName = strings.ReplaceAll(pluginName, "/", "_") - pluginName = html.EscapeString(pluginName) - pluginScriptName := fmt.Sprintf("/plugin_%s_%d.js", pluginName, rand.Intn(100000)) - d.pluginScripts[pluginScriptName] = script -} - -func (d *AssetServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) { - if isWebSocket(req) { - // WebSockets are not supported by the AssetServer - rw.WriteHeader(http.StatusNotImplemented) - return - } - - if d.servingFromDisk { - rw.Header().Add(HeaderCacheControl, "no-cache") - } - - handler := d.handler - if req.Method != http.MethodGet { - handler.ServeHTTP(rw, req) - return - } - - path := req.URL.Path - if path == runtimeJSPath { - d.writeBlob(rw, path, d.runtimeJS) - } else if path == runtimePath && d.runtimeHandler != nil { - d.runtimeHandler.HandleRuntimeCall(rw, req) - } else if path == ipcJSPath { - content := d.runtime.DesktopIPC() - if d.ipcJS != nil { - content = d.ipcJS(req) - } - d.writeBlob(rw, path, content) - - } else if script, ok := d.pluginScripts[path]; ok { - d.writeBlob(rw, path, []byte(script)) - } else if d.isRuntimeInjectionMatch(path) { - recorder := &bodyRecorder{ - ResponseWriter: rw, - doRecord: func(code int, h http.Header) bool { - if code == http.StatusNotFound { - return true - } - - if code != http.StatusOK { - return false - } - - return strings.Contains(h.Get(HeaderContentType), "text/html") - }, - } - - handler.ServeHTTP(recorder, req) - - body := recorder.Body() - if body == nil { - // The body has been streamed and not recorded, we are finished - return - } - - code := recorder.Code() - switch code { - case http.StatusOK: - content, err := d.processIndexHTML(body.Bytes()) - if err != nil { - d.serveError(rw, err, "Unable to processIndexHTML") - return - } - d.writeBlob(rw, indexHTML, content) - - case http.StatusNotFound: - d.writeBlob(rw, indexHTML, defaultHTML) - - default: - rw.WriteHeader(code) - - } - - } else { - handler.ServeHTTP(rw, req) - } -} - -func (d *AssetServer) processIndexHTML(indexHTML []byte) ([]byte, error) { - htmlNode, err := getHTMLNode(indexHTML) - if err != nil { - return nil, err - } - - if d.appendSpinnerToBody { - err = appendSpinnerToBody(htmlNode) - if err != nil { - return nil, err - } - } - - if err := insertScriptInHead(htmlNode, runtimeJSPath); err != nil { - return nil, err - } - - if err := insertScriptInHead(htmlNode, ipcJSPath); err != nil { - return nil, err - } - - // Inject plugins - for scriptName := range d.pluginScripts { - if err := insertScriptInHead(htmlNode, scriptName); err != nil { - return nil, err - } - } - - var buffer bytes.Buffer - err = html.Render(&buffer, htmlNode) - if err != nil { - return nil, err - } - return buffer.Bytes(), nil -} - -func (d *AssetServer) writeBlob(rw http.ResponseWriter, filename string, blob []byte) { - err := serveFile(rw, filename, blob) - if err != nil { - d.serveError(rw, err, "Unable to write content %s", filename) - } -} - -func (d *AssetServer) serveError(rw http.ResponseWriter, err error, msg string, args ...interface{}) { - args = append(args, err) - d.logError(msg+": %s", args...) - rw.WriteHeader(http.StatusInternalServerError) -} - -func (d *AssetServer) logDebug(message string, args ...interface{}) { - if d.logger != nil { - d.logger.Debug("[AssetServer] "+message, args...) - } -} - -func (d *AssetServer) logError(message string, args ...interface{}) { - if d.logger != nil { - d.logger.Error("[AssetServer] "+message, args...) - } -} - -func (AssetServer) isRuntimeInjectionMatch(path string) bool { - if path == "" { - path = "/" - } - - return strings.HasSuffix(path, "/") || - strings.HasSuffix(path, "/"+indexHTML) -} diff --git a/v2/pkg/assetserver/assetserver_dev.go b/v2/pkg/assetserver/assetserver_dev.go deleted file mode 100644 index f6a2a0d2f..000000000 --- a/v2/pkg/assetserver/assetserver_dev.go +++ /dev/null @@ -1,31 +0,0 @@ -//go:build dev -// +build dev - -package assetserver - -import ( - "net/http" - "strings" -) - -/* -The assetserver for the dev mode. -Depending on the UserAgent it injects a websocket based IPC script into `index.html` or the default desktop IPC. The -default desktop IPC is injected when the webview accesses the devserver. -*/ -func NewDevAssetServer(handler http.Handler, bindingsJSON string, servingFromDisk bool, logger Logger, runtime RuntimeAssets) (*AssetServer, error) { - result, err := NewAssetServerWithHandler(handler, bindingsJSON, servingFromDisk, logger, runtime) - if err != nil { - return nil, err - } - - result.appendSpinnerToBody = true - result.ipcJS = func(req *http.Request) []byte { - if strings.Contains(req.UserAgent(), WailsUserAgentValue) { - return runtime.DesktopIPC() - } - return runtime.WebsocketIPC() - } - - return result, nil -} diff --git a/v2/pkg/assetserver/assetserver_webview.go b/v2/pkg/assetserver/assetserver_webview.go deleted file mode 100644 index 63f80f0ae..000000000 --- a/v2/pkg/assetserver/assetserver_webview.go +++ /dev/null @@ -1,185 +0,0 @@ -package assetserver - -import ( - "fmt" - "net/http" - "net/url" - "strconv" - "strings" - "sync" - - "github.com/wailsapp/wails/v2/pkg/assetserver/webview" -) - -type assetServerWebView struct { - // ExpectedWebViewHost is checked against the Request Host of every WebViewRequest, other hosts won't be processed. - ExpectedWebViewHost string - - dispatchInit sync.Once - dispatchReqC chan<- webview.Request - dispatchWorkers int -} - -// ServeWebViewRequest processes the HTTP Request asynchronously by faking a golang HTTP Server. -// The request will be finished with a StatusNotImplemented code if no handler has written to the response. -// The AssetServer takes ownership of the request and the caller mustn't close it or access it in any other way. -func (d *AssetServer) ServeWebViewRequest(req webview.Request) { - d.dispatchInit.Do(func() { - workers := d.dispatchWorkers - if workers <= 0 { - return - } - - workerC := make(chan webview.Request, workers*2) - for i := 0; i < workers; i++ { - go func() { - for req := range workerC { - d.processWebViewRequest(req) - } - }() - } - - dispatchC := make(chan webview.Request) - go queueingDispatcher(50, dispatchC, workerC) - - d.dispatchReqC = dispatchC - }) - - if d.dispatchReqC == nil { - go d.processWebViewRequest(req) - } else { - d.dispatchReqC <- req - } -} - -func (d *AssetServer) processWebViewRequest(r webview.Request) { - uri, _ := r.URL() - d.processWebViewRequestInternal(r) - if err := r.Close(); err != nil { - d.logError("Unable to call close for request for uri '%s'", uri) - } -} - -// processWebViewRequestInternal processes the HTTP Request by faking a golang HTTP Server. -// The request will be finished with a StatusNotImplemented code if no handler has written to the response. -func (d *AssetServer) processWebViewRequestInternal(r webview.Request) { - uri := "unknown" - var err error - - wrw := r.Response() - defer func() { - if err := wrw.Finish(); err != nil { - d.logError("Error finishing request '%s': %s", uri, err) - } - }() - - var rw http.ResponseWriter = &contentTypeSniffer{rw: wrw} // Make sure we have a Content-Type sniffer - defer rw.WriteHeader(http.StatusNotImplemented) // This is a NOP when a handler has already written and set the status - - uri, err = r.URL() - if err != nil { - d.logError("Error processing request, unable to get URL: %s (HttpResponse=500)", err) - http.Error(rw, err.Error(), http.StatusInternalServerError) - return - } - - method, err := r.Method() - if err != nil { - d.webviewRequestErrorHandler(uri, rw, fmt.Errorf("HTTP-Method: %w", err)) - return - } - - header, err := r.Header() - if err != nil { - d.webviewRequestErrorHandler(uri, rw, fmt.Errorf("HTTP-Header: %w", err)) - return - } - - body, err := r.Body() - if err != nil { - d.webviewRequestErrorHandler(uri, rw, fmt.Errorf("HTTP-Body: %w", err)) - return - } - - if body == nil { - body = http.NoBody - } - defer body.Close() - - req, err := http.NewRequest(method, uri, body) - if err != nil { - d.webviewRequestErrorHandler(uri, rw, fmt.Errorf("HTTP-Request: %w", err)) - return - } - - // For server requests, the URL is parsed from the URI supplied on the Request-Line as stored in RequestURI. For - // most requests, fields other than Path and RawQuery will be empty. (See RFC 7230, Section 5.3) - req.URL.Scheme = "" - req.URL.Host = "" - req.URL.Fragment = "" - req.URL.RawFragment = "" - - if url := req.URL; req.RequestURI == "" && url != nil { - req.RequestURI = url.String() - } - - req.Header = header - - if req.RemoteAddr == "" { - // 192.0.2.0/24 is "TEST-NET" in RFC 5737 - req.RemoteAddr = "192.0.2.1:1234" - } - - if req.ContentLength == 0 { - req.ContentLength = -1 - } else { - size := strconv.FormatInt(req.ContentLength, 10) - req.Header.Set(HeaderContentLength, size) - } - - if host := req.Header.Get(HeaderHost); host != "" { - req.Host = host - } - - if expectedHost := d.ExpectedWebViewHost; expectedHost != "" && expectedHost != req.Host { - d.webviewRequestErrorHandler(uri, rw, fmt.Errorf("expected host '%s' in request, but was '%s'", expectedHost, req.Host)) - return - } - - d.ServeHTTP(rw, req) -} - -func (d *AssetServer) webviewRequestErrorHandler(uri string, rw http.ResponseWriter, err error) { - logInfo := uri - if uri, err := url.ParseRequestURI(uri); err == nil { - logInfo = strings.Replace(logInfo, fmt.Sprintf("%s://%s", uri.Scheme, uri.Host), "", 1) - } - - d.logError("Error processing request '%s': %s (HttpResponse=500)", logInfo, err) - http.Error(rw, err.Error(), http.StatusInternalServerError) -} - -func queueingDispatcher[T any](minQueueSize uint, inC <-chan T, outC chan<- T) { - q := newRingqueue[T](minQueueSize) - for { - in, ok := <-inC - if !ok { - return - } - - q.Add(in) - for q.Len() != 0 { - out, _ := q.Peek() - select { - case outC <- out: - q.Remove() - case in, ok := <-inC: - if !ok { - return - } - - q.Add(in) - } - } - } -} diff --git a/v2/pkg/assetserver/body_recorder.go b/v2/pkg/assetserver/body_recorder.go deleted file mode 100644 index fa3bc1e7c..000000000 --- a/v2/pkg/assetserver/body_recorder.go +++ /dev/null @@ -1,61 +0,0 @@ -package assetserver - -import ( - "bytes" - "net/http" -) - -type bodyRecorder struct { - http.ResponseWriter - doRecord func(code int, header http.Header) bool - - body *bytes.Buffer - code int - wroteHeader bool -} - -func (rw *bodyRecorder) Write(buf []byte) (int, error) { - rw.writeHeader(buf, http.StatusOK) - if rw.body != nil { - return rw.body.Write(buf) - } - return rw.ResponseWriter.Write(buf) -} - -func (rw *bodyRecorder) WriteHeader(code int) { - rw.writeHeader(nil, code) -} - -func (rw *bodyRecorder) Code() int { - return rw.code -} - -func (rw *bodyRecorder) Body() *bytes.Buffer { - return rw.body -} - -func (rw *bodyRecorder) writeHeader(buf []byte, code int) { - if rw.wroteHeader { - return - } - - if rw.doRecord != nil { - header := rw.Header() - if len(buf) != 0 { - if _, hasType := header[HeaderContentType]; !hasType { - header.Set(HeaderContentType, http.DetectContentType(buf)) - } - } - - if rw.doRecord(code, header) { - rw.body = bytes.NewBuffer(nil) - } - } - - if rw.body == nil { - rw.ResponseWriter.WriteHeader(code) - } - - rw.code = code - rw.wroteHeader = true -} diff --git a/v2/pkg/assetserver/common.go b/v2/pkg/assetserver/common.go deleted file mode 100644 index 57934e08e..000000000 --- a/v2/pkg/assetserver/common.go +++ /dev/null @@ -1,135 +0,0 @@ -package assetserver - -import ( - "bytes" - "errors" - "io" - "net/http" - "strconv" - "strings" - - "github.com/wailsapp/wails/v2/pkg/options" - "github.com/wailsapp/wails/v2/pkg/options/assetserver" - "golang.org/x/net/html" -) - -func BuildAssetServerConfig(appOptions *options.App) (assetserver.Options, error) { - var options assetserver.Options - if opt := appOptions.AssetServer; opt != nil { - if appOptions.Assets != nil || appOptions.AssetsHandler != nil { - panic("It's not possible to use the deprecated Assets and AssetsHandler options and the new AssetServer option at the same time. Please migrate all your Assets options to the AssetServer option.") - } - - options = *opt - } else { - options = assetserver.Options{ - Assets: appOptions.Assets, - Handler: appOptions.AssetsHandler, - } - } - - return options, options.Validate() -} - -const ( - HeaderHost = "Host" - HeaderContentType = "Content-Type" - HeaderContentLength = "Content-Length" - HeaderUserAgent = "User-Agent" - HeaderCacheControl = "Cache-Control" - HeaderUpgrade = "Upgrade" - - WailsUserAgentValue = "wails.io" -) - -func serveFile(rw http.ResponseWriter, filename string, blob []byte) error { - header := rw.Header() - header.Set(HeaderContentLength, strconv.Itoa(len(blob))) - if mimeType := header.Get(HeaderContentType); mimeType == "" { - mimeType = GetMimetype(filename, blob) - header.Set(HeaderContentType, mimeType) - } - - rw.WriteHeader(http.StatusOK) - _, err := io.Copy(rw, bytes.NewReader(blob)) - return err -} - -func createScriptNode(scriptName string) *html.Node { - return &html.Node{ - Type: html.ElementNode, - Data: "script", - Attr: []html.Attribute{ - { - Key: "src", - Val: scriptName, - }, - }, - } -} - -func createDivNode(id string) *html.Node { - return &html.Node{ - Type: html.ElementNode, - Data: "div", - Attr: []html.Attribute{ - { - Namespace: "", - Key: "id", - Val: id, - }, - }, - } -} - -func insertScriptInHead(htmlNode *html.Node, scriptName string) error { - headNode := findFirstTag(htmlNode, "head") - if headNode == nil { - return errors.New("cannot find head in HTML") - } - scriptNode := createScriptNode(scriptName) - if headNode.FirstChild != nil { - headNode.InsertBefore(scriptNode, headNode.FirstChild) - } else { - headNode.AppendChild(scriptNode) - } - return nil -} - -func appendSpinnerToBody(htmlNode *html.Node) error { - bodyNode := findFirstTag(htmlNode, "body") - if bodyNode == nil { - return errors.New("cannot find body in HTML") - } - scriptNode := createDivNode("wails-spinner") - bodyNode.AppendChild(scriptNode) - return nil -} - -func getHTMLNode(htmldata []byte) (*html.Node, error) { - return html.Parse(bytes.NewReader(htmldata)) -} - -func findFirstTag(htmlnode *html.Node, tagName string) *html.Node { - var extractor func(*html.Node) *html.Node - var result *html.Node - extractor = func(node *html.Node) *html.Node { - if node.Type == html.ElementNode && node.Data == tagName { - return node - } - for child := node.FirstChild; child != nil; child = child.NextSibling { - result := extractor(child) - if result != nil { - return result - } - } - return nil - } - result = extractor(htmlnode) - return result -} - -func isWebSocket(req *http.Request) bool { - upgrade := req.Header.Get(HeaderUpgrade) - return strings.EqualFold(upgrade, "websocket") -} diff --git a/v2/pkg/assetserver/content_type_sniffer.go b/v2/pkg/assetserver/content_type_sniffer.go deleted file mode 100644 index 475428ae5..000000000 --- a/v2/pkg/assetserver/content_type_sniffer.go +++ /dev/null @@ -1,42 +0,0 @@ -package assetserver - -import ( - "net/http" -) - -type contentTypeSniffer struct { - rw http.ResponseWriter - - wroteHeader bool -} - -func (rw *contentTypeSniffer) Header() http.Header { - return rw.rw.Header() -} - -func (rw *contentTypeSniffer) Write(buf []byte) (int, error) { - rw.writeHeader(buf) - return rw.rw.Write(buf) -} - -func (rw *contentTypeSniffer) WriteHeader(code int) { - if rw.wroteHeader { - return - } - - rw.rw.WriteHeader(code) - rw.wroteHeader = true -} - -func (rw *contentTypeSniffer) writeHeader(b []byte) { - if rw.wroteHeader { - return - } - - m := rw.rw.Header() - if _, hasType := m[HeaderContentType]; !hasType { - m.Set(HeaderContentType, http.DetectContentType(b)) - } - - rw.WriteHeader(http.StatusOK) -} diff --git a/v2/pkg/assetserver/defaultindex.html b/v2/pkg/assetserver/defaultindex.html deleted file mode 100644 index 1ea97c405..000000000 --- a/v2/pkg/assetserver/defaultindex.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - index.html not found - - - - -
index.html not found
-

Please try reloading the page

- - \ No newline at end of file diff --git a/v2/pkg/assetserver/fs.go b/v2/pkg/assetserver/fs.go deleted file mode 100644 index 7ecc9cec8..000000000 --- a/v2/pkg/assetserver/fs.go +++ /dev/null @@ -1,75 +0,0 @@ -package assetserver - -import ( - "embed" - "fmt" - "io/fs" - "os" - "path/filepath" - "strings" -) - -// FindEmbedRootPath finds the root path in the embed FS. It's the directory which contains all the files. -func FindEmbedRootPath(fsys embed.FS) (string, error) { - stopErr := fmt.Errorf("files or multiple dirs found") - - fPath := "" - err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error { - if err != nil { - return err - } - - if d.IsDir() { - fPath = path - if entries, dErr := fs.ReadDir(fsys, path); dErr != nil { - return dErr - } else if len(entries) <= 1 { - return nil - } - } - - return stopErr - }) - - if err != nil && err != stopErr { - return "", err - } - - return fPath, nil -} - -func FindPathToFile(fsys fs.FS, file string) (string, error) { - stat, _ := fs.Stat(fsys, file) - if stat != nil { - return ".", nil - } - var indexFiles []string - err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error { - if err != nil { - return err - } - if strings.HasSuffix(path, file) { - indexFiles = append(indexFiles, path) - } - return nil - }) - if err != nil { - return "", err - } - - if len(indexFiles) > 1 { - selected := indexFiles[0] - for _, f := range indexFiles { - if len(f) < len(selected) { - selected = f - } - } - path, _ := filepath.Split(selected) - return path, nil - } - if len(indexFiles) > 0 { - path, _ := filepath.Split(indexFiles[0]) - return path, nil - } - return "", fmt.Errorf("%s: %w", file, os.ErrNotExist) -} diff --git a/v2/pkg/assetserver/mimecache.go b/v2/pkg/assetserver/mimecache.go deleted file mode 100644 index 9d97e8f5a..000000000 --- a/v2/pkg/assetserver/mimecache.go +++ /dev/null @@ -1,67 +0,0 @@ -package assetserver - -import ( - "net/http" - "path/filepath" - "sync" - - "github.com/wailsapp/mimetype" -) - -var ( - mimeCache = map[string]string{} - mimeMutex sync.Mutex - - // The list of builtin mime-types by extension as defined by - // the golang standard lib package "mime" - // The standard lib also takes into account mime type definitions from - // etc files like '/etc/apache2/mime.types' but we want to have the - // same behavivour on all platforms and not depend on some external file. - mimeTypesByExt = map[string]string{ - ".avif": "image/avif", - ".css": "text/css; charset=utf-8", - ".gif": "image/gif", - ".htm": "text/html; charset=utf-8", - ".html": "text/html; charset=utf-8", - ".jpeg": "image/jpeg", - ".jpg": "image/jpeg", - ".js": "text/javascript; charset=utf-8", - ".json": "application/json", - ".mjs": "text/javascript; charset=utf-8", - ".pdf": "application/pdf", - ".png": "image/png", - ".svg": "image/svg+xml", - ".wasm": "application/wasm", - ".webp": "image/webp", - ".xml": "text/xml; charset=utf-8", - } -) - -func GetMimetype(filename string, data []byte) string { - mimeMutex.Lock() - defer mimeMutex.Unlock() - - result := mimeTypesByExt[filepath.Ext(filename)] - if result != "" { - return result - } - - result = mimeCache[filename] - if result != "" { - return result - } - - detect := mimetype.Detect(data) - if detect == nil { - result = http.DetectContentType(data) - } else { - result = detect.String() - } - - if result == "" { - result = "application/octet-stream" - } - - mimeCache[filename] = result - return result -} diff --git a/v2/pkg/assetserver/mimecache_test.go b/v2/pkg/assetserver/mimecache_test.go deleted file mode 100644 index 1496dbf52..000000000 --- a/v2/pkg/assetserver/mimecache_test.go +++ /dev/null @@ -1,47 +0,0 @@ -package assetserver - -import ( - "testing" -) - -func TestGetMimetype(t *testing.T) { - type args struct { - filename string - data []byte - } - bomUTF8 := []byte{0xef, 0xbb, 0xbf} - var emptyMsg []byte - css := []byte("body{margin:0;padding:0;background-color:#d579b2}#app{font-family:Avenir,Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-align:center;color:#2c3e50;background-color:#ededed}#nav{padding:30px}#nav a{font-weight:700;color:#2c\n3e50}#nav a.router-link-exact-active{color:#42b983}.hello[data-v-4e26ad49]{margin:10px 0}") - html := []byte("title") - bomHtml := append(bomUTF8, html...) - svg := []byte("") - svgWithComment := append([]byte(""), svg...) - svgWithCommentAndControlChars := append([]byte(" \r\n "), svgWithComment...) - svgWithBomCommentAndControlChars := append(bomUTF8, append([]byte(" \r\n "), svgWithComment...)...) - - tests := []struct { - name string - args args - want string - }{ - // TODO: Add test cases. - {"nil data", args{"nil.svg", nil}, "image/svg+xml"}, - {"empty data", args{"empty.html", emptyMsg}, "text/html; charset=utf-8"}, - {"css", args{"test.css", css}, "text/css; charset=utf-8"}, - {"js", args{"test.js", []byte("let foo = 'bar'; console.log(foo);")}, "text/javascript; charset=utf-8"}, - {"mjs", args{"test.mjs", []byte("let foo = 'bar'; console.log(foo);")}, "text/javascript; charset=utf-8"}, - {"html-utf8", args{"test_utf8.html", html}, "text/html; charset=utf-8"}, - {"html-bom-utf8", args{"test_bom_utf8.html", bomHtml}, "text/html; charset=utf-8"}, - {"svg", args{"test.svg", svg}, "image/svg+xml"}, - {"svg-w-comment", args{"test_comment.svg", svgWithComment}, "image/svg+xml"}, - {"svg-w-control-comment", args{"test_control_comment.svg", svgWithCommentAndControlChars}, "image/svg+xml"}, - {"svg-w-bom-control-comment", args{"test_bom_control_comment.svg", svgWithBomCommentAndControlChars}, "image/svg+xml"}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := GetMimetype(tt.args.filename, tt.args.data); got != tt.want { - t.Errorf("GetMimetype() = '%v', want '%v'", got, tt.want) - } - }) - } -} diff --git a/v2/pkg/assetserver/ringqueue.go b/v2/pkg/assetserver/ringqueue.go deleted file mode 100644 index b94e7cd5c..000000000 --- a/v2/pkg/assetserver/ringqueue.go +++ /dev/null @@ -1,101 +0,0 @@ -// Code from https://github.com/erikdubbelboer/ringqueue -/* -The MIT License (MIT) - -Copyright (c) 2015 Erik Dubbelboer - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ -package assetserver - -type ringqueue[T any] struct { - nodes []T - head int - tail int - cnt int - - minSize int -} - -func newRingqueue[T any](minSize uint) *ringqueue[T] { - if minSize < 2 { - minSize = 2 - } - return &ringqueue[T]{ - nodes: make([]T, minSize), - minSize: int(minSize), - } -} - -func (q *ringqueue[T]) resize(n int) { - nodes := make([]T, n) - if q.head < q.tail { - copy(nodes, q.nodes[q.head:q.tail]) - } else { - copy(nodes, q.nodes[q.head:]) - copy(nodes[len(q.nodes)-q.head:], q.nodes[:q.tail]) - } - - q.tail = q.cnt % n - q.head = 0 - q.nodes = nodes -} - -func (q *ringqueue[T]) Add(i T) { - if q.cnt == len(q.nodes) { - // Also tested a grow rate of 1.5, see: http://stackoverflow.com/questions/2269063/buffer-growth-strategy - // In Go this resulted in a higher memory usage. - q.resize(q.cnt * 2) - } - q.nodes[q.tail] = i - q.tail = (q.tail + 1) % len(q.nodes) - q.cnt++ -} - -func (q *ringqueue[T]) Peek() (T, bool) { - if q.cnt == 0 { - var none T - return none, false - } - return q.nodes[q.head], true -} - -func (q *ringqueue[T]) Remove() (T, bool) { - if q.cnt == 0 { - var none T - return none, false - } - i := q.nodes[q.head] - q.head = (q.head + 1) % len(q.nodes) - q.cnt-- - - if n := len(q.nodes) / 2; n > q.minSize && q.cnt <= n { - q.resize(n) - } - - return i, true -} - -func (q *ringqueue[T]) Cap() int { - return cap(q.nodes) -} - -func (q *ringqueue[T]) Len() int { - return q.cnt -} diff --git a/v2/pkg/assetserver/webview/request.go b/v2/pkg/assetserver/webview/request.go deleted file mode 100644 index 18ff29890..000000000 --- a/v2/pkg/assetserver/webview/request.go +++ /dev/null @@ -1,17 +0,0 @@ -package webview - -import ( - "io" - "net/http" -) - -type Request interface { - URL() (string, error) - Method() (string, error) - Header() (http.Header, error) - Body() (io.ReadCloser, error) - - Response() ResponseWriter - - Close() error -} diff --git a/v2/pkg/assetserver/webview/request_darwin.go b/v2/pkg/assetserver/webview/request_darwin.go deleted file mode 100644 index c44e5f196..000000000 --- a/v2/pkg/assetserver/webview/request_darwin.go +++ /dev/null @@ -1,251 +0,0 @@ -//go:build darwin - -package webview - -/* -#cgo CFLAGS: -x objective-c -#cgo LDFLAGS: -framework Foundation -framework WebKit - -#import -#import -#include - -static void URLSchemeTaskRetain(void *wkUrlSchemeTask) { - id urlSchemeTask = (id) wkUrlSchemeTask; - [urlSchemeTask retain]; -} - -static void URLSchemeTaskRelease(void *wkUrlSchemeTask) { - id urlSchemeTask = (id) wkUrlSchemeTask; - [urlSchemeTask release]; -} - -static const char * URLSchemeTaskRequestURL(void *wkUrlSchemeTask) { - id urlSchemeTask = (id) wkUrlSchemeTask; - @autoreleasepool { - return [urlSchemeTask.request.URL.absoluteString UTF8String]; - } -} - -static const char * URLSchemeTaskRequestMethod(void *wkUrlSchemeTask) { - id urlSchemeTask = (id) wkUrlSchemeTask; - @autoreleasepool { - return [urlSchemeTask.request.HTTPMethod UTF8String]; - } -} - -static const char * URLSchemeTaskRequestHeadersJSON(void *wkUrlSchemeTask) { - id urlSchemeTask = (id) wkUrlSchemeTask; - @autoreleasepool { - NSData *headerData = [NSJSONSerialization dataWithJSONObject: urlSchemeTask.request.allHTTPHeaderFields options:0 error: nil]; - if (!headerData) { - return nil; - } - - NSString* headerString = [[[NSString alloc] initWithData:headerData encoding:NSUTF8StringEncoding] autorelease]; - const char * headerJSON = [headerString UTF8String]; - - return strdup(headerJSON); - } -} - -static bool URLSchemeTaskRequestBodyBytes(void *wkUrlSchemeTask, const void **body, int *bodyLen) { - id urlSchemeTask = (id) wkUrlSchemeTask; - @autoreleasepool { - if (!urlSchemeTask.request.HTTPBody) { - return false; - } - - *body = urlSchemeTask.request.HTTPBody.bytes; - *bodyLen = urlSchemeTask.request.HTTPBody.length; - return true; - } -} - -static bool URLSchemeTaskRequestBodyStreamOpen(void *wkUrlSchemeTask) { - id urlSchemeTask = (id) wkUrlSchemeTask; - @autoreleasepool { - if (!urlSchemeTask.request.HTTPBodyStream) { - return false; - } - - [urlSchemeTask.request.HTTPBodyStream open]; - return true; - } -} - -static void URLSchemeTaskRequestBodyStreamClose(void *wkUrlSchemeTask) { - id urlSchemeTask = (id) wkUrlSchemeTask; - @autoreleasepool { - if (!urlSchemeTask.request.HTTPBodyStream) { - return; - } - - [urlSchemeTask.request.HTTPBodyStream close]; - } -} - -static int URLSchemeTaskRequestBodyStreamRead(void *wkUrlSchemeTask, void *buf, int bufLen) { - id urlSchemeTask = (id) wkUrlSchemeTask; - - @autoreleasepool { - NSInputStream *stream = urlSchemeTask.request.HTTPBodyStream; - if (!stream) { - return -2; - } - - NSStreamStatus status = stream.streamStatus; - if (status == NSStreamStatusAtEnd || !stream.hasBytesAvailable) { - return 0; - } else if (status != NSStreamStatusOpen) { - return -3; - } - - return [stream read:buf maxLength:bufLen]; - } -} -*/ -import "C" - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "net/http" - "unsafe" -) - -// NewRequest creates as new WebViewRequest based on a pointer to an `id` -func NewRequest(wkURLSchemeTask unsafe.Pointer) Request { - C.URLSchemeTaskRetain(wkURLSchemeTask) - return newRequestFinalizer(&request{task: wkURLSchemeTask}) -} - -var _ Request = &request{} - -type request struct { - task unsafe.Pointer - - header http.Header - body io.ReadCloser - rw *responseWriter -} - -func (r *request) URL() (string, error) { - return C.GoString(C.URLSchemeTaskRequestURL(r.task)), nil -} - -func (r *request) Method() (string, error) { - return C.GoString(C.URLSchemeTaskRequestMethod(r.task)), nil -} - -func (r *request) Header() (http.Header, error) { - if r.header != nil { - return r.header, nil - } - - header := http.Header{} - if cHeaders := C.URLSchemeTaskRequestHeadersJSON(r.task); cHeaders != nil { - if headers := C.GoString(cHeaders); headers != "" { - var h map[string]string - if err := json.Unmarshal([]byte(headers), &h); err != nil { - return nil, fmt.Errorf("unable to unmarshal request headers: %s", err) - } - - for k, v := range h { - header.Add(k, v) - } - } - C.free(unsafe.Pointer(cHeaders)) - } - r.header = header - return header, nil -} - -func (r *request) Body() (io.ReadCloser, error) { - if r.body != nil { - return r.body, nil - } - - var body unsafe.Pointer - var bodyLen C.int - if C.URLSchemeTaskRequestBodyBytes(r.task, &body, &bodyLen) { - if body != nil && bodyLen > 0 { - r.body = io.NopCloser(bytes.NewReader(C.GoBytes(body, bodyLen))) - } else { - r.body = http.NoBody - } - } else if C.URLSchemeTaskRequestBodyStreamOpen(r.task) { - r.body = &requestBodyStreamReader{task: r.task} - } - - return r.body, nil -} - -func (r *request) Response() ResponseWriter { - if r.rw != nil { - return r.rw - } - - r.rw = &responseWriter{r: r} - return r.rw -} - -func (r *request) Close() error { - var err error - if r.body != nil { - err = r.body.Close() - } - err = r.Response().Finish() - if err != nil { - return err - } - C.URLSchemeTaskRelease(r.task) - return err -} - -var _ io.ReadCloser = &requestBodyStreamReader{} - -type requestBodyStreamReader struct { - task unsafe.Pointer - closed bool -} - -// Read implements io.Reader -func (r *requestBodyStreamReader) Read(p []byte) (n int, err error) { - var content unsafe.Pointer - var contentLen int - if p != nil { - content = unsafe.Pointer(&p[0]) - contentLen = len(p) - } - - res := C.URLSchemeTaskRequestBodyStreamRead(r.task, content, C.int(contentLen)) - if res > 0 { - return int(res), nil - } - - switch res { - case 0: - return 0, io.EOF - case -1: - return 0, fmt.Errorf("body: stream error") - case -2: - return 0, fmt.Errorf("body: no stream defined") - case -3: - return 0, io.ErrClosedPipe - default: - return 0, fmt.Errorf("body: unknown error %d", res) - } -} - -func (r *requestBodyStreamReader) Close() error { - if r.closed { - return nil - } - r.closed = true - - C.URLSchemeTaskRequestBodyStreamClose(r.task) - return nil -} diff --git a/v2/pkg/assetserver/webview/request_finalizer.go b/v2/pkg/assetserver/webview/request_finalizer.go deleted file mode 100644 index 6a8c6a928..000000000 --- a/v2/pkg/assetserver/webview/request_finalizer.go +++ /dev/null @@ -1,40 +0,0 @@ -package webview - -import ( - "runtime" - "sync/atomic" -) - -var _ Request = &requestFinalizer{} - -type requestFinalizer struct { - Request - closed int32 -} - -// newRequestFinalizer returns a request with a runtime finalizer to make sure it will be closed from the finalizer -// if it has not been already closed. -// It also makes sure Close() of the wrapping request is only called once. -func newRequestFinalizer(r Request) Request { - rf := &requestFinalizer{Request: r} - // Make sure to async release since it might block the finalizer goroutine for a longer period - runtime.SetFinalizer(rf, func(obj *requestFinalizer) { rf.close(true) }) - return rf -} - -func (r *requestFinalizer) Close() error { - return r.close(false) -} - -func (r *requestFinalizer) close(asyncRelease bool) error { - if atomic.CompareAndSwapInt32(&r.closed, 0, 1) { - runtime.SetFinalizer(r, nil) - if asyncRelease { - go r.Request.Close() - return nil - } else { - return r.Request.Close() - } - } - return nil -} diff --git a/v2/pkg/assetserver/webview/request_linux.go b/v2/pkg/assetserver/webview/request_linux.go deleted file mode 100644 index c6785fb1c..000000000 --- a/v2/pkg/assetserver/webview/request_linux.go +++ /dev/null @@ -1,85 +0,0 @@ -//go:build linux -// +build linux - -package webview - -/* -#cgo linux pkg-config: gtk+-3.0 gio-unix-2.0 -#cgo !webkit2_41 pkg-config: webkit2gtk-4.0 -#cgo webkit2_41 pkg-config: webkit2gtk-4.1 - -#include "gtk/gtk.h" -#include "webkit2/webkit2.h" -*/ -import "C" - -import ( - "io" - "net/http" - "unsafe" -) - -// NewRequest creates as new WebViewRequest based on a pointer to an `WebKitURISchemeRequest` -func NewRequest(webKitURISchemeRequest unsafe.Pointer) Request { - webkitReq := (*C.WebKitURISchemeRequest)(webKitURISchemeRequest) - C.g_object_ref(C.gpointer(webkitReq)) - - req := &request{req: webkitReq} - return newRequestFinalizer(req) -} - -var _ Request = &request{} - -type request struct { - req *C.WebKitURISchemeRequest - - header http.Header - body io.ReadCloser - rw *responseWriter -} - -func (r *request) URL() (string, error) { - return C.GoString(C.webkit_uri_scheme_request_get_uri(r.req)), nil -} - -func (r *request) Method() (string, error) { - return webkit_uri_scheme_request_get_http_method(r.req), nil -} - -func (r *request) Header() (http.Header, error) { - if r.header != nil { - return r.header, nil - } - - r.header = webkit_uri_scheme_request_get_http_headers(r.req) - return r.header, nil -} - -func (r *request) Body() (io.ReadCloser, error) { - if r.body != nil { - return r.body, nil - } - - r.body = webkit_uri_scheme_request_get_http_body(r.req) - - return r.body, nil -} - -func (r *request) Response() ResponseWriter { - if r.rw != nil { - return r.rw - } - - r.rw = &responseWriter{req: r.req} - return r.rw -} - -func (r *request) Close() error { - var err error - if r.body != nil { - err = r.body.Close() - } - r.Response().Finish() - C.g_object_unref(C.gpointer(r.req)) - return err -} diff --git a/v2/pkg/assetserver/webview/request_windows.go b/v2/pkg/assetserver/webview/request_windows.go deleted file mode 100644 index fa83cd8d7..000000000 --- a/v2/pkg/assetserver/webview/request_windows.go +++ /dev/null @@ -1,217 +0,0 @@ -//go:build windows -// +build windows - -package webview - -import ( - "fmt" - "io" - "net/http" - "strings" - - "github.com/wailsapp/go-webview2/pkg/edge" -) - -// NewRequest creates as new WebViewRequest for chromium. This Method must be called from the Main-Thread! -func NewRequest(env *edge.ICoreWebView2Environment, args *edge.ICoreWebView2WebResourceRequestedEventArgs, invokeSync func(fn func())) (Request, error) { - req, err := args.GetRequest() - if err != nil { - return nil, fmt.Errorf("GetRequest failed: %s", err) - } - defer req.Release() - - r := &request{ - invokeSync: invokeSync, - } - - code := http.StatusInternalServerError - r.response, err = env.CreateWebResourceResponse(nil, code, http.StatusText(code), "") - if err != nil { - return nil, fmt.Errorf("CreateWebResourceResponse failed: %s", err) - } - - if err := args.PutResponse(r.response); err != nil { - r.finishResponse() - return nil, fmt.Errorf("PutResponse failed: %s", err) - } - - r.deferral, err = args.GetDeferral() - if err != nil { - r.finishResponse() - return nil, fmt.Errorf("GetDeferral failed: %s", err) - } - - r.url, r.urlErr = req.GetUri() - r.method, r.methodErr = req.GetMethod() - r.header, r.headerErr = getHeaders(req) - - if content, err := req.GetContent(); err != nil { - r.bodyErr = err - } else if content != nil { - // It is safe to access Content from another Thread: https://learn.microsoft.com/en-us/microsoft-edge/webview2/concepts/threading-model#thread-safety - r.body = &iStreamReleaseCloser{stream: content} - } - - return r, nil -} - -var _ Request = &request{} - -type request struct { - response *edge.ICoreWebView2WebResourceResponse - deferral *edge.ICoreWebView2Deferral - - url string - urlErr error - - method string - methodErr error - - header http.Header - headerErr error - - body io.ReadCloser - bodyErr error - rw *responseWriter - - invokeSync func(fn func()) -} - -func (r *request) URL() (string, error) { - return r.url, r.urlErr -} - -func (r *request) Method() (string, error) { - return r.method, r.methodErr -} - -func (r *request) Header() (http.Header, error) { - return r.header, r.headerErr -} - -func (r *request) Body() (io.ReadCloser, error) { - return r.body, r.bodyErr -} - -func (r *request) Response() ResponseWriter { - if r.rw != nil { - return r.rw - } - - r.rw = &responseWriter{req: r} - return r.rw -} - -func (r *request) Close() error { - var errs []error - if r.body != nil { - if err := r.body.Close(); err != nil { - errs = append(errs, err) - } - r.body = nil - } - - if err := r.Response().Finish(); err != nil { - errs = append(errs, err) - } - - return combineErrs(errs) -} - -// finishResponse must be called on the main-thread -func (r *request) finishResponse() error { - var errs []error - if r.response != nil { - if err := r.response.Release(); err != nil { - errs = append(errs, err) - } - r.response = nil - } - if r.deferral != nil { - if err := r.deferral.Complete(); err != nil { - errs = append(errs, err) - } - - if err := r.deferral.Release(); err != nil { - errs = append(errs, err) - } - r.deferral = nil - } - return combineErrs(errs) -} - -type iStreamReleaseCloser struct { - stream *edge.IStream - closed bool -} - -func (i *iStreamReleaseCloser) Read(p []byte) (int, error) { - if i.closed { - return 0, io.ErrClosedPipe - } - return i.stream.Read(p) -} - -func (i *iStreamReleaseCloser) Close() error { - if i.closed { - return nil - } - i.closed = true - return i.stream.Release() -} - -func getHeaders(req *edge.ICoreWebView2WebResourceRequest) (http.Header, error) { - header := http.Header{} - headers, err := req.GetHeaders() - if err != nil { - return nil, fmt.Errorf("GetHeaders Error: %s", err) - } - defer headers.Release() - - headersIt, err := headers.GetIterator() - if err != nil { - return nil, fmt.Errorf("GetIterator Error: %s", err) - } - defer headersIt.Release() - - for { - has, err := headersIt.HasCurrentHeader() - if err != nil { - return nil, fmt.Errorf("HasCurrentHeader Error: %s", err) - } - if !has { - break - } - - name, value, err := headersIt.GetCurrentHeader() - if err != nil { - return nil, fmt.Errorf("GetCurrentHeader Error: %s", err) - } - - header.Set(name, value) - if _, err := headersIt.MoveNext(); err != nil { - return nil, fmt.Errorf("MoveNext Error: %s", err) - } - } - - // WebView2 has problems when a request returns a 304 status code and the WebView2 is going to hang for other - // requests including IPC calls. - // So prevent 304 status codes by removing the headers that are used in combinationwith caching. - header.Del("If-Modified-Since") - header.Del("If-None-Match") - return header, nil -} - -func combineErrs(errs []error) error { - // TODO use Go1.20 errors.Join - if len(errs) == 0 { - return nil - } - - errStrings := make([]string, len(errs)) - for i, err := range errs { - errStrings[i] = err.Error() - } - - return fmt.Errorf(strings.Join(errStrings, "\n")) -} diff --git a/v2/pkg/assetserver/webview/responsewriter.go b/v2/pkg/assetserver/webview/responsewriter.go deleted file mode 100644 index dacbb567d..000000000 --- a/v2/pkg/assetserver/webview/responsewriter.go +++ /dev/null @@ -1,25 +0,0 @@ -package webview - -import ( - "errors" - "net/http" -) - -const ( - HeaderContentLength = "Content-Length" - HeaderContentType = "Content-Type" -) - -var ( - errRequestStopped = errors.New("request has been stopped") - errResponseFinished = errors.New("response has been finished") -) - -// A ResponseWriter interface is used by an HTTP handler to -// construct an HTTP response for the WebView. -type ResponseWriter interface { - http.ResponseWriter - - // Finish the response and flush all data. A Finish after the request has already been finished has no effect. - Finish() error -} diff --git a/v2/pkg/assetserver/webview/responsewriter_darwin.go b/v2/pkg/assetserver/webview/responsewriter_darwin.go deleted file mode 100644 index a3c73b6f1..000000000 --- a/v2/pkg/assetserver/webview/responsewriter_darwin.go +++ /dev/null @@ -1,164 +0,0 @@ -//go:build darwin - -package webview - -/* -#cgo CFLAGS: -x objective-c -#cgo LDFLAGS: -framework Foundation -framework WebKit - -#import -#import - -typedef void (^schemeTaskCaller)(id); - -static bool urlSchemeTaskCall(void *wkUrlSchemeTask, schemeTaskCaller fn) { - id urlSchemeTask = (id) wkUrlSchemeTask; - if (urlSchemeTask == nil) { - return false; - } - - @autoreleasepool { - @try { - fn(urlSchemeTask); - } @catch (NSException *exception) { - // This is very bad to detect a stopped schemeTask this should be implemented in a better way - // But it seems to be very tricky to not deadlock when keeping a lock curing executing fn() - // It seems like those call switch the thread back to the main thread and then deadlocks when they reentrant want - // to get the lock again to start another request or stop it. - if ([exception.reason isEqualToString: @"This task has already been stopped"]) { - return false; - } - - @throw exception; - } - - return true; - } -} - -static bool URLSchemeTaskDidReceiveData(void *wkUrlSchemeTask, void* data, int datalength) { - return urlSchemeTaskCall( - wkUrlSchemeTask, - ^(id urlSchemeTask) { - NSData *nsdata = [NSData dataWithBytes:data length:datalength]; - [urlSchemeTask didReceiveData:nsdata]; - }); -} - -static bool URLSchemeTaskDidFinish(void *wkUrlSchemeTask) { - return urlSchemeTaskCall( - wkUrlSchemeTask, - ^(id urlSchemeTask) { - [urlSchemeTask didFinish]; - }); -} - -static bool URLSchemeTaskDidReceiveResponse(void *wkUrlSchemeTask, int statusCode, void *headersString, int headersStringLength) { - return urlSchemeTaskCall( - wkUrlSchemeTask, - ^(id urlSchemeTask) { - NSData *nsHeadersJSON = [NSData dataWithBytes:headersString length:headersStringLength]; - NSDictionary *headerFields = [NSJSONSerialization JSONObjectWithData:nsHeadersJSON options: NSJSONReadingMutableContainers error: nil]; - NSHTTPURLResponse *response = [[[NSHTTPURLResponse alloc] initWithURL:urlSchemeTask.request.URL statusCode:statusCode HTTPVersion:@"HTTP/1.1" headerFields:headerFields] autorelease]; - - [urlSchemeTask didReceiveResponse:response]; - }); -} -*/ -import "C" - -import ( - "encoding/json" - "fmt" - "net/http" - "unsafe" -) - -var _ ResponseWriter = &responseWriter{} - -type responseWriter struct { - r *request - - header http.Header - wroteHeader bool - - finished bool -} - -func (rw *responseWriter) Header() http.Header { - if rw.header == nil { - rw.header = http.Header{} - } - return rw.header -} - -func (rw *responseWriter) Write(buf []byte) (int, error) { - if rw.finished { - return 0, errResponseFinished - } - - rw.WriteHeader(http.StatusOK) - - var contentLen int - if buf != nil { - contentLen = len(buf) - } - - if contentLen > 0 { - // Create a C array to hold the data - cBuf := C.malloc(C.size_t(contentLen)) - if cBuf == nil { - return 0, fmt.Errorf("memory allocation failed for %d bytes", contentLen) - } - defer C.free(cBuf) - - // Copy the Go slice to the C array - C.memcpy(cBuf, unsafe.Pointer(&buf[0]), C.size_t(contentLen)) - - if !C.URLSchemeTaskDidReceiveData(rw.r.task, cBuf, C.int(contentLen)) { - return 0, errRequestStopped - } - } else { - if !C.URLSchemeTaskDidReceiveData(rw.r.task, nil, 0) { - return 0, errRequestStopped - } - } - - return contentLen, nil -} - -func (rw *responseWriter) WriteHeader(code int) { - if rw.wroteHeader || rw.finished { - return - } - rw.wroteHeader = true - - header := map[string]string{} - for k := range rw.Header() { - header[k] = rw.Header().Get(k) - } - headerData, _ := json.Marshal(header) - - var headers unsafe.Pointer - var headersLen int - if len(headerData) != 0 { - headers = unsafe.Pointer(&headerData[0]) - headersLen = len(headerData) - } - - C.URLSchemeTaskDidReceiveResponse(rw.r.task, C.int(code), headers, C.int(headersLen)) -} - -func (rw *responseWriter) Finish() error { - if !rw.wroteHeader { - rw.WriteHeader(http.StatusNotImplemented) - } - - if rw.finished { - return nil - } - rw.finished = true - - C.URLSchemeTaskDidFinish(rw.r.task) - return nil -} diff --git a/v2/pkg/assetserver/webview/responsewriter_linux.go b/v2/pkg/assetserver/webview/responsewriter_linux.go deleted file mode 100644 index 59646ce29..000000000 --- a/v2/pkg/assetserver/webview/responsewriter_linux.go +++ /dev/null @@ -1,132 +0,0 @@ -//go:build linux -// +build linux - -package webview - -/* -#cgo linux pkg-config: gtk+-3.0 gio-unix-2.0 -#cgo !webkit2_41 pkg-config: webkit2gtk-4.0 -#cgo webkit2_41 pkg-config: webkit2gtk-4.1 - -#include "gtk/gtk.h" -#include "webkit2/webkit2.h" -#include "gio/gunixinputstream.h" - -*/ -import "C" -import ( - "fmt" - "io" - "net/http" - "os" - "strconv" - "syscall" - "unsafe" -) - -type responseWriter struct { - req *C.WebKitURISchemeRequest - - header http.Header - wroteHeader bool - finished bool - - w io.WriteCloser - wErr error -} - -func (rw *responseWriter) Header() http.Header { - if rw.header == nil { - rw.header = http.Header{} - } - return rw.header -} - -func (rw *responseWriter) Write(buf []byte) (int, error) { - if rw.finished { - return 0, errResponseFinished - } - - rw.WriteHeader(http.StatusOK) - if rw.wErr != nil { - return 0, rw.wErr - } - return rw.w.Write(buf) -} - -func (rw *responseWriter) WriteHeader(code int) { - if rw.wroteHeader || rw.finished { - return - } - rw.wroteHeader = true - - contentLength := int64(-1) - if sLen := rw.Header().Get(HeaderContentLength); sLen != "" { - if pLen, _ := strconv.ParseInt(sLen, 10, 64); pLen > 0 { - contentLength = pLen - } - } - - // We can't use os.Pipe here, because that returns files with a finalizer for closing the FD. But the control over the - // read FD is given to the InputStream and will be closed there. - // Furthermore we especially don't want to have the FD_CLOEXEC - rFD, w, err := pipe() - if err != nil { - rw.finishWithError(http.StatusInternalServerError, fmt.Errorf("unable to open pipe: %s", err)) - return - } - rw.w = w - - stream := C.g_unix_input_stream_new(C.int(rFD), C.gboolean(1)) - defer C.g_object_unref(C.gpointer(stream)) - - if err := webkit_uri_scheme_request_finish(rw.req, code, rw.Header(), stream, contentLength); err != nil { - rw.finishWithError(http.StatusInternalServerError, fmt.Errorf("unable to finish request: %s", err)) - return - } -} - -func (rw *responseWriter) Finish() error { - if !rw.wroteHeader { - rw.WriteHeader(http.StatusNotImplemented) - } - - if rw.finished { - return nil - } - rw.finished = true - if rw.w != nil { - rw.w.Close() - } - return nil -} - -func (rw *responseWriter) finishWithError(code int, err error) { - if rw.w != nil { - rw.w.Close() - rw.w = &nopCloser{io.Discard} - } - rw.wErr = err - - msg := C.CString(err.Error()) - gerr := C.g_error_new_literal(C.g_quark_from_string(msg), C.int(code), msg) - C.webkit_uri_scheme_request_finish_error(rw.req, gerr) - C.g_error_free(gerr) - C.free(unsafe.Pointer(msg)) -} - -type nopCloser struct { - io.Writer -} - -func (nopCloser) Close() error { return nil } - -func pipe() (r int, w *os.File, err error) { - var p [2]int - e := syscall.Pipe2(p[0:], 0) - if e != nil { - return 0, nil, fmt.Errorf("pipe2: %s", e) - } - - return p[0], os.NewFile(uintptr(p[1]), "|1"), nil -} diff --git a/v2/pkg/assetserver/webview/responsewriter_windows.go b/v2/pkg/assetserver/webview/responsewriter_windows.go deleted file mode 100644 index 748d9511b..000000000 --- a/v2/pkg/assetserver/webview/responsewriter_windows.go +++ /dev/null @@ -1,105 +0,0 @@ -//go:build windows -// +build windows - -package webview - -import ( - "bytes" - "fmt" - "net/http" - "strings" -) - -var _ http.ResponseWriter = &responseWriter{} - -type responseWriter struct { - req *request - - header http.Header - wroteHeader bool - code int - body *bytes.Buffer - - finished bool -} - -func (rw *responseWriter) Header() http.Header { - if rw.header == nil { - rw.header = http.Header{} - } - return rw.header -} - -func (rw *responseWriter) Write(buf []byte) (int, error) { - if rw.finished { - return 0, errResponseFinished - } - - rw.WriteHeader(http.StatusOK) - - return rw.body.Write(buf) -} - -func (rw *responseWriter) WriteHeader(code int) { - if rw.wroteHeader || rw.finished { - return - } - rw.wroteHeader = true - - if rw.body == nil { - rw.body = &bytes.Buffer{} - } - - rw.code = code -} - -func (rw *responseWriter) Finish() error { - if !rw.wroteHeader { - rw.WriteHeader(http.StatusNotImplemented) - } - - if rw.finished { - return nil - } - rw.finished = true - - var errs []error - - code := rw.code - if code == http.StatusNotModified { - // WebView2 has problems when a request returns a 304 status code and the WebView2 is going to hang for other - // requests including IPC calls. - errs = append(errs, fmt.Errorf("AssetServer returned 304 - StatusNotModified which are going to hang WebView2, changed code to 505 - StatusInternalServerError")) - code = http.StatusInternalServerError - } - - rw.req.invokeSync(func() { - resp := rw.req.response - - hdrs, err := resp.GetHeaders() - if err != nil { - errs = append(errs, fmt.Errorf("Resp.GetHeaders failed: %s", err)) - } else { - for k, v := range rw.header { - if err := hdrs.AppendHeader(k, strings.Join(v, ",")); err != nil { - errs = append(errs, fmt.Errorf("Resp.AppendHeader failed: %s", err)) - } - } - hdrs.Release() - } - - if err := resp.PutStatusCode(code); err != nil { - errs = append(errs, fmt.Errorf("Resp.PutStatusCode failed: %s", err)) - } - - if err := resp.PutByteContent(rw.body.Bytes()); err != nil { - errs = append(errs, fmt.Errorf("Resp.PutByteContent failed: %s", err)) - } - - if err := rw.req.finishResponse(); err != nil { - errs = append(errs, fmt.Errorf("Resp.finishResponse failed: %s", err)) - } - }) - - return combineErrs(errs) -} diff --git a/v2/pkg/assetserver/webview/webkit2_36+.go b/v2/pkg/assetserver/webview/webkit2_36+.go deleted file mode 100644 index 1f0db3c89..000000000 --- a/v2/pkg/assetserver/webview/webkit2_36+.go +++ /dev/null @@ -1,71 +0,0 @@ -//go:build linux && (webkit2_36 || webkit2_40 || webkit2_41 ) - -package webview - -/* -#cgo linux pkg-config: gtk+-3.0 -#cgo !webkit2_41 pkg-config: webkit2gtk-4.0 libsoup-2.4 -#cgo webkit2_41 pkg-config: webkit2gtk-4.1 libsoup-3.0 - -#include "gtk/gtk.h" -#include "webkit2/webkit2.h" -#include "libsoup/soup.h" -*/ -import "C" - -import ( - "net/http" - "strings" - "unsafe" -) - -func webkit_uri_scheme_request_get_http_method(req *C.WebKitURISchemeRequest) string { - method := C.GoString(C.webkit_uri_scheme_request_get_http_method(req)) - return strings.ToUpper(method) -} - -func webkit_uri_scheme_request_get_http_headers(req *C.WebKitURISchemeRequest) http.Header { - hdrs := C.webkit_uri_scheme_request_get_http_headers(req) - - var iter C.SoupMessageHeadersIter - C.soup_message_headers_iter_init(&iter, hdrs) - - var name *C.char - var value *C.char - - h := http.Header{} - for C.soup_message_headers_iter_next(&iter, &name, &value) != 0 { - h.Add(C.GoString(name), C.GoString(value)) - } - - return h -} - -func webkit_uri_scheme_request_finish(req *C.WebKitURISchemeRequest, code int, header http.Header, stream *C.GInputStream, streamLength int64) error { - resp := C.webkit_uri_scheme_response_new(stream, C.gint64(streamLength)) - defer C.g_object_unref(C.gpointer(resp)) - - cReason := C.CString(http.StatusText(code)) - C.webkit_uri_scheme_response_set_status(resp, C.guint(code), cReason) - C.free(unsafe.Pointer(cReason)) - - cMimeType := C.CString(header.Get(HeaderContentType)) - C.webkit_uri_scheme_response_set_content_type(resp, cMimeType) - C.free(unsafe.Pointer(cMimeType)) - - hdrs := C.soup_message_headers_new(C.SOUP_MESSAGE_HEADERS_RESPONSE) - for name, values := range header { - cName := C.CString(name) - for _, value := range values { - cValue := C.CString(value) - C.soup_message_headers_append(hdrs, cName, cValue) - C.free(unsafe.Pointer(cValue)) - } - C.free(unsafe.Pointer(cName)) - } - - C.webkit_uri_scheme_response_set_http_headers(resp, hdrs) - - C.webkit_uri_scheme_request_finish_with_response(req, resp) - return nil -} diff --git a/v2/pkg/assetserver/webview/webkit2_36.go b/v2/pkg/assetserver/webview/webkit2_36.go deleted file mode 100644 index cd200af8e..000000000 --- a/v2/pkg/assetserver/webview/webkit2_36.go +++ /dev/null @@ -1,21 +0,0 @@ -//go:build linux && webkit2_36 - -package webview - -/* -#cgo linux pkg-config: webkit2gtk-4.0 - -#include "webkit2/webkit2.h" -*/ -import "C" - -import ( - "io" - "net/http" -) - -const Webkit2MinMinorVersion = 36 - -func webkit_uri_scheme_request_get_http_body(_ *C.WebKitURISchemeRequest) io.ReadCloser { - return http.NoBody -} diff --git a/v2/pkg/assetserver/webview/webkit2_40+.go b/v2/pkg/assetserver/webview/webkit2_40+.go deleted file mode 100644 index eb3e439f2..000000000 --- a/v2/pkg/assetserver/webview/webkit2_40+.go +++ /dev/null @@ -1,85 +0,0 @@ -//go:build linux && (webkit2_40 || webkit2_41) - -package webview - -/* -#cgo linux pkg-config: gtk+-3.0 gio-unix-2.0 -#cgo !webkit2_41 pkg-config: webkit2gtk-4.0 -#cgo webkit2_41 pkg-config: webkit2gtk-4.1 - -#include "gtk/gtk.h" -#include "webkit2/webkit2.h" -#include "gio/gunixinputstream.h" -*/ -import "C" - -import ( - "fmt" - "io" - "net/http" - "unsafe" -) - -func webkit_uri_scheme_request_get_http_body(req *C.WebKitURISchemeRequest) io.ReadCloser { - stream := C.webkit_uri_scheme_request_get_http_body(req) - if stream == nil { - return http.NoBody - } - return &webkitRequestBody{stream: stream} -} - -type webkitRequestBody struct { - stream *C.GInputStream - closed bool -} - -// Read implements io.Reader -func (r *webkitRequestBody) Read(p []byte) (int, error) { - if r.closed { - return 0, io.ErrClosedPipe - } - - var content unsafe.Pointer - var contentLen int - if p != nil { - content = unsafe.Pointer(&p[0]) - contentLen = len(p) - } - - var n C.gsize - var gErr *C.GError - res := C.g_input_stream_read_all(r.stream, content, C.gsize(contentLen), &n, nil, &gErr) - if res == 0 { - return 0, formatGError("stream read failed", gErr) - } else if n == 0 { - return 0, io.EOF - } - return int(n), nil -} - -func (r *webkitRequestBody) Close() error { - if r.closed { - return nil - } - r.closed = true - - // https://docs.gtk.org/gio/method.InputStream.close.html - // Streams will be automatically closed when the last reference is dropped, but you might want to call this function - // to make sure resources are released as early as possible. - var err error - var gErr *C.GError - if C.g_input_stream_close(r.stream, nil, &gErr) == 0 { - err = formatGError("stream close failed", gErr) - } - C.g_object_unref(C.gpointer(r.stream)) - r.stream = nil - return err -} - -func formatGError(msg string, gErr *C.GError, args ...any) error { - if gErr != nil && gErr.message != nil { - msg += ": " + C.GoString(gErr.message) - C.g_error_free(gErr) - } - return fmt.Errorf(msg, args...) -} diff --git a/v2/pkg/assetserver/webview/webkit2_40.go b/v2/pkg/assetserver/webview/webkit2_40.go deleted file mode 100644 index 47b504383..000000000 --- a/v2/pkg/assetserver/webview/webkit2_40.go +++ /dev/null @@ -1,5 +0,0 @@ -//go:build linux && webkit2_40 - -package webview - -const Webkit2MinMinorVersion = 40 diff --git a/v2/pkg/assetserver/webview/webkit2_41.go b/v2/pkg/assetserver/webview/webkit2_41.go deleted file mode 100644 index 82f948d06..000000000 --- a/v2/pkg/assetserver/webview/webkit2_41.go +++ /dev/null @@ -1,5 +0,0 @@ -//go:build linux && webkit2_41 - -package webview - -const Webkit2MinMinorVersion = 41 diff --git a/v2/pkg/assetserver/webview/webkit2_legacy.go b/v2/pkg/assetserver/webview/webkit2_legacy.go deleted file mode 100644 index 1d1cf7c2b..000000000 --- a/v2/pkg/assetserver/webview/webkit2_legacy.go +++ /dev/null @@ -1,48 +0,0 @@ -//go:build linux && !(webkit2_36 || webkit2_40 || webkit2_41) - -package webview - -/* -#cgo linux pkg-config: gtk+-3.0 webkit2gtk-4.0 - -#include "gtk/gtk.h" -#include "webkit2/webkit2.h" -*/ -import "C" - -import ( - "fmt" - "io" - "net/http" - "unsafe" -) - -const Webkit2MinMinorVersion = 0 - -func webkit_uri_scheme_request_get_http_method(_ *C.WebKitURISchemeRequest) string { - return http.MethodGet -} - -func webkit_uri_scheme_request_get_http_headers(_ *C.WebKitURISchemeRequest) http.Header { - // Fake some basic default headers that are needed if e.g. request are being proxied to the an external sever, like - // we do in the devserver. - h := http.Header{} - h.Add("Accept", "*/*") - h.Add("User-Agent", "wails.io/605.1.15") - return h -} - -func webkit_uri_scheme_request_get_http_body(_ *C.WebKitURISchemeRequest) io.ReadCloser { - return http.NoBody -} - -func webkit_uri_scheme_request_finish(req *C.WebKitURISchemeRequest, code int, header http.Header, stream *C.GInputStream, streamLength int64) error { - if code != http.StatusOK { - return fmt.Errorf("StatusCodes not supported: %d - %s", code, http.StatusText(code)) - } - - cMimeType := C.CString(header.Get(HeaderContentType)) - C.webkit_uri_scheme_request_finish(req, stream, C.gint64(streamLength), cMimeType) - C.free(unsafe.Pointer(cMimeType)) - return nil -} diff --git a/v2/pkg/buildassets/build/README.md b/v2/pkg/buildassets/build/README.md index 1ae2f677f..c01ea3cb1 100644 --- a/v2/pkg/buildassets/build/README.md +++ b/v2/pkg/buildassets/build/README.md @@ -4,32 +4,58 @@ The build directory is used to house all the build files and assets for your app The structure is: -* bin - Output directory -* darwin - macOS specific files -* windows - Windows specific files + * bin - Output directory + * dialog - Icons for dialogs + * tray - Icons for the system tray + * mac - MacOS specific files + * linux - Linux specific files + * windows - Windows specific files + +## Dialog Icons + +Place any PNG file in this directory to be able to use them in message dialogs. +The files should have names in the following format: `name[-(light|dark)][2x].png` + +Examples: + +* `mypic.png` - Standard definition icon with ID `mypic` +* `mypic-light.png` - Standard definition icon with ID `mypic`, used when system theme is light +* `mypic-dark.png` - Standard definition icon with ID `mypic`, used when system theme is dark +* `mypic2x.png` - High definition icon with ID `mypic` +* `mypic-light2x.png` - High definition icon with ID `mypic`, used when system theme is light +* `mypic-dark2x.png` - High definition icon with ID `mypic`, used when system theme is dark + +### Order of preference + +Icons are selected with the following order of preference: + +For High Definition displays: +* name-(theme)2x.png +* name2x.png +* name-(theme).png +* name.png + +For Standard Definition displays: +* name-(theme).png +* name.png + +## Tray + +Place any PNG file in this directory to be able to use them as tray icons. +The name of the filename will be the ID to reference the image. + +Example: + +* `mypic.png` - May be referenced using `runtime.Tray.SetIcon("mypic")` ## Mac -The `darwin` directory holds files specific to Mac builds. -These may be customised and used as part of the build. To return these files to the default state, simply delete them -and -build with `wails build`. +The `darwin` directory holds files specific to Mac builds, such as `Info.plist`. +These may be customised and used as part of the build. To return these files to the default state, simply delete them and +build with the `-package` flag. -The directory contains the following files: +## Windows -- `Info.plist` - the main plist file used for Mac builds. It is used when building using `wails build`. -- `Info.dev.plist` - same as the main plist file but used when building using `wails dev`. - -## Windows - -The `windows` directory contains the manifest and rc files used when building with `wails build`. +The `windows` directory contains the manifest and rc files used when building with the `-package` flag. These may be customised for your application. To return these files to the default state, simply delete them and -build with `wails build`. - -- `icon.ico` - The icon used for the application. This is used when building using `wails build`. If you wish to - use a different icon, simply replace this file with your own. If it is missing, a new `icon.ico` file - will be created using the `appicon.png` file in the build directory. -- `installer/*` - The files used to create the Windows installer. These are used when building using `wails build`. -- `info.json` - Application details used for Windows builds. The data here will be used by the Windows installer, - as well as the application itself (right click the exe -> properties -> details) -- `wails.exe.manifest` - The main application manifest file. \ No newline at end of file +build with the `-package` flag. \ No newline at end of file diff --git a/v2/pkg/buildassets/build/appicon.png b/v2/pkg/buildassets/build/appicon.png index 63617fe4f..1c1dba67c 100644 Binary files a/v2/pkg/buildassets/build/appicon.png and b/v2/pkg/buildassets/build/appicon.png differ diff --git a/v2/pkg/buildassets/build/darwin/Info.dev.plist b/v2/pkg/buildassets/build/darwin/Info.dev.plist deleted file mode 100644 index 14121ef7c..000000000 --- a/v2/pkg/buildassets/build/darwin/Info.dev.plist +++ /dev/null @@ -1,68 +0,0 @@ - - - - CFBundlePackageType - APPL - CFBundleName - {{.Info.ProductName}} - CFBundleExecutable - {{.OutputFilename}} - CFBundleIdentifier - com.wails.{{.Name}} - CFBundleVersion - {{.Info.ProductVersion}} - CFBundleGetInfoString - {{.Info.Comments}} - CFBundleShortVersionString - {{.Info.ProductVersion}} - CFBundleIconFile - iconfile - LSMinimumSystemVersion - 10.13.0 - NSHighResolutionCapable - true - NSHumanReadableCopyright - {{.Info.Copyright}} - {{if .Info.FileAssociations}} - CFBundleDocumentTypes - - {{range .Info.FileAssociations}} - - CFBundleTypeExtensions - - {{.Ext}} - - CFBundleTypeName - {{.Name}} - CFBundleTypeRole - {{.Role}} - CFBundleTypeIconFile - {{.IconName}} - - {{end}} - - {{end}} - {{if .Info.Protocols}} - CFBundleURLTypes - - {{range .Info.Protocols}} - - CFBundleURLName - com.wails.{{.Scheme}} - CFBundleURLSchemes - - {{.Scheme}} - - CFBundleTypeRole - {{.Role}} - - {{end}} - - {{end}} - NSAppTransportSecurity - - NSAllowsLocalNetworking - - - - diff --git a/v2/pkg/buildassets/build/darwin/Info.plist b/v2/pkg/buildassets/build/darwin/Info.plist deleted file mode 100644 index d17a7475c..000000000 --- a/v2/pkg/buildassets/build/darwin/Info.plist +++ /dev/null @@ -1,63 +0,0 @@ - - - - CFBundlePackageType - APPL - CFBundleName - {{.Info.ProductName}} - CFBundleExecutable - {{.OutputFilename}} - CFBundleIdentifier - com.wails.{{.Name}} - CFBundleVersion - {{.Info.ProductVersion}} - CFBundleGetInfoString - {{.Info.Comments}} - CFBundleShortVersionString - {{.Info.ProductVersion}} - CFBundleIconFile - iconfile - LSMinimumSystemVersion - 10.13.0 - NSHighResolutionCapable - true - NSHumanReadableCopyright - {{.Info.Copyright}} - {{if .Info.FileAssociations}} - CFBundleDocumentTypes - - {{range .Info.FileAssociations}} - - CFBundleTypeExtensions - - {{.Ext}} - - CFBundleTypeName - {{.Name}} - CFBundleTypeRole - {{.Role}} - CFBundleTypeIconFile - {{.IconName}} - - {{end}} - - {{end}} - {{if .Info.Protocols}} - CFBundleURLTypes - - {{range .Info.Protocols}} - - CFBundleURLName - com.wails.{{.Scheme}} - CFBundleURLSchemes - - {{.Scheme}} - - CFBundleTypeRole - {{.Role}} - - {{end}} - - {{end}} - - diff --git a/v2/pkg/buildassets/build/darwin/Info.tmpl.plist b/v2/pkg/buildassets/build/darwin/Info.tmpl.plist new file mode 100644 index 000000000..7180c58de --- /dev/null +++ b/v2/pkg/buildassets/build/darwin/Info.tmpl.plist @@ -0,0 +1,14 @@ + + + CFBundlePackageTypeAPPL + CFBundleName{{.Name}} + CFBundleExecutable{{.Name}} + CFBundleIdentifiercom.wails.{{.Name}} + CFBundleVersion1.0.0 + CFBundleGetInfoStringBuilt using Wails (https://wails.app) + CFBundleShortVersionString1.0.0 + CFBundleIconFileiconfile + LSMinimumSystemVersion10.13.0 + NSHighResolutionCapabletrue + NSHumanReadableCopyrightCopyright......... + \ No newline at end of file diff --git a/v2/pkg/buildassets/build/windows/info.json b/v2/pkg/buildassets/build/windows/info.json deleted file mode 100644 index 9727946b7..000000000 --- a/v2/pkg/buildassets/build/windows/info.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "fixed": { - "file_version": "{{.Info.ProductVersion}}" - }, - "info": { - "0000": { - "ProductVersion": "{{.Info.ProductVersion}}", - "CompanyName": "{{.Info.CompanyName}}", - "FileDescription": "{{.Info.ProductName}}", - "LegalCopyright": "{{.Info.Copyright}}", - "ProductName": "{{.Info.ProductName}}", - "Comments": "{{.Info.Comments}}" - } - } -} \ No newline at end of file diff --git a/v2/pkg/buildassets/build/windows/installer/project.nsi b/v2/pkg/buildassets/build/windows/installer/project.nsi deleted file mode 100644 index 654ae2e49..000000000 --- a/v2/pkg/buildassets/build/windows/installer/project.nsi +++ /dev/null @@ -1,114 +0,0 @@ -Unicode true - -#### -## Please note: Template replacements don't work in this file. They are provided with default defines like -## mentioned underneath. -## If the keyword is not defined, "wails_tools.nsh" will populate them with the values from ProjectInfo. -## If they are defined here, "wails_tools.nsh" will not touch them. This allows to use this project.nsi manually -## from outside of Wails for debugging and development of the installer. -## -## For development first make a wails nsis build to populate the "wails_tools.nsh": -## > wails build --target windows/amd64 --nsis -## Then you can call makensis on this file with specifying the path to your binary: -## For a AMD64 only installer: -## > makensis -DARG_WAILS_AMD64_BINARY=..\..\bin\app.exe -## For a ARM64 only installer: -## > makensis -DARG_WAILS_ARM64_BINARY=..\..\bin\app.exe -## For a installer with both architectures: -## > makensis -DARG_WAILS_AMD64_BINARY=..\..\bin\app-amd64.exe -DARG_WAILS_ARM64_BINARY=..\..\bin\app-arm64.exe -#### -## The following information is taken from the ProjectInfo file, but they can be overwritten here. -#### -## !define INFO_PROJECTNAME "MyProject" # Default "{{.Name}}" -## !define INFO_COMPANYNAME "MyCompany" # Default "{{.Info.CompanyName}}" -## !define INFO_PRODUCTNAME "MyProduct" # Default "{{.Info.ProductName}}" -## !define INFO_PRODUCTVERSION "1.0.0" # Default "{{.Info.ProductVersion}}" -## !define INFO_COPYRIGHT "Copyright" # Default "{{.Info.Copyright}}" -### -## !define PRODUCT_EXECUTABLE "Application.exe" # Default "${INFO_PROJECTNAME}.exe" -## !define UNINST_KEY_NAME "UninstKeyInRegistry" # Default "${INFO_COMPANYNAME}${INFO_PRODUCTNAME}" -#### -## !define REQUEST_EXECUTION_LEVEL "admin" # Default "admin" see also https://nsis.sourceforge.io/Docs/Chapter4.html -#### -## Include the wails tools -#### -!include "wails_tools.nsh" - -# The version information for this two must consist of 4 parts -VIProductVersion "${INFO_PRODUCTVERSION}.0" -VIFileVersion "${INFO_PRODUCTVERSION}.0" - -VIAddVersionKey "CompanyName" "${INFO_COMPANYNAME}" -VIAddVersionKey "FileDescription" "${INFO_PRODUCTNAME} Installer" -VIAddVersionKey "ProductVersion" "${INFO_PRODUCTVERSION}" -VIAddVersionKey "FileVersion" "${INFO_PRODUCTVERSION}" -VIAddVersionKey "LegalCopyright" "${INFO_COPYRIGHT}" -VIAddVersionKey "ProductName" "${INFO_PRODUCTNAME}" - -# Enable HiDPI support. https://nsis.sourceforge.io/Reference/ManifestDPIAware -ManifestDPIAware true - -!include "MUI.nsh" - -!define MUI_ICON "..\icon.ico" -!define MUI_UNICON "..\icon.ico" -# !define MUI_WELCOMEFINISHPAGE_BITMAP "resources\leftimage.bmp" #Include this to add a bitmap on the left side of the Welcome Page. Must be a size of 164x314 -!define MUI_FINISHPAGE_NOAUTOCLOSE # Wait on the INSTFILES page so the user can take a look into the details of the installation steps -!define MUI_ABORTWARNING # This will warn the user if they exit from the installer. - -!insertmacro MUI_PAGE_WELCOME # Welcome to the installer page. -# !insertmacro MUI_PAGE_LICENSE "resources\eula.txt" # Adds a EULA page to the installer -!insertmacro MUI_PAGE_DIRECTORY # In which folder install page. -!insertmacro MUI_PAGE_INSTFILES # Installing page. -!insertmacro MUI_PAGE_FINISH # Finished installation page. - -!insertmacro MUI_UNPAGE_INSTFILES # Uinstalling page - -!insertmacro MUI_LANGUAGE "English" # Set the Language of the installer - -## The following two statements can be used to sign the installer and the uninstaller. The path to the binaries are provided in %1 -#!uninstfinalize 'signtool --file "%1"' -#!finalize 'signtool --file "%1"' - -Name "${INFO_PRODUCTNAME}" -OutFile "..\..\bin\${INFO_PROJECTNAME}-${ARCH}-installer.exe" # Name of the installer's file. -InstallDir "$PROGRAMFILES64\${INFO_COMPANYNAME}\${INFO_PRODUCTNAME}" # Default installing folder ($PROGRAMFILES is Program Files folder). -ShowInstDetails show # This will always show the installation details. - -Function .onInit - !insertmacro wails.checkArchitecture -FunctionEnd - -Section - !insertmacro wails.setShellContext - - !insertmacro wails.webview2runtime - - SetOutPath $INSTDIR - - !insertmacro wails.files - - CreateShortcut "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}" - CreateShortCut "$DESKTOP\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}" - - !insertmacro wails.associateFiles - !insertmacro wails.associateCustomProtocols - - !insertmacro wails.writeUninstaller -SectionEnd - -Section "uninstall" - !insertmacro wails.setShellContext - - RMDir /r "$AppData\${PRODUCT_EXECUTABLE}" # Remove the WebView2 DataPath - - RMDir /r $INSTDIR - - Delete "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk" - Delete "$DESKTOP\${INFO_PRODUCTNAME}.lnk" - - !insertmacro wails.unassociateFiles - !insertmacro wails.unassociateCustomProtocols - - !insertmacro wails.deleteUninstaller -SectionEnd diff --git a/v2/pkg/buildassets/build/windows/installer/wails_tools.nsh b/v2/pkg/buildassets/build/windows/installer/wails_tools.nsh deleted file mode 100644 index 2f6d32195..000000000 --- a/v2/pkg/buildassets/build/windows/installer/wails_tools.nsh +++ /dev/null @@ -1,249 +0,0 @@ -# DO NOT EDIT - Generated automatically by `wails build` - -!include "x64.nsh" -!include "WinVer.nsh" -!include "FileFunc.nsh" - -!ifndef INFO_PROJECTNAME - !define INFO_PROJECTNAME "{{.Name}}" -!endif -!ifndef INFO_COMPANYNAME - !define INFO_COMPANYNAME "{{.Info.CompanyName}}" -!endif -!ifndef INFO_PRODUCTNAME - !define INFO_PRODUCTNAME "{{.Info.ProductName}}" -!endif -!ifndef INFO_PRODUCTVERSION - !define INFO_PRODUCTVERSION "{{.Info.ProductVersion}}" -!endif -!ifndef INFO_COPYRIGHT - !define INFO_COPYRIGHT "{{.Info.Copyright}}" -!endif -!ifndef PRODUCT_EXECUTABLE - !define PRODUCT_EXECUTABLE "${INFO_PROJECTNAME}.exe" -!endif -!ifndef UNINST_KEY_NAME - !define UNINST_KEY_NAME "${INFO_COMPANYNAME}${INFO_PRODUCTNAME}" -!endif -!define UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINST_KEY_NAME}" - -!ifndef REQUEST_EXECUTION_LEVEL - !define REQUEST_EXECUTION_LEVEL "admin" -!endif - -RequestExecutionLevel "${REQUEST_EXECUTION_LEVEL}" - -!ifdef ARG_WAILS_AMD64_BINARY - !define SUPPORTS_AMD64 -!endif - -!ifdef ARG_WAILS_ARM64_BINARY - !define SUPPORTS_ARM64 -!endif - -!ifdef SUPPORTS_AMD64 - !ifdef SUPPORTS_ARM64 - !define ARCH "amd64_arm64" - !else - !define ARCH "amd64" - !endif -!else - !ifdef SUPPORTS_ARM64 - !define ARCH "arm64" - !else - !error "Wails: Undefined ARCH, please provide at least one of ARG_WAILS_AMD64_BINARY or ARG_WAILS_ARM64_BINARY" - !endif -!endif - -!macro wails.checkArchitecture - !ifndef WAILS_WIN10_REQUIRED - !define WAILS_WIN10_REQUIRED "This product is only supported on Windows 10 (Server 2016) and later." - !endif - - !ifndef WAILS_ARCHITECTURE_NOT_SUPPORTED - !define WAILS_ARCHITECTURE_NOT_SUPPORTED "This product can't be installed on the current Windows architecture. Supports: ${ARCH}" - !endif - - ${If} ${AtLeastWin10} - !ifdef SUPPORTS_AMD64 - ${if} ${IsNativeAMD64} - Goto ok - ${EndIf} - !endif - - !ifdef SUPPORTS_ARM64 - ${if} ${IsNativeARM64} - Goto ok - ${EndIf} - !endif - - IfSilent silentArch notSilentArch - silentArch: - SetErrorLevel 65 - Abort - notSilentArch: - MessageBox MB_OK "${WAILS_ARCHITECTURE_NOT_SUPPORTED}" - Quit - ${else} - IfSilent silentWin notSilentWin - silentWin: - SetErrorLevel 64 - Abort - notSilentWin: - MessageBox MB_OK "${WAILS_WIN10_REQUIRED}" - Quit - ${EndIf} - - ok: -!macroend - -!macro wails.files - !ifdef SUPPORTS_AMD64 - ${if} ${IsNativeAMD64} - File "/oname=${PRODUCT_EXECUTABLE}" "${ARG_WAILS_AMD64_BINARY}" - ${EndIf} - !endif - - !ifdef SUPPORTS_ARM64 - ${if} ${IsNativeARM64} - File "/oname=${PRODUCT_EXECUTABLE}" "${ARG_WAILS_ARM64_BINARY}" - ${EndIf} - !endif -!macroend - -!macro wails.writeUninstaller - WriteUninstaller "$INSTDIR\uninstall.exe" - - SetRegView 64 - WriteRegStr HKLM "${UNINST_KEY}" "Publisher" "${INFO_COMPANYNAME}" - WriteRegStr HKLM "${UNINST_KEY}" "DisplayName" "${INFO_PRODUCTNAME}" - WriteRegStr HKLM "${UNINST_KEY}" "DisplayVersion" "${INFO_PRODUCTVERSION}" - WriteRegStr HKLM "${UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PRODUCT_EXECUTABLE}" - WriteRegStr HKLM "${UNINST_KEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\"" - WriteRegStr HKLM "${UNINST_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S" - - ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2 - IntFmt $0 "0x%08X" $0 - WriteRegDWORD HKLM "${UNINST_KEY}" "EstimatedSize" "$0" -!macroend - -!macro wails.deleteUninstaller - Delete "$INSTDIR\uninstall.exe" - - SetRegView 64 - DeleteRegKey HKLM "${UNINST_KEY}" -!macroend - -!macro wails.setShellContext - ${If} ${REQUEST_EXECUTION_LEVEL} == "admin" - SetShellVarContext all - ${else} - SetShellVarContext current - ${EndIf} -!macroend - -# Install webview2 by launching the bootstrapper -# See https://docs.microsoft.com/en-us/microsoft-edge/webview2/concepts/distribution#online-only-deployment -!macro wails.webview2runtime - !ifndef WAILS_INSTALL_WEBVIEW_DETAILPRINT - !define WAILS_INSTALL_WEBVIEW_DETAILPRINT "Installing: WebView2 Runtime" - !endif - - SetRegView 64 - # If the admin key exists and is not empty then webview2 is already installed - ReadRegStr $0 HKLM "SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv" - ${If} $0 != "" - Goto ok - ${EndIf} - - ${If} ${REQUEST_EXECUTION_LEVEL} == "user" - # If the installer is run in user level, check the user specific key exists and is not empty then webview2 is already installed - ReadRegStr $0 HKCU "Software\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv" - ${If} $0 != "" - Goto ok - ${EndIf} - ${EndIf} - - SetDetailsPrint both - DetailPrint "${WAILS_INSTALL_WEBVIEW_DETAILPRINT}" - SetDetailsPrint listonly - - InitPluginsDir - CreateDirectory "$pluginsdir\webview2bootstrapper" - SetOutPath "$pluginsdir\webview2bootstrapper" - File "tmp\MicrosoftEdgeWebview2Setup.exe" - ExecWait '"$pluginsdir\webview2bootstrapper\MicrosoftEdgeWebview2Setup.exe" /silent /install' - - SetDetailsPrint both - ok: -!macroend - -# Copy of APP_ASSOCIATE and APP_UNASSOCIATE macros from here https://gist.github.com/nikku/281d0ef126dbc215dd58bfd5b3a5cd5b -!macro APP_ASSOCIATE EXT FILECLASS DESCRIPTION ICON COMMANDTEXT COMMAND - ; Backup the previously associated file class - ReadRegStr $R0 SHELL_CONTEXT "Software\Classes\.${EXT}" "" - WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "${FILECLASS}_backup" "$R0" - - WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "" "${FILECLASS}" - - WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}" "" `${DESCRIPTION}` - WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\DefaultIcon" "" `${ICON}` - WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell" "" "open" - WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell\open" "" `${COMMANDTEXT}` - WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell\open\command" "" `${COMMAND}` -!macroend - -!macro APP_UNASSOCIATE EXT FILECLASS - ; Backup the previously associated file class - ReadRegStr $R0 SHELL_CONTEXT "Software\Classes\.${EXT}" `${FILECLASS}_backup` - WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "" "$R0" - - DeleteRegKey SHELL_CONTEXT `Software\Classes\${FILECLASS}` -!macroend - -!macro wails.associateFiles - ; Create file associations - {{range .Info.FileAssociations}} - !insertmacro APP_ASSOCIATE "{{.Ext}}" "{{.Name}}" "{{.Description}}" "$INSTDIR\{{.IconName}}.ico" "Open with ${INFO_PRODUCTNAME}" "$INSTDIR\${PRODUCT_EXECUTABLE} $\"%1$\"" - - File "..\{{.IconName}}.ico" - {{end}} -!macroend - -!macro wails.unassociateFiles - ; Delete app associations - {{range .Info.FileAssociations}} - !insertmacro APP_UNASSOCIATE "{{.Ext}}" "{{.Name}}" - - Delete "$INSTDIR\{{.IconName}}.ico" - {{end}} -!macroend - -!macro CUSTOM_PROTOCOL_ASSOCIATE PROTOCOL DESCRIPTION ICON COMMAND - DeleteRegKey SHELL_CONTEXT "Software\Classes\${PROTOCOL}" - WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}" "" "${DESCRIPTION}" - WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}" "URL Protocol" "" - WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\DefaultIcon" "" "${ICON}" - WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell" "" "" - WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell\open" "" "" - WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell\open\command" "" "${COMMAND}" -!macroend - -!macro CUSTOM_PROTOCOL_UNASSOCIATE PROTOCOL - DeleteRegKey SHELL_CONTEXT "Software\Classes\${PROTOCOL}" -!macroend - -!macro wails.associateCustomProtocols - ; Create custom protocols associations - {{range .Info.Protocols}} - !insertmacro CUSTOM_PROTOCOL_ASSOCIATE "{{.Scheme}}" "{{.Description}}" "$INSTDIR\${PRODUCT_EXECUTABLE},0" "$INSTDIR\${PRODUCT_EXECUTABLE} $\"%1$\"" - - {{end}} -!macroend - -!macro wails.unassociateCustomProtocols - ; Delete app custom protocol associations - {{range .Info.Protocols}} - !insertmacro CUSTOM_PROTOCOL_UNASSOCIATE "{{.Scheme}}" - {{end}} -!macroend diff --git a/v2/pkg/buildassets/build/windows/wails.exe.manifest b/v2/pkg/buildassets/build/windows/wails.exe.manifest index 17e1a2387..0cb94320a 100644 --- a/v2/pkg/buildassets/build/windows/wails.exe.manifest +++ b/v2/pkg/buildassets/build/windows/wails.exe.manifest @@ -1,6 +1,6 @@ - + diff --git a/v2/pkg/buildassets/buildassets.go b/v2/pkg/buildassets/buildassets.go index 6934b98bd..138b387fd 100644 --- a/v2/pkg/buildassets/buildassets.go +++ b/v2/pkg/buildassets/buildassets.go @@ -1,35 +1,33 @@ package buildassets import ( - "bytes" "embed" - "errors" - "fmt" - iofs "io/fs" + "github.com/leaanthony/debme" + "github.com/leaanthony/gosod" "os" "path/filepath" - "text/template" - - "github.com/leaanthony/gosod" - "github.com/samber/lo" - "github.com/wailsapp/wails/v2/internal/fs" - "github.com/wailsapp/wails/v2/internal/project" ) //go:embed build var assets embed.FS -// Same as assets but chrooted into /build/ -var buildAssets iofs.FS - -func init() { - buildAssets = lo.Must(iofs.Sub(assets, "build")) +type assetData struct { + Name string } // Install will install all default project assets -func Install(targetDir string) error { +func Install(targetDir string, projectName string) error { templateDir := gosod.New(assets) - err := templateDir.Extract(targetDir, nil) + err := templateDir.Extract(targetDir, &assetData{Name: projectName}) + if err != nil { + return err + } + + // Rename the manifest file + windowsDir := filepath.Join(targetDir, "build", "windows") + manifest := filepath.Join(windowsDir, "wails.exe.manifest") + targetFile := filepath.Join(windowsDir, projectName+".exe.manifest") + err = os.Rename(manifest, targetFile) if err != nil { return err } @@ -37,106 +35,18 @@ func Install(targetDir string) error { return nil } -// GetLocalPath returns the local path of the requested build asset file -func GetLocalPath(projectData *project.Project, file string) string { - return filepath.Clean(filepath.Join(projectData.GetBuildDir(), filepath.FromSlash(file))) -} - -// ReadFile reads the file from the project build folder. -// If the file does not exist it falls back to the embedded file and the file will be written -// to the disk for customisation. -func ReadFile(projectData *project.Project, file string) ([]byte, error) { - localFilePath := GetLocalPath(projectData, file) - - content, err := os.ReadFile(localFilePath) - if errors.Is(err, iofs.ErrNotExist) { - // The file does not exist, let's read it from the assets FS and write it to disk - content, err := iofs.ReadFile(buildAssets, file) - if err != nil { - return nil, err - } - - if err := writeFileSystemFile(projectData, file, content); err != nil { - return nil, fmt.Errorf("Unable to create file in build folder: %s", err) - } - return content, nil - } - - return content, err -} - -// ReadFileWithProjectData reads the file from the project build folder and replaces ProjectInfo if necessary. -// If the file does not exist it falls back to the embedded file and the file will be written -// to the disk for customisation. The file written is the original unresolved one. -func ReadFileWithProjectData(projectData *project.Project, file string) ([]byte, error) { - content, err := ReadFile(projectData, file) +func RegenerateManifest(target string) error { + a, err := debme.FS(assets, "build") if err != nil { - return nil, err - } - - content, err = resolveProjectData(content, projectData) - if err != nil { - return nil, fmt.Errorf("Unable to resolve data in %s: %w", file, err) - } - return content, nil -} - -// ReadOriginalFileWithProjectDataAndSave reads the file from the embedded assets and replaces -// ProjectInfo if necessary. -// It will also write the resolved final file back to the project build folder. -func ReadOriginalFileWithProjectDataAndSave(projectData *project.Project, file string) ([]byte, error) { - content, err := iofs.ReadFile(buildAssets, file) - if err != nil { - return nil, fmt.Errorf("Unable to read file %s: %w", file, err) - } - - content, err = resolveProjectData(content, projectData) - if err != nil { - return nil, fmt.Errorf("Unable to resolve data in %s: %w", file, err) - } - - if err := writeFileSystemFile(projectData, file, content); err != nil { - return nil, fmt.Errorf("Unable to create file in build folder: %w", err) - } - return content, nil -} - -type assetData struct { - Name string - Info project.Info - OutputFilename string -} - -func resolveProjectData(content []byte, projectData *project.Project) ([]byte, error) { - tmpl, err := template.New("").Parse(string(content)) - if err != nil { - return nil, err - } - - data := &assetData{ - Name: projectData.Name, - Info: projectData.Info, - OutputFilename: projectData.OutputFilename, - } - - var out bytes.Buffer - if err := tmpl.Execute(&out, data); err != nil { - return nil, err - } - return out.Bytes(), nil -} - -func writeFileSystemFile(projectData *project.Project, file string, content []byte) error { - targetPath := GetLocalPath(projectData, file) - - if dir := filepath.Dir(targetPath); !fs.DirExists(dir) { - if err := fs.MkDirs(dir, 0o755); err != nil { - return fmt.Errorf("Unable to create directory: %w", err) - } - } - - if err := os.WriteFile(targetPath, content, 0o644); err != nil { return err } - return nil + return a.CopyFile("windows/wails.exe.manifest", target, 0644) +} + +func RegenerateAppIcon(target string) error { + a, err := debme.FS(assets, "build") + if err != nil { + return err + } + return a.CopyFile("appicon.png", target, 0644) } diff --git a/v2/pkg/clilogger/clilogger.go b/v2/pkg/clilogger/clilogger.go index efc202bbd..aa64fab5f 100644 --- a/v2/pkg/clilogger/clilogger.go +++ b/v2/pkg/clilogger/clilogger.go @@ -34,7 +34,7 @@ func (c *CLILogger) Print(message string, args ...interface{}) { _, err := fmt.Fprintf(c.Writer, message, args...) if err != nil { - c.Fatal("FATAL: " + err.Error()) + c.Fatal("Fatal: ", err) } } @@ -46,7 +46,7 @@ func (c *CLILogger) Println(message string, args ...interface{}) { temp := fmt.Sprintf(message, args...) _, err := fmt.Fprintln(c.Writer, temp) if err != nil { - c.Fatal("FATAL: " + err.Error()) + c.Fatal("Fatal: ", err) } } diff --git a/v2/pkg/commands/bindings/bindings.go b/v2/pkg/commands/bindings/bindings.go deleted file mode 100644 index 82ce0d58f..000000000 --- a/v2/pkg/commands/bindings/bindings.go +++ /dev/null @@ -1,97 +0,0 @@ -package bindings - -import ( - "fmt" - "log" - "os" - "path/filepath" - "runtime" - - "github.com/samber/lo" - "github.com/wailsapp/wails/v2/internal/colour" - "github.com/wailsapp/wails/v2/internal/shell" - "github.com/wailsapp/wails/v2/pkg/commands/buildtags" -) - -// Options for generating bindings -type Options struct { - Filename string - Tags []string - ProjectDirectory string - Compiler string - GoModTidy bool - TsPrefix string - TsSuffix string - TsOutputType string -} - -// GenerateBindings generates bindings for the Wails project in the given ProjectDirectory. -// If no project directory is given then the current working directory is used. -func GenerateBindings(options Options) (string, error) { - filename, _ := lo.Coalesce(options.Filename, "wailsbindings") - if runtime.GOOS == "windows" { - filename += ".exe" - } - - // go build -tags bindings -o bindings.exe - tempDir := os.TempDir() - filename = filepath.Join(tempDir, filename) - - workingDirectory, _ := lo.Coalesce(options.ProjectDirectory, lo.Must(os.Getwd())) - - var stdout, stderr string - var err error - - tags := append(options.Tags, "bindings") - genModuleTags := lo.Without(tags, "desktop", "production", "debug", "dev") - tagString := buildtags.Stringify(genModuleTags) - - if options.GoModTidy { - stdout, stderr, err = shell.RunCommand(workingDirectory, options.Compiler, "mod", "tidy") - if err != nil { - return stdout, fmt.Errorf("%s\n%s\n%s", stdout, stderr, err) - } - } - - envBuild := os.Environ() - envBuild = shell.SetEnv(envBuild, "GOOS", runtime.GOOS) - envBuild = shell.SetEnv(envBuild, "GOARCH", runtime.GOARCH) - // wailsbindings is executed on the build machine. - // So, use the default C compiler, not the one set for cross compiling. - envBuild = shell.RemoveEnv(envBuild, "CC") - - stdout, stderr, err = shell.RunCommandWithEnv(envBuild, workingDirectory, options.Compiler, "build", "-buildvcs=false", "-tags", tagString, "-o", filename) - if err != nil { - return stdout, fmt.Errorf("%s\n%s\n%s", stdout, stderr, err) - } - - if runtime.GOOS == "darwin" { - // Remove quarantine attribute - stdout, stderr, err = shell.RunCommand(workingDirectory, "/usr/bin/xattr", "-rc", filename) - if err != nil { - return stdout, fmt.Errorf("%s\n%s\n%s", stdout, stderr, err) - } - } - - defer func() { - // Best effort removal of temp file - _ = os.Remove(filename) - }() - - // Set environment variables accordingly - env := os.Environ() - env = shell.SetEnv(env, "tsprefix", options.TsPrefix) - env = shell.SetEnv(env, "tssuffix", options.TsSuffix) - env = shell.SetEnv(env, "tsoutputtype", options.TsOutputType) - - stdout, stderr, err = shell.RunCommandWithEnv(env, workingDirectory, filename) - if err != nil { - return stdout, fmt.Errorf("%s\n%s\n%s", stdout, stderr, err) - } - - if stderr != "" { - log.Println(colour.DarkYellow(stderr)) - } - - return stdout, nil -} diff --git a/v2/pkg/commands/bindings/bindings_test.go b/v2/pkg/commands/bindings/bindings_test.go deleted file mode 100644 index 53f42f2c7..000000000 --- a/v2/pkg/commands/bindings/bindings_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package bindings - -import ( - "os" - "path/filepath" - "runtime" - "strings" - "testing" - - "github.com/matryer/is" - "github.com/wailsapp/wails/v2/pkg/templates" -) - -const standardBindings = `// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Greet(arg1) { - return window['go']['main']['App']['Greet'](arg1); -} -` - -const obfuscatedBindings = `// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Greet(arg1) { - return ObfuscatedCall(0, [arg1]); -} -` - -func TestGenerateBindings(t *testing.T) { - - i := is.New(t) - - // Get the directory of this file - _, filename, _, _ := runtime.Caller(0) - workingDirectory := filepath.Dir(filename) - - projectDir := filepath.Join(workingDirectory, "test") - - _ = os.RemoveAll(projectDir) - - _, _, err := templates.Install(&templates.Options{ - ProjectName: "test", - TemplateName: "plain", - WailsVersion: "latest", - }) - if err != nil { - println(err.Error()) - t.Fail() - } - - defer func() { - _ = os.RemoveAll(projectDir) - }() - - // Make the go.mod point to local - goModPath := filepath.Join(projectDir, "go.mod") - goMod, err := os.ReadFile(goModPath) - i.NoErr(err) - pathToRepository := filepath.Join(workingDirectory, "..", "..", "..") - absPathToRepo, _ := filepath.Abs(pathToRepository) - goModString := string(goMod) - goModSplit := strings.Split(goModString, "=>") - goModSplit[1] = absPathToRepo - goModString = strings.Join(goModSplit, "=> ") - goMod = []byte(strings.ReplaceAll(goModString, "// replace", "replace")) - // Write file back - err = os.WriteFile(goModPath, goMod, 0755) - i.NoErr(err) - - tests := []struct { - name string - options Options - stdout string - expectedBindings string - wantErr bool - }{ - { - name: "should generate standard bindings with no user tags", - options: Options{ - ProjectDirectory: projectDir, - Compiler: "go", - GoModTidy: true, - }, - expectedBindings: standardBindings, - stdout: "", - wantErr: false, - }, - { - name: "should generate bindings when given tags", - options: Options{ - ProjectDirectory: projectDir, - Compiler: "go", - Tags: []string{"test"}, - GoModTidy: true, - }, - expectedBindings: standardBindings, - stdout: "", - wantErr: false, - }, - { - name: "should generate obfuscated bindings", - options: Options{ - ProjectDirectory: projectDir, - Compiler: "go", - Tags: []string{"obfuscated"}, - GoModTidy: true, - }, - expectedBindings: obfuscatedBindings, - stdout: "", - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - stdout, err := GenerateBindings(tt.options) - i.True((err != nil) == tt.wantErr) - i.Equal(stdout, tt.stdout) - // Read bindings - bindingsFile := filepath.Join(projectDir, "frontend", "wailsjs", "go", "main", "App.js") - bindings, err := os.ReadFile(bindingsFile) - i.NoErr(err) - i.Equal(string(bindings), tt.expectedBindings) - }) - } -} diff --git a/v2/pkg/commands/build/base.go b/v2/pkg/commands/build/base.go index 239932ce8..022495a16 100644 --- a/v2/pkg/commands/build/base.go +++ b/v2/pkg/commands/build/base.go @@ -3,24 +3,22 @@ package build import ( "bytes" "fmt" + "github.com/leaanthony/gosod" + wailsRuntime "github.com/wailsapp/wails/v2/internal/frontend/runtime" + "github.com/wailsapp/wails/v2/internal/frontend/runtime/wrapper" + "io/ioutil" "os" "os/exec" "path/filepath" "runtime" - "strconv" "strings" - "github.com/pterm/pterm" - - "github.com/wailsapp/wails/v2/internal/system" - - "github.com/leaanthony/gosod" - "github.com/wailsapp/wails/v2/internal/frontend/runtime/wrapper" - "github.com/pkg/errors" "github.com/leaanthony/slicer" + "github.com/wailsapp/wails/v2/internal/assetdb" "github.com/wailsapp/wails/v2/internal/fs" + "github.com/wailsapp/wails/v2/internal/html" "github.com/wailsapp/wails/v2/internal/project" "github.com/wailsapp/wails/v2/internal/shell" "github.com/wailsapp/wails/v2/pkg/clilogger" @@ -65,8 +63,51 @@ func (b *BaseBuilder) fileExists(path string) bool { return true } +// buildCustomAssets will iterate through the projects static directory and add all files +// to the application wide asset database. +func (b *BaseBuilder) buildCustomAssets(projectData *project.Project) error { + + // Add trailing slash to Asset directory + customAssetsDir := filepath.Join(projectData.Path, "assets", "custom") + "/" + if !b.fileExists(customAssetsDir) { + err := fs.MkDirs(customAssetsDir) + if err != nil { + return err + } + } + + assets := assetdb.NewAssetDB() + err := filepath.Walk(customAssetsDir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + normalisedPath := filepath.ToSlash(path) + localPath := strings.TrimPrefix(normalisedPath, customAssetsDir) + if len(localPath) == 0 { + return nil + } + if data, err := ioutil.ReadFile(filepath.Join(customAssetsDir, localPath)); err == nil { + assets.AddAsset(localPath, data) + } + + return nil + }) + if err != nil { + return err + } + + // Write assetdb out to root directory + assetsDbFilename := fs.RelativePath("../../../assetsdb.go") + b.addFileToDelete(assetsDbFilename) + err = ioutil.WriteFile(assetsDbFilename, []byte(assets.Serialize("assets", "wails")), 0644) + if err != nil { + return err + } + return nil +} + func (b *BaseBuilder) convertFileToIntegerString(filename string) (string, error) { - rawData, err := os.ReadFile(filename) + rawData, err := ioutil.ReadFile(filename) if err != nil { return "", err } @@ -74,6 +115,7 @@ func (b *BaseBuilder) convertFileToIntegerString(filename string) (string, error } func (b *BaseBuilder) convertByteSliceToIntegerString(data []byte) string { + // Create string builder var result strings.Builder @@ -84,7 +126,8 @@ func (b *BaseBuilder) convertByteSliceToIntegerString(data []byte) string { result.WriteString(fmt.Sprintf("%v,", data[i])) } - result.WriteString(strconv.FormatUint(uint64(data[len(data)-1]), 10)) + result.WriteString(fmt.Sprintf("%v", data[len(data)-1])) + } return result.String() @@ -92,8 +135,10 @@ func (b *BaseBuilder) convertByteSliceToIntegerString(data []byte) string { // CleanUp does post-build housekeeping func (b *BaseBuilder) CleanUp() { + // Delete all the files b.filesToDelete.Each(func(filename string) { + // if file doesn't exist, ignore if !b.fileExists(filename) { return @@ -102,21 +147,8 @@ func (b *BaseBuilder) CleanUp() { // Delete file. We ignore errors because these files will be overwritten // by the next build anyway. _ = os.Remove(filename) - }) -} -func commandPrettifier(args []string) string { - // If we have a single argument, just return it - if len(args) == 1 { - return args[0] - } - // If an argument contains a space, quote it - for i, arg := range args { - if strings.Contains(arg, " ") { - args[i] = fmt.Sprintf("\"%s\"", arg) - } - } - return strings.Join(args, " ") + }) } func (b *BaseBuilder) OutputFilename(options *Options) string { @@ -154,6 +186,7 @@ func (b *BaseBuilder) OutputFilename(options *Options) string { // CompileProject compiles the project func (b *BaseBuilder) CompileProject(options *Options) error { + // Check if the runtime wrapper exists err := generateRuntimeWrapper(options) if err != nil { @@ -162,56 +195,27 @@ func (b *BaseBuilder) CompileProject(options *Options) error { verbose := options.Verbosity == VERBOSE // Run go mod tidy first - if !options.SkipModTidy { - cmd := exec.Command(options.Compiler, "mod", "tidy") - cmd.Stderr = os.Stderr - if verbose { - println("") - cmd.Stdout = os.Stdout - } - err = cmd.Run() - if err != nil { - return err - } + cmd := exec.Command(options.Compiler, "mod", "tidy") + cmd.Stderr = os.Stderr + if verbose { + println("") + cmd.Stdout = os.Stdout } - - commands := slicer.String() - - compiler := options.Compiler - if options.Obfuscated { - if !shell.CommandExists("garble") { - return fmt.Errorf("the 'garble' command was not found. Please install it with `go install mvdan.cc/garble@latest`") - } else { - compiler = "garble" - if options.GarbleArgs != "" { - commands.AddSlice(strings.Split(options.GarbleArgs, " ")) - } - options.UserTags = append(options.UserTags, "obfuscated") - } + err = cmd.Run() + if err != nil { + return err } // Default go build command - commands.Add("build") - - commands.Add("-buildvcs=false") + commands := slicer.String([]string{"build"}) // Add better debugging flags - if options.Mode == Dev || options.Mode == Debug { + if options.Mode == Dev { commands.Add("-gcflags") - commands.Add("all=-N -l") + commands.Add(`"all=-N -l"`) } - if options.ForceBuild { - commands.Add("-a") - } - - if options.TrimPath { - commands.Add("-trimpath") - } - - if options.RaceDetector { - commands.Add("-race") - } + //commands.Add("-a") var tags slicer.StringSlicer tags.Add(options.OutputType) @@ -222,22 +226,9 @@ func (b *BaseBuilder) CompileProject(options *Options) error { tags.Add(options.WebView2Strategy) } - if options.Mode == Production || options.Mode == Debug { + if options.Mode == Production { tags.Add("production") } - // This mode allows you to debug a production build (not dev build) - if options.Mode == Debug { - tags.Add("debug") - } - - // This options allows you to enable devtools in production build (not dev build as it's always enabled there) - if options.Devtools { - tags.Add("devtools") - } - - if options.Obfuscated { - tags.Add("obfuscated") - } tags.Deduplicate() @@ -253,7 +244,7 @@ func (b *BaseBuilder) CompileProject(options *Options) error { if options.Mode == Production { ldflags.Add("-w", "-s") - if options.Platform == "windows" && !options.WindowsConsole { + if runtime.GOOS == "windows" { ldflags.Add("-H windowsgui") } } @@ -266,9 +257,9 @@ func (b *BaseBuilder) CompileProject(options *Options) error { } // Get application build directory - appDir := options.BinDirectory - if options.CleanBinDirectory { - err = cleanBinDirectory(options) + appDir := options.BuildDirectory + if options.CleanBuildDirectory { + err = cleanBuildDirectory(options) if err != nil { return err } @@ -280,20 +271,20 @@ func (b *BaseBuilder) CompileProject(options *Options) error { commands.Add("-o") commands.Add(compiledBinary) + b.projectData.OutputFilename = strings.TrimPrefix(compiledBinary, options.ProjectData.Path) options.CompiledBinary = compiledBinary - // Build the application - cmd := exec.Command(compiler, commands.AsSlice()...) + // Create the command + cmd = exec.Command(options.Compiler, commands.AsSlice()...) cmd.Stderr = os.Stderr if verbose { - pterm.Info.Println("Build command:", compiler, commandPrettifier(commands.AsSlice())) + println(" Build command:", commands.Join(" ")) cmd.Stdout = os.Stdout } // Set the directory cmd.Dir = b.projectData.Path // Add CGO flags - // TODO: Remove this as we don't generate headers any more // We use the project/build dir as a temporary place for our generated c headers buildBaseDir, err := fs.RelativeToCwd("build") if err != nil { @@ -303,20 +294,16 @@ func (b *BaseBuilder) CompileProject(options *Options) error { cmd.Env = os.Environ() // inherit env if options.Platform != "windows" { - // Use shell.UpsertEnv so we don't overwrite user's CGO_CFLAGS - cmd.Env = shell.UpsertEnv(cmd.Env, "CGO_CFLAGS", func(v string) string { - if options.Platform == "darwin" { - if v != "" { - v += " " - } - if !strings.Contains(v, "-mmacosx-version-min") { - v += "-mmacosx-version-min=10.13" - } + // Use upsertEnv so we don't overwrite user's CGO_CFLAGS + cmd.Env = upsertEnv(cmd.Env, "CGO_CFLAGS", func(v string) string { + if v != "" { + v += " " } + v += "-I" + buildBaseDir return v }) - // Use shell.UpsertEnv so we don't overwrite user's CGO_CXXFLAGS - cmd.Env = shell.UpsertEnv(cmd.Env, "CGO_CXXFLAGS", func(v string) string { + // Use upsertEnv so we don't overwrite user's CGO_CXXFLAGS + cmd.Env = upsertEnv(cmd.Env, "CGO_CXXFLAGS", func(v string) string { if v != "" { v += " " } @@ -324,49 +311,21 @@ func (b *BaseBuilder) CompileProject(options *Options) error { return v }) - cmd.Env = shell.UpsertEnv(cmd.Env, "CGO_ENABLED", func(v string) string { + cmd.Env = upsertEnv(cmd.Env, "CGO_ENABLED", func(v string) string { return "1" }) - if options.Platform == "darwin" { - // Determine version so we can link to newer frameworks - // Why doesn't CGO have this option?!?! - info, err := system.GetInfo() - if err != nil { - return err - } - versionSplit := strings.Split(info.OS.Version, ".") - majorVersion, err := strconv.Atoi(versionSplit[0]) - if err != nil { - return err - } - addUTIFramework := majorVersion >= 11 - // Set the minimum Mac SDK to 10.13 - cmd.Env = shell.UpsertEnv(cmd.Env, "CGO_LDFLAGS", func(v string) string { - if v != "" { - v += " " - } - if addUTIFramework { - v += "-framework UniformTypeIdentifiers " - } - if !strings.Contains(v, "-mmacosx-version-min") { - v += "-mmacosx-version-min=10.13" - } - - return v - }) - } } - cmd.Env = shell.UpsertEnv(cmd.Env, "GOOS", func(v string) string { + cmd.Env = upsertEnv(cmd.Env, "GOOS", func(v string) string { return options.Platform }) - cmd.Env = shell.UpsertEnv(cmd.Env, "GOARCH", func(v string) string { + cmd.Env = upsertEnv(cmd.Env, "GOARCH", func(v string) string { return options.Arch }) if verbose { - printBulletPoint("Environment:", strings.Join(cmd.Env, " ")) + println(" Environment:", strings.Join(cmd.Env, " ")) } // Run command @@ -375,34 +334,24 @@ func (b *BaseBuilder) CompileProject(options *Options) error { // Format error if we have one if err != nil { - if options.Platform == "darwin" { - output, _ := cmd.CombinedOutput() - stdErr := string(output) - if strings.Contains(err.Error(), "ld: framework not found UniformTypeIdentifiers") || - strings.Contains(stdErr, "ld: framework not found UniformTypeIdentifiers") { - pterm.Warning.Println(` -NOTE: It would appear that you do not have the latest Xcode cli tools installed. -Please reinstall by doing the following: - 1. Remove the current installation located at "xcode-select -p", EG: sudo rm -rf /Library/Developer/CommandLineTools - 2. Install latest Xcode tools: xcode-select --install`) - } - } return err } + println("Done.") + if !options.Compress { return nil } - printBulletPoint("Compressing application: ") + fmt.Printf("Compressing application: ") // Do we have upx installed? if !shell.CommandExists("upx") { - pterm.Warning.Println("Warning: Cannot compress binary: upx not found") + println("Warning: Cannot compress binary: upx not found") return nil } - args := []string{"--best", "--no-color", "--no-progress", options.CompiledBinary} + var args = []string{"--best", "--no-color", "--no-progress", options.CompiledBinary} if options.CompressFlags != "" { args = strings.Split(options.CompressFlags, " ") @@ -410,29 +359,22 @@ Please reinstall by doing the following: } if verbose { - pterm.Info.Println("upx", strings.Join(args, " ")) + println("upx", strings.Join(args, " ")) } output, err := exec.Command("upx", args...).Output() if err != nil { return errors.Wrap(err, "Error during compression:") } - pterm.Println("Done.") + println("Done.") if verbose { - pterm.Info.Println(string(output)) + println(string(output)) } return nil } func generateRuntimeWrapper(options *Options) error { - if options.WailsJSDir == "" { - cwd, err := os.Getwd() - if err != nil { - return err - } - options.WailsJSDir = filepath.Join(cwd, "frontend") - } wrapperDir := filepath.Join(options.WailsJSDir, "wailsjs", "runtime") _ = os.RemoveAll(wrapperDir) extractor := gosod.New(wrapper.RuntimeWrapper) @@ -441,6 +383,16 @@ func generateRuntimeWrapper(options *Options) error { return err } + //ipcdev.js + err = os.WriteFile(filepath.Join(wrapperDir, "ipcdev.js"), wailsRuntime.DesktopIPC, 0755) + if err != nil { + return err + } + //runtimedev.js + err = os.WriteFile(filepath.Join(wrapperDir, "runtimedev.js"), wailsRuntime.RuntimeDesktopJS, 0755) + if err != nil { + return err + } return nil } @@ -451,6 +403,7 @@ func (b *BaseBuilder) NpmInstall(sourceDir string, verbose bool) error { // NpmInstallUsingCommand runs the given install command in the specified npm project directory func (b *BaseBuilder) NpmInstallUsingCommand(sourceDir string, installCommand string, verbose bool) error { + packageJSON := filepath.Join(sourceDir, "package.json") // Check package.json exists @@ -490,10 +443,7 @@ func (b *BaseBuilder) NpmInstallUsingCommand(sourceDir string, installCommand st } // Shortcut installation - if !install { - if verbose { - pterm.Println("Skipping npm install") - } + if install == false { return nil } @@ -502,10 +452,10 @@ func (b *BaseBuilder) NpmInstallUsingCommand(sourceDir string, installCommand st stdout, stderr, err := shell.RunCommand(sourceDir, cmd[0], cmd[1:]...) if verbose || err != nil { for _, l := range strings.Split(stdout, "\n") { - pterm.Printf(" %s\n", l) + fmt.Printf(" %s\n", l) } for _, l := range strings.Split(stderr, "\n") { - pterm.Printf(" %s\n", l) + fmt.Printf(" %s\n", l) } } @@ -517,10 +467,10 @@ func (b *BaseBuilder) NpmRun(projectDir, buildTarget string, verbose bool) error stdout, stderr, err := shell.RunCommand(projectDir, "npm", "run", buildTarget) if verbose || err != nil { for _, l := range strings.Split(stdout, "\n") { - pterm.Printf(" %s\n", l) + fmt.Printf(" %s\n", l) } for _, l := range strings.Split(stderr, "\n") { - pterm.Printf(" %s\n", l) + fmt.Printf(" %s\n", l) } } return err @@ -536,10 +486,10 @@ func (b *BaseBuilder) NpmRunWithEnvironment(projectDir, buildTarget string, verb err := cmd.Run() if verbose || err != nil { for _, l := range strings.Split(stdo.String(), "\n") { - pterm.Printf(" %s\n", l) + fmt.Printf(" %s\n", l) } for _, l := range strings.Split(stde.String(), "\n") { - pterm.Printf(" %s\n", l) + fmt.Printf(" %s\n", l) } } return err @@ -547,66 +497,88 @@ func (b *BaseBuilder) NpmRunWithEnvironment(projectDir, buildTarget string, verb // BuildFrontend executes the `npm build` command for the frontend directory func (b *BaseBuilder) BuildFrontend(outputLogger *clilogger.CLILogger) error { + verbose := b.options.Verbosity == VERBOSE - frontendDir := b.projectData.GetFrontendDir() - if !fs.DirExists(frontendDir) { - return fmt.Errorf("frontend directory '%s' does not exist", frontendDir) - } + frontendDir := filepath.Join(b.projectData.Path, "frontend") // Check there is an 'InstallCommand' provided in wails.json - installCommand := b.projectData.InstallCommand - if b.projectData.OutputType == "dev" { - installCommand = b.projectData.GetDevInstallerCommand() - } - if installCommand == "" { + if b.projectData.InstallCommand == "" { // No - don't install - printBulletPoint("No Install command. Skipping.") - pterm.Println("") + outputLogger.Println("No Install command. Skipping.") } else { // Do install if needed - printBulletPoint("Installing frontend dependencies: ") + outputLogger.Print("Installing frontend dependencies: ") if verbose { - pterm.Println("") - pterm.Info.Println("Install command: '" + installCommand + "'") + outputLogger.Println("") + outputLogger.Println(" Install command: '" + b.projectData.InstallCommand + "'") } - if err := b.NpmInstallUsingCommand(frontendDir, installCommand, verbose); err != nil { + if err := b.NpmInstallUsingCommand(frontendDir, b.projectData.InstallCommand, verbose); err != nil { return err } outputLogger.Println("Done.") } // Check if there is a build command - buildCommand := b.projectData.BuildCommand - if b.projectData.OutputType == "dev" { - buildCommand = b.projectData.GetDevBuildCommand() + var buildCommand string + switch b.projectData.OutputType { + case "dev": + buildCommand = b.projectData.DevCommand + default: + buildCommand = b.projectData.BuildCommand } if buildCommand == "" { - printBulletPoint("No Build command. Skipping.") - pterm.Println("") + outputLogger.Println("No Build command. Skipping.") // No - ignore return nil } - printBulletPoint("Compiling frontend: ") - cmd := strings.Split(buildCommand, " ") + outputLogger.Print("Compiling frontend: ") + cmd := strings.Split(b.projectData.BuildCommand, " ") if verbose { - pterm.Println("") - pterm.Info.Println("Build command: '" + buildCommand + "'") + outputLogger.Println("") + outputLogger.Println(" Build command: '" + strings.Join(cmd, " ") + "'") } stdout, stderr, err := shell.RunCommand(frontendDir, cmd[0], cmd[1:]...) if verbose || err != nil { for _, l := range strings.Split(stdout, "\n") { - pterm.Printf(" %s\n", l) + fmt.Printf(" %s\n", l) } for _, l := range strings.Split(stderr, "\n") { - pterm.Printf(" %s\n", l) + fmt.Printf(" %s\n", l) } } if err != nil { return err } - pterm.Println("Done.") + outputLogger.Println("Done.") return nil } + +// ExtractAssets gets the assets from the index.html file +func (b *BaseBuilder) ExtractAssets() (*html.AssetBundle, error) { + + // Read in html + //return html.NewAssetBundle(b.projectData.HTML) + return nil, nil +} + +func upsertEnv(env []string, key string, update func(v string) string) []string { + newEnv := make([]string, len(env), len(env)+1) + found := false + for i := range env { + if strings.HasPrefix(env[i], key+"=") { + eqIndex := strings.Index(env[i], "=") + val := env[i][eqIndex+1:] + newEnv[i] = fmt.Sprintf("%s=%v", key, update(val)) + found = true + continue + } + newEnv[i] = env[i] + } + if !found { + newEnv = append(newEnv, fmt.Sprintf("%s=%v", key, update(""))) + } + return newEnv +} diff --git a/v2/pkg/commands/build/base_test.go b/v2/pkg/commands/build/base_test.go index 3b48b24b6..1f3c84cd2 100644 --- a/v2/pkg/commands/build/base_test.go +++ b/v2/pkg/commands/build/base_test.go @@ -2,33 +2,30 @@ package build import "testing" -func Test_commandPrettifier(t *testing.T) { - tests := []struct { - name string - input []string - want string - }{ - { - name: "empty", - input: []string{}, - want: "", - }, - { - name: "one arg", - input: []string{"one"}, - want: "one", - }, - { - name: "args where one has spaces", - input: []string{"one", "two three"}, - want: `one "two three"`, - }, +func TestUpdateEnv(t *testing.T) { + + env := []string{"one=1", "two=a=b", "three="} + newEnv := upsertEnv(env, "two", func(v string) string { + return v + "+added" + }) + newEnv = upsertEnv(newEnv, "newVar", func(v string) string { + return "added" + }) + newEnv = upsertEnv(newEnv, "three", func(v string) string { + return "3" + }) + + if len(newEnv) != 4 { + t.Errorf("expected: 4, got: %d", len(newEnv)) } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := commandPrettifier(tt.input); got != tt.want { - t.Errorf("commandPrettifier() = %v, want %v", got, tt.want) - } - }) + if newEnv[1] != "two=a=b+added" { + t.Errorf("expected: \"two=a=b+added\", got: %q", newEnv[1]) } + if newEnv[2] != "three=3" { + t.Errorf("expected: \"three=3\", got: %q", newEnv[2]) + } + if newEnv[3] != "newVar=added" { + t.Errorf("expected: \"newVar=added\", got: %q", newEnv[3]) + } + } diff --git a/v2/pkg/commands/build/build.go b/v2/pkg/commands/build/build.go index 7263f63ae..9e2798a1b 100644 --- a/v2/pkg/commands/build/build.go +++ b/v2/pkg/commands/build/build.go @@ -2,17 +2,10 @@ package build import ( "fmt" + "log" "os" "path/filepath" "runtime" - "strings" - - "github.com/google/shlex" - "github.com/pterm/pterm" - "github.com/samber/lo" - - "github.com/wailsapp/wails/v2/internal/staticanalysis" - "github.com/wailsapp/wails/v2/pkg/commands/bindings" "github.com/wailsapp/wails/v2/internal/fs" @@ -30,50 +23,38 @@ const ( Dev Mode = iota // Production mode Production - // Debug build - Debug ) // Options contains all the build options as well as the project data type Options struct { - LDFlags string // Optional flags to pass to linker - UserTags []string // Tags to pass to the Go compiler - Logger *clilogger.CLILogger // All output to the logger - OutputType string // EG: desktop, server.... - Mode Mode // release or dev - Devtools bool // Enable devtools in production - ProjectData *project.Project // The project data - Pack bool // Create a package for the app after building - Platform string // The platform to build for - Arch string // The architecture to build for - Compiler string // The compiler command to use - SkipModTidy bool // Skip mod tidy before compile - IgnoreFrontend bool // Indicates if the frontend does not need building - IgnoreApplication bool // Indicates if the application does not need building - OutputFile string // Override the output filename - BinDirectory string // Directory to use to write the built applications - CleanBinDirectory bool // Indicates if the bin output directory should be cleaned before building - CompiledBinary string // Fully qualified path to the compiled binary - KeepAssets bool // Keep the generated assets/files - Verbosity int // Verbosity level (0 - silent, 1 - default, 2 - verbose) - Compress bool // Compress the final binary - CompressFlags string // Flags to pass to UPX - WebView2Strategy string // WebView2 installer strategy - RunDelve bool // Indicates if we should run delve after the build - WailsJSDir string // Directory to generate the wailsjs module - ForceBuild bool // Force - BundleName string // Bundlename for Mac - TrimPath bool // Use Go's trimpath compiler flag - RaceDetector bool // Build with Go's race detector - WindowsConsole bool // Indicates that the windows console should be kept - Obfuscated bool // Indicates that bound methods should be obfuscated - GarbleArgs string // The arguments for Garble - SkipBindings bool // Skip binding generation - SkipEmbedCreate bool // Skip creation of embed files + LDFlags string // Optional flags to pass to linker + UserTags []string // Tags to pass to the Go compiler + Logger *clilogger.CLILogger // All output to the logger + OutputType string // EG: desktop, server.... + Mode Mode // release or dev + ProjectData *project.Project // The project data + Pack bool // Create a package for the app after building + Platform string // The platform to build for + Arch string // The architecture to build for + Compiler string // The compiler command to use + IgnoreFrontend bool // Indicates if the frontend does not need building + OutputFile string // Override the output filename + BuildDirectory string // Directory to use for building the application + CleanBuildDirectory bool // Indicates if the build directory should be cleaned before building + CompiledBinary string // Fully qualified path to the compiled binary + KeepAssets bool // Keep the generated assets/files + Verbosity int // Verbosity level (0 - silent, 1 - default, 2 - verbose) + Compress bool // Compress the final binary + CompressFlags string // Flags to pass to UPX + WebView2Strategy string // WebView2 installer strategy + RunDelve bool // Indicates if we should run delve after the build + WailsJSDir string // Directory to generate the wailsjs module + ForceBuild bool // Force } // Build the project! func Build(options *Options) (string, error) { + // Extract logger outputLogger := options.Logger @@ -83,196 +64,80 @@ func Build(options *Options) (string, error) { return "", err } - // wails js dir - options.WailsJSDir = options.ProjectData.GetWailsJSDir() + // Load project + projectData, err := project.Load(cwd) + if err != nil { + return "", err + } + options.ProjectData = projectData + + // Add default path if it doesn't exist + if projectData.Path == "" { + projectData.Path = cwd + } // Set build directory - options.BinDirectory = filepath.Join(options.ProjectData.GetBuildDir(), "bin") + options.BuildDirectory = filepath.Join(options.ProjectData.Path, "build", "bin") // Save the project type - options.ProjectData.OutputType = options.OutputType + projectData.OutputType = options.OutputType // Create builder var builder Builder - switch options.OutputType { + switch projectData.OutputType { case "desktop": builder = newDesktopBuilder(options) + case "hybrid": + builder = newHybridBuilder(options) + case "server": + builder = newServerBuilder(options) case "dev": builder = newDesktopBuilder(options) default: - return "", fmt.Errorf("cannot build assets for output type %s", options.ProjectData.OutputType) + return "", fmt.Errorf("cannot build assets for output type %s", projectData.OutputType) } // Set up our clean up method defer builder.CleanUp() // Initialise Builder - builder.SetProjectData(options.ProjectData) + builder.SetProjectData(projectData) - hookArgs := map[string]string{ - "${platform}": options.Platform + "/" + options.Arch, - } - - for _, hook := range []string{options.Platform + "/" + options.Arch, options.Platform + "/*", "*/*"} { - if err := execPreBuildHook(outputLogger, options, hook, hookArgs); err != nil { - return "", err - } - } - - // Create embed directories if they don't exist - if !options.SkipEmbedCreate { - if err := CreateEmbedDirectories(cwd, options); err != nil { - return "", err - } - } - - // Generate bindings - if !options.SkipBindings { - err = GenerateBindings(options) - if err != nil { - return "", err - } - } - - if !options.IgnoreFrontend { + if !options.IgnoreFrontend || options.ForceBuild { err = builder.BuildFrontend(outputLogger) if err != nil { return "", err } } - compileBinary := "" - if !options.IgnoreApplication { - compileBinary, err = execBuildApplication(builder, options) - if err != nil { - return "", err - } + // Build the base assets + //err = builder.BuildAssets(options) + //if err != nil { + // return "", err + //} - hookArgs["${bin}"] = compileBinary - for _, hook := range []string{options.Platform + "/" + options.Arch, options.Platform + "/*", "*/*"} { - if err := execPostBuildHook(outputLogger, options, hook, hookArgs); err != nil { - return "", err - } - } - - } - return compileBinary, nil -} - -func CreateEmbedDirectories(cwd string, buildOptions *Options) error { - path := cwd - if buildOptions.ProjectData != nil { - path = buildOptions.ProjectData.Path - } - embedDetails, err := staticanalysis.GetEmbedDetails(path) - if err != nil { - return err - } - - for _, embedDetail := range embedDetails { - fullPath := embedDetail.GetFullPath() - // assumes path is directory only if it has no extension - if filepath.Ext(fullPath) == "" { - if _, err := os.Stat(fullPath); os.IsNotExist(err) { - err := os.MkdirAll(fullPath, 0o755) - if err != nil { - return err - } - f, err := os.Create(filepath.Join(fullPath, "gitkeep")) - if err != nil { - return err - } - _ = f.Close() - } - } - } - - return nil -} - -func fatal(message string) { - printer := pterm.PrefixPrinter{ - MessageStyle: &pterm.ThemeDefault.FatalMessageStyle, - Prefix: pterm.Prefix{ - Style: &pterm.ThemeDefault.FatalPrefixStyle, - Text: " FATAL ", - }, - } - printer.Println(message) - os.Exit(1) -} - -func printBulletPoint(text string, args ...any) { - item := pterm.BulletListItem{ - Level: 2, - Text: text, - } - t, err := pterm.DefaultBulletList.WithItems([]pterm.BulletListItem{item}).Srender() - if err != nil { - fatal(err.Error()) - } - t = strings.Trim(t, "\n\r") - pterm.Printf(t, args...) -} - -func GenerateBindings(buildOptions *Options) error { - obfuscated := buildOptions.Obfuscated - if obfuscated { - printBulletPoint("Generating obfuscated bindings: ") - buildOptions.UserTags = append(buildOptions.UserTags, "obfuscated") - } else { - printBulletPoint("Generating bindings: ") - } - - if buildOptions.ProjectData.Bindings.TsGeneration.OutputType == "" { - buildOptions.ProjectData.Bindings.TsGeneration.OutputType = "classes" - } - - // Generate Bindings - output, err := bindings.GenerateBindings(bindings.Options{ - Compiler: buildOptions.Compiler, - Tags: buildOptions.UserTags, - GoModTidy: !buildOptions.SkipModTidy, - TsPrefix: buildOptions.ProjectData.Bindings.TsGeneration.Prefix, - TsSuffix: buildOptions.ProjectData.Bindings.TsGeneration.Suffix, - TsOutputType: buildOptions.ProjectData.Bindings.TsGeneration.OutputType, - }) - if err != nil { - return err - } - - if buildOptions.Verbosity == VERBOSE { - pterm.Info.Println(output) - } - - pterm.Println("Done.") - - return nil -} - -func execBuildApplication(builder Builder, options *Options) (string, error) { // If we are building for windows, we will need to generate the asset bundle before // compilation. This will be a .syso file in the project root if options.Pack && options.Platform == "windows" { - printBulletPoint("Generating application assets: ") - err := packageApplicationForWindows(options) + outputLogger.Print("Generating bundle assets: ") + err := packageApplication(options) if err != nil { return "", err } - pterm.Println("Done.") + outputLogger.Println("Done.") // When we finish, we will want to remove the syso file defer func() { - err := os.Remove(filepath.Join(options.ProjectData.Path, strings.ReplaceAll(options.ProjectData.Name, " ", "_")+"-res.syso")) + err := os.Remove(filepath.Join(options.ProjectData.Path, options.ProjectData.Name+"-res.syso")) if err != nil { - fatal(err.Error()) + log.Fatal(err) } }() } // Compile the application - printBulletPoint("Compiling application: ") + outputLogger.Print("Compiling application: ") if options.Platform == "darwin" && options.Arch == "universal" { outputFile := builder.OutputFilename(options) @@ -282,169 +147,71 @@ func execBuildApplication(builder Builder, options *Options) (string, error) { // Build amd64 first options.Arch = "amd64" options.OutputFile = amd64Filename - options.CleanBinDirectory = false + options.CleanBuildDirectory = false if options.Verbosity == VERBOSE { - pterm.Println("Building AMD64 Target: " + filepath.Join(options.BinDirectory, options.OutputFile)) + println() + println(" Building AMD64 Target:", filepath.Join(options.BuildDirectory, options.OutputFile)) } - err := builder.CompileProject(options) + err = builder.CompileProject(options) if err != nil { return "", err } // Build arm64 options.Arch = "arm64" options.OutputFile = arm64Filename - options.CleanBinDirectory = false + options.CleanBuildDirectory = false if options.Verbosity == VERBOSE { - pterm.Println("Building ARM64 Target: " + filepath.Join(options.BinDirectory, options.OutputFile)) + println(" Building ARM64 Target:", filepath.Join(options.BuildDirectory, options.OutputFile)) } err = builder.CompileProject(options) - if err != nil { return "", err } // Run lipo if options.Verbosity == VERBOSE { - pterm.Println(fmt.Sprintf("Running lipo: lipo -create -output %s %s %s", outputFile, amd64Filename, arm64Filename)) + println(" Running lipo: ", "lipo", "-create", "-output", outputFile, amd64Filename, arm64Filename) } - _, stderr, err := shell.RunCommand(options.BinDirectory, "lipo", "-create", "-output", outputFile, amd64Filename, arm64Filename) + _, stderr, err := shell.RunCommand(options.BuildDirectory, "lipo", "-create", "-output", outputFile, amd64Filename, arm64Filename) if err != nil { return "", fmt.Errorf("%s - %s", err.Error(), stderr) } // Remove temp binaries - err = fs.DeleteFile(filepath.Join(options.BinDirectory, amd64Filename)) + err = fs.DeleteFile(filepath.Join(options.BuildDirectory, amd64Filename)) if err != nil { return "", err } - err = fs.DeleteFile(filepath.Join(options.BinDirectory, arm64Filename)) + err = fs.DeleteFile(filepath.Join(options.BuildDirectory, arm64Filename)) if err != nil { return "", err } - options.ProjectData.OutputFilename = outputFile - options.CompiledBinary = filepath.Join(options.BinDirectory, outputFile) + projectData.OutputFilename = outputFile + options.CompiledBinary = filepath.Join(options.BuildDirectory, outputFile) } else { - err := builder.CompileProject(options) + err = builder.CompileProject(options) if err != nil { return "", err } } - if runtime.GOOS == "darwin" { - // Remove quarantine attribute - if _, err := os.Stat(options.CompiledBinary); os.IsNotExist(err) { - return "", fmt.Errorf("compiled binary does not exist at path: %s", options.CompiledBinary) - } - stdout, stderr, err := shell.RunCommand(options.BinDirectory, "/usr/bin/xattr", "-rc", options.CompiledBinary) - if err != nil { - return "", fmt.Errorf("%s - %s", err.Error(), stderr) - } - if options.Verbosity == VERBOSE && stdout != "" { - pterm.Info.Println(stdout) - } - } - - pterm.Println("Done.") - // Do we need to pack the app for non-windows? if options.Pack && options.Platform != "windows" { - printBulletPoint("Packaging application: ") + outputLogger.Print("Packaging application: ") // TODO: Allow cross platform build - err := packageProject(options, runtime.GOOS) + err = packageProject(options, runtime.GOOS) if err != nil { return "", err } - pterm.Println("Done.") + outputLogger.Println("Done.") } - if options.Platform == "windows" { - const nativeWebView2Loader = "native_webview2loader" - - tags := options.UserTags - if lo.Contains(tags, nativeWebView2Loader) { - message := "You are using the legacy native WebView2Loader. This loader will be deprecated in the near future. Please report any bugs related to the new loader: https://github.com/wailsapp/wails/issues/2004" - pterm.Warning.Println(message) - } else { - tags = append(tags, nativeWebView2Loader) - message := fmt.Sprintf("Wails is now using the new Go WebView2Loader. If you encounter any issues with it, please report them to https://github.com/wailsapp/wails/issues/2004. You could also use the old legacy loader with `-tags %s`, but keep in mind this will be deprecated in the near future.", strings.Join(tags, ",")) - pterm.Info.Println(message) - } - } - - if options.Platform == "darwin" && (options.Mode == Debug || options.Devtools) { - pterm.Warning.Println("This darwin build contains the use of private APIs. This will not pass Apple's AppStore approval process. Please use it only as a test build for testing and debug purposes.") + // Post compilation tasks + err = builder.PostCompilation(options) + if err != nil { + return "", err } return options.CompiledBinary, nil -} - -func execPreBuildHook(outputLogger *clilogger.CLILogger, options *Options, hookIdentifier string, argReplacements map[string]string) error { - preBuildHook := options.ProjectData.PreBuildHooks[hookIdentifier] - if preBuildHook == "" { - return nil - } - - return executeBuildHook(outputLogger, options, hookIdentifier, argReplacements, preBuildHook, "pre") -} - -func execPostBuildHook(outputLogger *clilogger.CLILogger, options *Options, hookIdentifier string, argReplacements map[string]string) error { - postBuildHook := options.ProjectData.PostBuildHooks[hookIdentifier] - if postBuildHook == "" { - return nil - } - - return executeBuildHook(outputLogger, options, hookIdentifier, argReplacements, postBuildHook, "post") -} - -func executeBuildHook(_ *clilogger.CLILogger, options *Options, hookIdentifier string, argReplacements map[string]string, buildHook string, hookName string) error { - if !options.ProjectData.RunNonNativeBuildHooks { - if hookIdentifier == "" { - // That's the global hook - } else { - platformOfHook := strings.Split(hookIdentifier, "/")[0] - if platformOfHook == "*" { - // That's OK, we don't have a specific platform of the hook - } else if platformOfHook == runtime.GOOS { - // The hook is for host platform - } else { - // Skip a hook which is not native - printBulletPoint(fmt.Sprintf("Non native build hook '%s': Skipping.", hookIdentifier)) - return nil - } - } - } - - printBulletPoint("Executing %s build hook '%s': ", hookName, hookIdentifier) - args, err := shlex.Split(buildHook) - if err != nil { - return fmt.Errorf("could not parse %s build hook command: %w", hookName, err) - } - for i, arg := range args { - newArg := argReplacements[arg] - if newArg == "" { - continue - } - args[i] = newArg - } - - if options.Verbosity == VERBOSE { - pterm.Info.Println(strings.Join(args, " ")) - } - - if !fs.DirExists(options.BinDirectory) { - if err := fs.MkDirs(options.BinDirectory); err != nil { - return fmt.Errorf("could not create target directory: %s", err.Error()) - } - } - - stdout, stderr, err := shell.RunCommand(options.BinDirectory, args[0], args[1:]...) - if options.Verbosity == VERBOSE { - pterm.Info.Println(stdout) - } - if err != nil { - return fmt.Errorf("%s - %s", err.Error(), stderr) - } - pterm.Println("Done.") - - return nil + } diff --git a/v2/pkg/commands/build/builder.go b/v2/pkg/commands/build/builder.go index 6a220c530..81dd5d307 100644 --- a/v2/pkg/commands/build/builder.go +++ b/v2/pkg/commands/build/builder.go @@ -8,8 +8,11 @@ import ( // Builder defines a builder that can build Wails applications type Builder interface { SetProjectData(projectData *project.Project) - BuildFrontend(logger *clilogger.CLILogger) error - CompileProject(options *Options) error - OutputFilename(options *Options) string + BuildAssets(*Options) error + BuildFrontend(*clilogger.CLILogger) error + BuildRuntime(*Options) error + CompileProject(*Options) error + OutputFilename(*Options) string + PostCompilation(*Options) error CleanUp() } diff --git a/v2/pkg/commands/build/desktop.go b/v2/pkg/commands/build/desktop.go index c54eb3035..76623c01a 100644 --- a/v2/pkg/commands/build/desktop.go +++ b/v2/pkg/commands/build/desktop.go @@ -1,5 +1,15 @@ package build +import ( + "fmt" + "github.com/wailsapp/wails/v2/pkg/buildassets" + "io/ioutil" + "path/filepath" + + "github.com/wailsapp/wails/v2/internal/fs" + "github.com/wailsapp/wails/v2/internal/html" +) + // DesktopBuilder builds applications for the desktop type DesktopBuilder struct { *BaseBuilder @@ -10,3 +20,147 @@ func newDesktopBuilder(options *Options) *DesktopBuilder { BaseBuilder: NewBaseBuilder(options), } } + +// BuildAssets builds the assets for the desktop application +func (d *DesktopBuilder) BuildAssets(options *Options) error { + + // Check assets directory exists + if !fs.DirExists(options.ProjectData.BuildDir) { + // Path to default assets + err := buildassets.Install(options.ProjectData.Path, options.ProjectData.Name) + if err != nil { + return err + } + } + + // We only build assets for cgo builds + //userTags := slicer.String(options.UserTags) + //if userTags.Contains("cgo") { + // // Get a list of assets from the HTML + // assets, err := d.BaseBuilder.ExtractAssets() + // if err != nil { + // return err + // } + // + // // Build base assets (HTML/JS/CSS/etc) + // err = d.BuildBaseAssets(assets, options) + // if err != nil { + // return err + // } + //} + + return nil +} + +// BuildBaseAssets builds the assets for the desktop application +func (d *DesktopBuilder) BuildBaseAssets(assets *html.AssetBundle, options *Options) error { + var err error + + outputLogger := options.Logger + outputLogger.Print("Building assets: ") + + // Get target asset directory + assetDir, err := fs.RelativeToCwd("build") + if err != nil { + return err + } + + // Make dir if it doesn't exist + if !fs.DirExists(assetDir) { + err := fs.Mkdir(assetDir) + if err != nil { + return err + } + } + + // Dump assets as C + assetsFile, err := assets.WriteToCFile(assetDir) + if err != nil { + return err + } + d.addFileToDelete(assetsFile) + + // Process Icon + err = d.processApplicationIcon(assetDir) + if err != nil { + return err + } + + // Process Tray Icons + err = d.processTrayIcons(assetDir, options) + if err != nil { + return err + } + + // Process Dialog Icons + err = d.processDialogIcons(assetDir, options) + if err != nil { + return err + } + + outputLogger.Println("Done.") + + return nil +} + +// processApplicationIcon will copy a default icon if one doesn't exist, then, if +// needed, will compile the icon +func (d *DesktopBuilder) processApplicationIcon(assetDir string) error { + + // Copy default icon if one doesn't exist + iconFile := filepath.Join(d.projectData.BuildDir, "appicon.png") + if !fs.FileExists(iconFile) { + err := buildassets.RegenerateAppIcon(iconFile) + if err != nil { + return err + } + } + + // Compile Icon + return d.compileIcon(assetDir, iconFile) +} + +// BuildRuntime builds the Wails javascript runtime and then converts it into a C file +func (d *DesktopBuilder) BuildRuntime(options *Options) error { + + outputLogger := options.Logger + + sourceDir := fs.RelativePath("../../../internal/runtime/js") + + if err := d.NpmInstall(sourceDir, options.Verbosity == VERBOSE); err != nil { + return err + } + + outputLogger.Print("Embedding Runtime: ") + envvars := []string{"WAILSPLATFORM=" + options.Platform} + if err := d.NpmRunWithEnvironment(sourceDir, "build:desktop", false, envvars); err != nil { + return err + } + + wailsJS := fs.RelativePath("../../../internal/runtime/assets/desktop.js") + runtimeData, err := ioutil.ReadFile(wailsJS) + if err != nil { + return err + } + outputLogger.Println("done.") + + // Convert to C structure + runtimeC := ` +// runtime.c (c) 2019-Present Lea Anthony. +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file was auto-generated. DO NOT MODIFY. +const unsigned char runtime[]={` + for _, b := range runtimeData { + runtimeC += fmt.Sprintf("0x%x, ", b) + } + runtimeC += "0x00};" + + // Save file + outputFile := fs.RelativePath("../../../internal/ffenestri/runtime.c") + + if err := ioutil.WriteFile(outputFile, []byte(runtimeC), 0600); err != nil { + return err + } + + return nil +} diff --git a/v2/pkg/commands/build/desktop_darwin.go b/v2/pkg/commands/build/desktop_darwin.go new file mode 100644 index 000000000..bc084f4f4 --- /dev/null +++ b/v2/pkg/commands/build/desktop_darwin.go @@ -0,0 +1,211 @@ +// +build darwin + +package build + +import ( + "fmt" + "io/ioutil" + "log" + "path/filepath" + "strconv" + "strings" + + "github.com/leaanthony/slicer" + "github.com/wailsapp/wails/v2/internal/fs" +) + +func (d *DesktopBuilder) convertToHexLiteral(bytes []byte) string { + result := "" + for _, b := range bytes { + result += fmt.Sprintf("0x%x, ", b) + } + return result +} + +// compileIcon will compile the icon found at /icon.png into the application +func (d *DesktopBuilder) compileIcon(assetDir string, iconFile string) error { + return nil +} + +// We will compile all tray icons found at /assets/trayicons/*.png into the application +func (d *DesktopBuilder) processTrayIcons(assetDir string, options *Options) error { + + var err error + + // Get all the tray icon filenames + trayIconDirectory := filepath.Join(options.ProjectData.BuildDir, "tray") + + // If the directory doesn't exist, create it + if !fs.DirExists(trayIconDirectory) { + err = fs.MkDirs(trayIconDirectory) + if err != nil { + return err + } + } + + var trayIconFilenames []string + trayIconFilenames, err = filepath.Glob(trayIconDirectory + "/*.png") + if err != nil { + log.Fatal(err) + return err + } + + // Setup target + targetFilename := "trayicons" + targetFile := filepath.Join(assetDir, targetFilename+".h") + d.addFileToDelete(targetFile) + + var dataBytes []byte + + // Use a strings builder + var cdata strings.Builder + + // Write header + header := `// trayicons.h +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL. +// This file was auto-generated. DO NOT MODIFY. + +` + cdata.WriteString(header) + + var variableList slicer.StringSlicer + + // Loop over icons + for count, filename := range trayIconFilenames { + + // Load the tray icon + dataBytes, err = ioutil.ReadFile(filename) + if err != nil { + return err + } + + iconname := strings.TrimSuffix(filepath.Base(filename), ".png") + trayIconName := fmt.Sprintf("trayIcon%dName", count) + variableList.Add(trayIconName) + cdata.WriteString(fmt.Sprintf("const unsigned char %s[] = { %s0x00 };\n", trayIconName, d.convertToHexLiteral([]byte(iconname)))) + + trayIconLength := fmt.Sprintf("trayIcon%dLength", count) + variableList.Add(trayIconLength) + lengthAsString := strconv.Itoa(len(dataBytes)) + cdata.WriteString(fmt.Sprintf("const unsigned char %s[] = { %s0x00 };\n", trayIconLength, d.convertToHexLiteral([]byte(lengthAsString)))) + + trayIconData := fmt.Sprintf("trayIcon%dData", count) + variableList.Add(trayIconData) + cdata.WriteString(fmt.Sprintf("const unsigned char %s[] = { ", trayIconData)) + + // Convert each byte to hex + for _, b := range dataBytes { + cdata.WriteString(fmt.Sprintf("0x%x, ", b)) + } + + cdata.WriteString("0x00 };\n") + } + + // Write out main trayIcons data + cdata.WriteString("const unsigned char *trayIcons[] = { ") + cdata.WriteString(variableList.Join(", ")) + if len(trayIconFilenames) > 0 { + cdata.WriteString(", ") + } + cdata.WriteString("0x00 };\n") + + err = ioutil.WriteFile(targetFile, []byte(cdata.String()), 0600) + if err != nil { + return err + } + return nil +} + +// PostCompilation is called after the compilation step, if successful +func (d *DesktopBuilder) PostCompilation(options *Options) error { + return nil +} + +// We will compile all dialog icons found at /icons/dialog/*.png into the application +func (d *DesktopBuilder) processDialogIcons(assetDir string, options *Options) error { + + var err error + + // Get all the dialog icon filenames + dialogIconDirectory := filepath.Join(options.ProjectData.BuildDir, "dialog") + var dialogIconFilenames []string + + // If the directory does not exist, create it + if !fs.DirExists(dialogIconDirectory) { + err = fs.MkDirs(dialogIconDirectory) + if err != nil { + return err + } + } + + dialogIconFilenames, err = filepath.Glob(dialogIconDirectory + "/*.png") + if err != nil { + log.Fatal(err) + return err + } + + // Setup target + targetFilename := "userdialogicons" + targetFile := filepath.Join(assetDir, targetFilename+".h") + d.addFileToDelete(targetFile) + + var dataBytes []byte + + // Use a strings builder + var cdata strings.Builder + + // Write header + header := `// userdialogicons.h +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL. +// This file was auto-generated. DO NOT MODIFY. + +` + cdata.WriteString(header) + + var variableList slicer.StringSlicer + + // Loop over icons + for count, filename := range dialogIconFilenames { + + // Load the tray icon + dataBytes, err = ioutil.ReadFile(filename) + if err != nil { + return err + } + + iconname := strings.TrimSuffix(filepath.Base(filename), ".png") + dialogIconName := fmt.Sprintf("userDialogIcon%dName", count) + variableList.Add(dialogIconName) + cdata.WriteString(fmt.Sprintf("const unsigned char %s[] = { %s0x00 };\n", dialogIconName, d.convertToHexLiteral([]byte(iconname)))) + + dialogIconLength := fmt.Sprintf("userDialogIcon%dLength", count) + variableList.Add(dialogIconLength) + lengthAsString := strconv.Itoa(len(dataBytes)) + cdata.WriteString(fmt.Sprintf("const unsigned char %s[] = { %s0x00 };\n", dialogIconLength, d.convertToHexLiteral([]byte(lengthAsString)))) + + dialogIconData := fmt.Sprintf("userDialogIcon%dData", count) + variableList.Add(dialogIconData) + cdata.WriteString(fmt.Sprintf("const unsigned char %s[] = { ", dialogIconData)) + + // Convert each byte to hex + for _, b := range dataBytes { + cdata.WriteString(fmt.Sprintf("0x%x, ", b)) + } + + cdata.WriteString("0x00 };\n") + } + + // Write out main dialogIcons data + cdata.WriteString("const unsigned char *userDialogIcons[] = { ") + cdata.WriteString(variableList.Join(", ")) + if len(dialogIconFilenames) > 0 { + cdata.WriteString(", ") + } + cdata.WriteString("0x00 };\n") + + err = ioutil.WriteFile(targetFile, []byte(cdata.String()), 0600) + if err != nil { + return err + } + return nil +} diff --git a/v2/pkg/commands/build/desktop_linux.go b/v2/pkg/commands/build/desktop_linux.go new file mode 100644 index 000000000..1d94e5ac6 --- /dev/null +++ b/v2/pkg/commands/build/desktop_linux.go @@ -0,0 +1,240 @@ +// +build linux + +package build + +import ( + "image/png" + "io/ioutil" + "os" + "path/filepath" + "strings" + + "github.com/xyproto/xpm" +) + +// compileIcon will compile the icon found at /icon.png into the application +func (d *DesktopBuilder) compileIcon(assetDir string, iconFile string) error { + + // Load icon into a databuffer + targetFilename := "icon" + targetFile := filepath.Join(assetDir, targetFilename+".h") + + d.addFileToDelete(targetFile) + + // Create a new XPM encoder + enc := xpm.NewEncoder(targetFilename) + + // Open the PNG file + f, err := os.Open(iconFile) + if err != nil { + return err + } + m, err := png.Decode(f) + if err != nil { + return err + } + err = f.Close() + if err != nil { + return err + } + + var buf strings.Builder + + // Generate and output the XPM data + err = enc.Encode(&buf, m) + if err != nil { + return err + } + + // Massage the output so we can extern reference it + output := buf.String() + output = strings.Replace(output, "static char", "const char", 1) + + // save icon.c + err = ioutil.WriteFile(targetFile, []byte(output), 0755) + + return err +} + +// We will compile all tray icons found at /assets/trayicons/*.png into the application +func (d *DesktopBuilder) processTrayIcons(assetDir string, options *Options) error { + // + // var err error + // + // // Get all the tray icon filenames + // trayIconDirectory := filepath.Join(options.ProjectData.BuildDir, "tray") + // + // // If the directory doesn't exist, create it + // if !fs.DirExists(trayIconDirectory) { + // err = fs.MkDirs(trayIconDirectory) + // if err != nil { + // return err + // } + // } + // + // var trayIconFilenames []string + // trayIconFilenames, err = filepath.Glob(trayIconDirectory + "/*.png") + // if err != nil { + // log.Fatal(err) + // return err + // } + // + // // Setup target + // targetFilename := "trayicons" + // targetFile := filepath.Join(assetDir, targetFilename+".h") + // d.addFileToDelete(targetFile) + // + // var dataBytes []byte + // + // // Use a strings builder + // var cdata strings.Builder + // + // // Write header + // header := `// trayicons.h + //// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL. + //// This file was auto-generated. DO NOT MODIFY. + // + //` + // cdata.WriteString(header) + // + // var variableList slicer.StringSlicer + // + // // Loop over icons + // for count, filename := range trayIconFilenames { + // + // // Load the tray icon + // dataBytes, err = ioutil.ReadFile(filename) + // if err != nil { + // return err + // } + // + // iconname := strings.TrimSuffix(filepath.Base(filename), ".png") + // trayIconName := fmt.Sprintf("trayIcon%dName", count) + // variableList.Add(trayIconName) + // cdata.WriteString(fmt.Sprintf("const unsigned char %s[] = { %s0x00 };\n", trayIconName, d.convertToHexLiteral([]byte(iconname)))) + // + // trayIconLength := fmt.Sprintf("trayIcon%dLength", count) + // variableList.Add(trayIconLength) + // lengthAsString := strconv.Itoa(len(dataBytes)) + // cdata.WriteString(fmt.Sprintf("const unsigned char %s[] = { %s0x00 };\n", trayIconLength, d.convertToHexLiteral([]byte(lengthAsString)))) + // + // trayIconData := fmt.Sprintf("trayIcon%dData", count) + // variableList.Add(trayIconData) + // cdata.WriteString(fmt.Sprintf("const unsigned char %s[] = { ", trayIconData)) + // + // // Convert each byte to hex + // for _, b := range dataBytes { + // cdata.WriteString(fmt.Sprintf("0x%x, ", b)) + // } + // + // cdata.WriteString("0x00 };\n") + // } + // + // // Write out main trayIcons data + // cdata.WriteString("const unsigned char *trayIcons[] = { ") + // cdata.WriteString(variableList.Join(", ")) + // if len(trayIconFilenames) > 0 { + // cdata.WriteString(", ") + // } + // cdata.WriteString("0x00 };\n") + // + // err = ioutil.WriteFile(targetFile, []byte(cdata.String()), 0600) + // if err != nil { + // return err + // } + return nil +} + +// We will compile all dialog icons found at /icons/dialog/*.png into the application +func (d *DesktopBuilder) processDialogIcons(assetDir string, options *Options) error { + + // var err error + // + // // Get all the dialog icon filenames + // dialogIconDirectory := filepath.Join(options.ProjectData.BuildDir, "dialog") + // var dialogIconFilenames []string + // + // // If the directory does not exist, create it + // if !fs.DirExists(dialogIconDirectory) { + // err = fs.MkDirs(dialogIconDirectory) + // if err != nil { + // return err + // } + // } + // + // dialogIconFilenames, err = filepath.Glob(dialogIconDirectory + "/*.png") + // if err != nil { + // log.Fatal(err) + // return err + // } + // + // // Setup target + // targetFilename := "userdialogicons" + // targetFile := filepath.Join(assetDir, targetFilename+".h") + // d.addFileToDelete(targetFile) + // + // var dataBytes []byte + // + // // Use a strings builder + // var cdata strings.Builder + // + // // Write header + // header := `// userdialogicons.h + //// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL. + //// This file was auto-generated. DO NOT MODIFY. + // + //` + // cdata.WriteString(header) + // + // var variableList slicer.StringSlicer + // + // // Loop over icons + // for count, filename := range dialogIconFilenames { + // + // // Load the tray icon + // dataBytes, err = ioutil.ReadFile(filename) + // if err != nil { + // return err + // } + // + // iconname := strings.TrimSuffix(filepath.Base(filename), ".png") + // dialogIconName := fmt.Sprintf("userDialogIcon%dName", count) + // variableList.Add(dialogIconName) + // cdata.WriteString(fmt.Sprintf("const unsigned char %s[] = { %s0x00 };\n", dialogIconName, d.convertToHexLiteral([]byte(iconname)))) + // + // dialogIconLength := fmt.Sprintf("userDialogIcon%dLength", count) + // variableList.Add(dialogIconLength) + // lengthAsString := strconv.Itoa(len(dataBytes)) + // cdata.WriteString(fmt.Sprintf("const unsigned char %s[] = { %s0x00 };\n", dialogIconLength, d.convertToHexLiteral([]byte(lengthAsString)))) + // + // dialogIconData := fmt.Sprintf("userDialogIcon%dData", count) + // variableList.Add(dialogIconData) + // cdata.WriteString(fmt.Sprintf("const unsigned char %s[] = { ", dialogIconData)) + // + // // Convert each byte to hex + // for _, b := range dataBytes { + // cdata.WriteString(fmt.Sprintf("0x%x, ", b)) + // } + // + // cdata.WriteString("0x00 };\n") + // } + // + // // Write out main dialogIcons data + // cdata.WriteString("const unsigned char *userDialogIcons[] = { ") + // cdata.WriteString(variableList.Join(", ")) + // if len(dialogIconFilenames) > 0 { + // cdata.WriteString(", ") + // } + // cdata.WriteString("0x00 };\n") + // + // err = ioutil.WriteFile(targetFile, []byte(cdata.String()), 0600) + // if err != nil { + // return err + // } + return nil +} + +// PostCompilation is called after the compilation step, if successful +func (d *DesktopBuilder) PostCompilation(options *Options) error { + return nil +} diff --git a/v2/pkg/commands/build/desktop_windows.go b/v2/pkg/commands/build/desktop_windows.go new file mode 100644 index 000000000..afb2e011f --- /dev/null +++ b/v2/pkg/commands/build/desktop_windows.go @@ -0,0 +1,199 @@ +// +build windows + +package build + +// PostCompilation is called after the compilation step, if successful +func (d *DesktopBuilder) PostCompilation(options *Options) error { + // Dump the DLLs + //userTags := slicer.String(options.UserTags) + //if userTags.Contains("cgo") { + // err := os.WriteFile(filepath.Join(options.BuildDirectory, "WebView2Loader.dll"), x64.WebView2Loader, 0755) + // if err != nil { + // return err + // } + //} + return nil +} + +// We will compile all tray icons found at /assets/trayicons/*.png into the application +func (d *DesktopBuilder) processTrayIcons(assetDir string, options *Options) error { + // + // var err error + // + // // Get all the tray icon filenames + // trayIconDirectory := filepath.Join(options.ProjectData.BuildDir, "tray") + // + // // If the directory doesn't exist, create it + // if !fs.DirExists(trayIconDirectory) { + // err = fs.MkDirs(trayIconDirectory) + // if err != nil { + // return err + // } + // } + // + // var trayIconFilenames []string + // trayIconFilenames, err = filepath.Glob(trayIconDirectory + "/*.png") + // if err != nil { + // log.Fatal(err) + // return err + // } + // + // // Setup target + // targetFilename := "trayicons" + // targetFile := filepath.Join(assetDir, targetFilename+".h") + // d.addFileToDelete(targetFile) + // + // var dataBytes []byte + // + // // Use a strings builder + // var cdata strings.Builder + // + // // Write header + // header := `// trayicons.h + //// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL. + //// This file was auto-generated. DO NOT MODIFY. + // + //` + // cdata.WriteString(header) + // + // var variableList slicer.StringSlicer + // + // // Loop over icons + // for count, filename := range trayIconFilenames { + // + // // Load the tray icon + // dataBytes, err = ioutil.ReadFile(filename) + // if err != nil { + // return err + // } + // + // iconname := strings.TrimSuffix(filepath.Base(filename), ".png") + // trayIconName := fmt.Sprintf("trayIcon%dName", count) + // variableList.Add(trayIconName) + // cdata.WriteString(fmt.Sprintf("const unsigned char %s[] = { %s0x00 };\n", trayIconName, d.convertToHexLiteral([]byte(iconname)))) + // + // trayIconLength := fmt.Sprintf("trayIcon%dLength", count) + // variableList.Add(trayIconLength) + // lengthAsString := strconv.Itoa(len(dataBytes)) + // cdata.WriteString(fmt.Sprintf("const unsigned char %s[] = { %s0x00 };\n", trayIconLength, d.convertToHexLiteral([]byte(lengthAsString)))) + // + // trayIconData := fmt.Sprintf("trayIcon%dData", count) + // variableList.Add(trayIconData) + // cdata.WriteString(fmt.Sprintf("const unsigned char %s[] = { ", trayIconData)) + // + // // Convert each byte to hex + // for _, b := range dataBytes { + // cdata.WriteString(fmt.Sprintf("0x%x, ", b)) + // } + // + // cdata.WriteString("0x00 };\n") + // } + // + // // Write out main trayIcons data + // cdata.WriteString("const unsigned char *trayIcons[] = { ") + // cdata.WriteString(variableList.Join(", ")) + // if len(trayIconFilenames) > 0 { + // cdata.WriteString(", ") + // } + // cdata.WriteString("0x00 };\n") + // + // err = ioutil.WriteFile(targetFile, []byte(cdata.String()), 0600) + // if err != nil { + // return err + // } + return nil +} + +// compileIcon will compile the icon found at /icon.png into the application +func (d *DesktopBuilder) compileIcon(assetDir string, iconFile string) error { + return nil +} + +// We will compile all dialog icons found at /icons/dialog/*.png into the application +func (d *DesktopBuilder) processDialogIcons(assetDir string, options *Options) error { + + // var err error + // + // // Get all the dialog icon filenames + // dialogIconDirectory := filepath.Join(options.ProjectData.BuildDir, "dialog") + // var dialogIconFilenames []string + // + // // If the directory does not exist, create it + // if !fs.DirExists(dialogIconDirectory) { + // err = fs.MkDirs(dialogIconDirectory) + // if err != nil { + // return err + // } + // } + // + // dialogIconFilenames, err = filepath.Glob(dialogIconDirectory + "/*.png") + // if err != nil { + // log.Fatal(err) + // return err + // } + // + // // Setup target + // targetFilename := "userdialogicons" + // targetFile := filepath.Join(assetDir, targetFilename+".h") + // d.addFileToDelete(targetFile) + // + // var dataBytes []byte + // + // // Use a strings builder + // var cdata strings.Builder + // + // // Write header + // header := `// userdialogicons.h + //// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL. + //// This file was auto-generated. DO NOT MODIFY. + // + //` + // cdata.WriteString(header) + // + // var variableList slicer.StringSlicer + // + // // Loop over icons + // for count, filename := range dialogIconFilenames { + // + // // Load the tray icon + // dataBytes, err = ioutil.ReadFile(filename) + // if err != nil { + // return err + // } + // + // iconname := strings.TrimSuffix(filepath.Base(filename), ".png") + // dialogIconName := fmt.Sprintf("userDialogIcon%dName", count) + // variableList.Add(dialogIconName) + // cdata.WriteString(fmt.Sprintf("const unsigned char %s[] = { %s0x00 };\n", dialogIconName, d.convertToHexLiteral([]byte(iconname)))) + // + // dialogIconLength := fmt.Sprintf("userDialogIcon%dLength", count) + // variableList.Add(dialogIconLength) + // lengthAsString := strconv.Itoa(len(dataBytes)) + // cdata.WriteString(fmt.Sprintf("const unsigned char %s[] = { %s0x00 };\n", dialogIconLength, d.convertToHexLiteral([]byte(lengthAsString)))) + // + // dialogIconData := fmt.Sprintf("userDialogIcon%dData", count) + // variableList.Add(dialogIconData) + // cdata.WriteString(fmt.Sprintf("const unsigned char %s[] = { ", dialogIconData)) + // + // // Convert each byte to hex + // for _, b := range dataBytes { + // cdata.WriteString(fmt.Sprintf("0x%x, ", b)) + // } + // + // cdata.WriteString("0x00 };\n") + // } + // + // // Write out main dialogIcons data + // cdata.WriteString("const unsigned char *userDialogIcons[] = { ") + // cdata.WriteString(variableList.Join(", ")) + // if len(dialogIconFilenames) > 0 { + // cdata.WriteString(", ") + // } + // cdata.WriteString("0x00 };\n") + // + // err = ioutil.WriteFile(targetFile, []byte(cdata.String()), 0600) + // if err != nil { + // return err + // } + return nil +} diff --git a/v2/pkg/commands/build/hybrid.go b/v2/pkg/commands/build/hybrid.go new file mode 100644 index 000000000..d21c78e60 --- /dev/null +++ b/v2/pkg/commands/build/hybrid.go @@ -0,0 +1,95 @@ +package build + +import ( + "github.com/wailsapp/wails/v2/internal/project" + "github.com/wailsapp/wails/v2/pkg/clilogger" +) + +// HybridBuilder builds applications as a server +type HybridBuilder struct { + *BaseBuilder + desktop *DesktopBuilder + server *ServerBuilder +} + +func newHybridBuilder(options *Options) Builder { + result := &HybridBuilder{ + BaseBuilder: NewBaseBuilder(options), + desktop: newDesktopBuilder(options), + server: newServerBuilder(options), + } + return result +} + +// BuildAssets builds the assets for the desktop application +func (b *HybridBuilder) BuildAssets(options *Options) error { + var err error + + // Build base assets (HTML/JS/CSS/etc) + err = b.BuildBaseAssets(options) + if err != nil { + return err + } + return nil +} + +// BuildFrontend builds the assets for the desktop application +func (b *HybridBuilder) BuildFrontend(_ *clilogger.CLILogger) error { + panic("To be implemented") + return nil +} + +// BuildAssets builds the assets for the desktop application +func (b *HybridBuilder) BuildBaseAssets(options *Options) error { + + assets, err := b.BaseBuilder.ExtractAssets() + if err != nil { + return err + } + + err = b.desktop.BuildBaseAssets(assets, options) + if err != nil { + return err + } + + err = b.server.BuildBaseAssets(assets) + if err != nil { + return err + } + + return nil +} + +func (b *HybridBuilder) BuildRuntime(options *Options) error { + err := b.desktop.BuildRuntime(options) + if err != nil { + return err + } + + err = b.server.BuildRuntime(options) + if err != nil { + return err + } + + return nil +} + +func (b *HybridBuilder) SetProjectData(projectData *project.Project) { + b.BaseBuilder.SetProjectData(projectData) + b.desktop.SetProjectData(projectData) + b.server.SetProjectData(projectData) +} + +func (b *HybridBuilder) CompileProject(options *Options) error { + return b.BaseBuilder.CompileProject(options) +} + +func (b *HybridBuilder) CleanUp() { + b.desktop.CleanUp() + b.server.CleanUp() +} + +// PostCompilation is called after the compilation step, if successful +func (s *HybridBuilder) PostCompilation(_ *Options) error { + return nil +} diff --git a/v2/pkg/commands/build/internal/packager/darwin/Info.plist b/v2/pkg/commands/build/internal/packager/darwin/Info.plist index 9736913ae..8e67cb18f 100644 --- a/v2/pkg/commands/build/internal/packager/darwin/Info.plist +++ b/v2/pkg/commands/build/internal/packager/darwin/Info.plist @@ -5,7 +5,7 @@ CFBundleExecutable{{.Title}} CFBundleIdentifiercom.wails.{{.Title}} CFBundleVersion1.0.0 - CFBundleGetInfoStringBuilt using Wails (https://wails.io) + CFBundleGetInfoStringBuilt using Wails (https://wails.app) CFBundleShortVersionString1.0.0 CFBundleIconFileiconfile LSMinimumSystemVersion10.13.0 diff --git a/v2/pkg/commands/build/internal/packager/icon128.png b/v2/pkg/commands/build/internal/packager/icon128.png index ea74d31b5..2ddf98679 100644 Binary files a/v2/pkg/commands/build/internal/packager/icon128.png and b/v2/pkg/commands/build/internal/packager/icon128.png differ diff --git a/v2/pkg/commands/build/internal/packager/icon256.png b/v2/pkg/commands/build/internal/packager/icon256.png index d7031f3a6..0f4235b84 100644 Binary files a/v2/pkg/commands/build/internal/packager/icon256.png and b/v2/pkg/commands/build/internal/packager/icon256.png differ diff --git a/v2/pkg/commands/build/internal/packager/icon32.png b/v2/pkg/commands/build/internal/packager/icon32.png index 231136baa..a03607d66 100644 Binary files a/v2/pkg/commands/build/internal/packager/icon32.png and b/v2/pkg/commands/build/internal/packager/icon32.png differ diff --git a/v2/pkg/commands/build/internal/packager/icons/dialog/README.md b/v2/pkg/commands/build/internal/packager/icons/dialog/README.md new file mode 100644 index 000000000..b9ddc2781 --- /dev/null +++ b/v2/pkg/commands/build/internal/packager/icons/dialog/README.md @@ -0,0 +1,3 @@ +# Default Dialog Icons + +This directory contains the default dialog icons. These are pre-compiled into a single C file (`defaultDialogIcons.c`) which resides in the `ffenestri` directory. If these icons are ever updated, then there is a need to run: `go run build.go` in this directory. This will generate a new `defaultDialogIcons.c` file in the `ffenestri` directory. \ No newline at end of file diff --git a/v2/pkg/commands/build/internal/packager/icons/dialog/build.go b/v2/pkg/commands/build/internal/packager/icons/dialog/build.go new file mode 100644 index 000000000..1d4f74f7a --- /dev/null +++ b/v2/pkg/commands/build/internal/packager/icons/dialog/build.go @@ -0,0 +1,99 @@ +package main + +import ( + "fmt" + "github.com/leaanthony/slicer" + "io/ioutil" + "log" + "path/filepath" + "strconv" + "strings" +) + +func convertToHexLiteral(bytes []byte) string { + result := "" + for _, b := range bytes { + result += fmt.Sprintf("0x%x, ", b) + } + return result +} + +func main() { + dialogIconFilenames, err := filepath.Glob("*.png") + if err != nil { + log.Fatal(err) + } + + // Build icons for Mac + err = buildMacIcons(dialogIconFilenames) + if err != nil { + log.Fatal(err) + } +} + +func buildMacIcons(dialogIconFilenames []string) error { + + // Setup target + targetFile := "../../../../../../../internal/ffenestri/defaultdialogicons_darwin.c" + + var dataBytes []byte + var err error + + // Use a strings builder + var cdata strings.Builder + + // Write header + header := `// defaultdialogicons_darwin.c +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL. +// This file was auto-generated. DO NOT MODIFY. + +` + cdata.WriteString(header) + + var variableList slicer.StringSlicer + + // Loop over icons + for count, filename := range dialogIconFilenames { + + // Load the tray icon + dataBytes, err = ioutil.ReadFile(filename) + if err != nil { + log.Fatal(err) + } + + iconname := strings.TrimSuffix(filepath.Base(filename), ".png") + dialogIconName := fmt.Sprintf("defaultDialogIcon%dName", count) + variableList.Add(dialogIconName) + cdata.WriteString(fmt.Sprintf("const unsigned char %s[] = { %s0x00 };\n", dialogIconName, convertToHexLiteral([]byte(iconname)))) + + dialogIconLength := fmt.Sprintf("defaultDialogIcon%dLength", count) + variableList.Add(dialogIconLength) + lengthAsString := strconv.Itoa(len(dataBytes)) + cdata.WriteString(fmt.Sprintf("const unsigned char %s[] = { %s0x00 };\n", dialogIconLength, convertToHexLiteral([]byte(lengthAsString)))) + + dialogIconData := fmt.Sprintf("defaultDialogIcon%dData", count) + variableList.Add(dialogIconData) + cdata.WriteString(fmt.Sprintf("const unsigned char %s[] = { ", dialogIconData)) + + // Convert each byte to hex + for _, b := range dataBytes { + cdata.WriteString(fmt.Sprintf("0x%x, ", b)) + } + + cdata.WriteString("0x00 };\n") + } + + // Write out main dialogIcons data + cdata.WriteString("const unsigned char *defaultDialogIcons[] = { ") + cdata.WriteString(variableList.Join(", ")) + if len(dialogIconFilenames) > 0 { + cdata.WriteString(", ") + } + cdata.WriteString("0x00 };\n") + + err = ioutil.WriteFile(targetFile, []byte(cdata.String()), 0600) + if err != nil { + log.Fatal(err) + } + return nil +} diff --git a/v2/pkg/commands/build/internal/packager/icons/dialog/info-dark.png b/v2/pkg/commands/build/internal/packager/icons/dialog/info-dark.png new file mode 100644 index 000000000..9ff6655ee Binary files /dev/null and b/v2/pkg/commands/build/internal/packager/icons/dialog/info-dark.png differ diff --git a/v2/pkg/commands/build/internal/packager/icons/dialog/info-dark2x.png b/v2/pkg/commands/build/internal/packager/icons/dialog/info-dark2x.png new file mode 100644 index 000000000..fcdf8006a Binary files /dev/null and b/v2/pkg/commands/build/internal/packager/icons/dialog/info-dark2x.png differ diff --git a/v2/pkg/commands/build/internal/packager/icons/dialog/info-light.png b/v2/pkg/commands/build/internal/packager/icons/dialog/info-light.png new file mode 100644 index 000000000..1fb32e8a9 Binary files /dev/null and b/v2/pkg/commands/build/internal/packager/icons/dialog/info-light.png differ diff --git a/v2/pkg/commands/build/internal/packager/icons/dialog/info-light2x.png b/v2/pkg/commands/build/internal/packager/icons/dialog/info-light2x.png new file mode 100644 index 000000000..874b2d301 Binary files /dev/null and b/v2/pkg/commands/build/internal/packager/icons/dialog/info-light2x.png differ diff --git a/v2/pkg/commands/build/internal/packager/icons/dialog/question-dark.png b/v2/pkg/commands/build/internal/packager/icons/dialog/question-dark.png new file mode 100644 index 000000000..c2387420e Binary files /dev/null and b/v2/pkg/commands/build/internal/packager/icons/dialog/question-dark.png differ diff --git a/v2/pkg/commands/build/internal/packager/icons/dialog/question-dark2x.png b/v2/pkg/commands/build/internal/packager/icons/dialog/question-dark2x.png new file mode 100644 index 000000000..86ea1b037 Binary files /dev/null and b/v2/pkg/commands/build/internal/packager/icons/dialog/question-dark2x.png differ diff --git a/v2/pkg/commands/build/internal/packager/icons/dialog/question-light.png b/v2/pkg/commands/build/internal/packager/icons/dialog/question-light.png new file mode 100644 index 000000000..0d3b6ba02 Binary files /dev/null and b/v2/pkg/commands/build/internal/packager/icons/dialog/question-light.png differ diff --git a/v2/pkg/commands/build/internal/packager/icons/dialog/question-light2x.png b/v2/pkg/commands/build/internal/packager/icons/dialog/question-light2x.png new file mode 100644 index 000000000..fcd21569f Binary files /dev/null and b/v2/pkg/commands/build/internal/packager/icons/dialog/question-light2x.png differ diff --git a/v2/pkg/commands/build/internal/packager/icons/dialog/warning-dark.png b/v2/pkg/commands/build/internal/packager/icons/dialog/warning-dark.png new file mode 100644 index 000000000..db432321b Binary files /dev/null and b/v2/pkg/commands/build/internal/packager/icons/dialog/warning-dark.png differ diff --git a/v2/pkg/commands/build/internal/packager/icons/dialog/warning-dark2x.png b/v2/pkg/commands/build/internal/packager/icons/dialog/warning-dark2x.png new file mode 100644 index 000000000..3325d22d2 Binary files /dev/null and b/v2/pkg/commands/build/internal/packager/icons/dialog/warning-dark2x.png differ diff --git a/v2/pkg/commands/build/internal/packager/icons/dialog/warning-light.png b/v2/pkg/commands/build/internal/packager/icons/dialog/warning-light.png new file mode 100644 index 000000000..cf421a171 Binary files /dev/null and b/v2/pkg/commands/build/internal/packager/icons/dialog/warning-light.png differ diff --git a/v2/pkg/commands/build/internal/packager/icons/dialog/warning-light2x.png b/v2/pkg/commands/build/internal/packager/icons/dialog/warning-light2x.png new file mode 100644 index 000000000..ff092f6cd Binary files /dev/null and b/v2/pkg/commands/build/internal/packager/icons/dialog/warning-light2x.png differ diff --git a/v2/pkg/commands/build/nsis_installer.go b/v2/pkg/commands/build/nsis_installer.go deleted file mode 100644 index 820df2d1d..000000000 --- a/v2/pkg/commands/build/nsis_installer.go +++ /dev/null @@ -1,119 +0,0 @@ -package build - -import ( - "fmt" - "path" - "path/filepath" - "strings" - - "github.com/wailsapp/wails/v2/internal/fs" - "github.com/wailsapp/wails/v2/internal/shell" - "github.com/wailsapp/wails/v2/internal/webview2runtime" - "github.com/wailsapp/wails/v2/pkg/buildassets" -) - -const ( - nsisTypeSingle = "single" - nsisTypeMultiple = "multiple" - - nsisFolder = "windows/installer" - nsisProjectFile = "project.nsi" - nsisToolsFile = "wails_tools.nsh" - nsisWebView2SetupFile = "tmp/MicrosoftEdgeWebview2Setup.exe" -) - -func GenerateNSISInstaller(options *Options, amd64Binary string, arm64Binary string) error { - outputLogger := options.Logger - outputLogger.Println("Creating NSIS installer\n------------------------------") - - // Ensure the file exists, if not the template will be written. - projectFile := path.Join(nsisFolder, nsisProjectFile) - if _, err := buildassets.ReadFile(options.ProjectData, projectFile); err != nil { - return fmt.Errorf("Unable to generate NSIS installer project template: %w", err) - } - - // Write the resolved nsis tools - toolsFile := path.Join(nsisFolder, nsisToolsFile) - if _, err := buildassets.ReadOriginalFileWithProjectDataAndSave(options.ProjectData, toolsFile); err != nil { - return fmt.Errorf("Unable to generate NSIS tools file: %w", err) - } - - // Write the WebView2 SetupFile - webviewSetup := buildassets.GetLocalPath(options.ProjectData, path.Join(nsisFolder, nsisWebView2SetupFile)) - if dir := filepath.Dir(webviewSetup); !fs.DirExists(dir) { - if err := fs.MkDirs(dir, 0o755); err != nil { - return err - } - } - - if err := webview2runtime.WriteInstallerToFile(webviewSetup); err != nil { - return fmt.Errorf("Unable to write WebView2 Bootstrapper Setup: %w", err) - } - - if !shell.CommandExists("makensis") { - outputLogger.Println("Warning: Cannot create installer: makensis not found") - return nil - } - - nsisType := options.ProjectData.NSISType - if nsisType == nsisTypeSingle && (amd64Binary == "" || arm64Binary == "") { - nsisType = "" - } - - switch nsisType { - case "": - fallthrough - case nsisTypeMultiple: - if amd64Binary != "" { - if err := makeNSIS(options, "amd64", amd64Binary, ""); err != nil { - return err - } - } - - if arm64Binary != "" { - if err := makeNSIS(options, "arm64", "", arm64Binary); err != nil { - return err - } - } - - case nsisTypeSingle: - if err := makeNSIS(options, "single", amd64Binary, arm64Binary); err != nil { - return err - } - default: - return fmt.Errorf("Unsupported nsisType: %s", nsisType) - } - - return nil -} - -func makeNSIS(options *Options, installerKind string, amd64Binary string, arm64Binary string) error { - verbose := options.Verbosity == VERBOSE - outputLogger := options.Logger - - outputLogger.Print(" - Building '%s' installer: ", installerKind) - args := []string{} - if amd64Binary != "" { - args = append(args, "-DARG_WAILS_AMD64_BINARY="+amd64Binary) - } - if arm64Binary != "" { - args = append(args, "-DARG_WAILS_ARM64_BINARY="+arm64Binary) - } - args = append(args, nsisProjectFile) - - if verbose { - outputLogger.Println("makensis %s", strings.Join(args, " ")) - } - - installerDir := buildassets.GetLocalPath(options.ProjectData, nsisFolder) - stdOut, stdErr, err := shell.RunCommand(installerDir, "makensis", args...) - if err != nil || verbose { - outputLogger.Println(stdOut) - outputLogger.Println(stdErr) - } - if err != nil { - return fmt.Errorf("Error during creation of the installer: %w", err) - } - outputLogger.Println("Done.") - return nil -} diff --git a/v2/pkg/commands/build/packager.go b/v2/pkg/commands/build/packager.go index d406256f9..9c1f2bd3f 100644 --- a/v2/pkg/commands/build/packager.go +++ b/v2/pkg/commands/build/packager.go @@ -1,35 +1,21 @@ package build import ( - "bytes" "fmt" - "image" "os" "path/filepath" - "strings" - - "github.com/leaanthony/winicon" - "github.com/tc-hib/winres" - "github.com/tc-hib/winres/version" - "github.com/wailsapp/wails/v2/internal/project" - - "github.com/jackmordaunt/icns" - "github.com/pkg/errors" - "github.com/wailsapp/wails/v2/pkg/buildassets" + "runtime" "github.com/wailsapp/wails/v2/internal/fs" ) // PackageProject packages the application func packageProject(options *Options, platform string) error { + var err error switch platform { - case "darwin": - err = packageApplicationForDarwin(options) - case "windows": - err = packageApplicationForWindows(options) - case "linux": - err = packageApplicationForLinux(options) + case "darwin", "windows": + err = packageApplication(options) default: err = fmt.Errorf("packing not supported for %s yet", platform) } @@ -41,9 +27,10 @@ func packageProject(options *Options, platform string) error { return nil } -// cleanBinDirectory will remove an existing bin directory and recreate it -func cleanBinDirectory(options *Options) error { - buildDirectory := options.BinDirectory +// cleanBuildDirectory will remove an existing build directory and recreate it +func cleanBuildDirectory(options *Options) error { + + buildDirectory := options.BuildDirectory // Clear out old builds if fs.DirExists(buildDirectory) { @@ -54,7 +41,7 @@ func cleanBinDirectory(options *Options) error { } // Create clean directory - err := os.MkdirAll(buildDirectory, 0o700) + err := os.MkdirAll(buildDirectory, 0700) if err != nil { return err } @@ -62,240 +49,19 @@ func cleanBinDirectory(options *Options) error { return nil } -func packageApplicationForDarwin(options *Options) error { - var err error - - // Create directory structure - bundlename := options.BundleName - if bundlename == "" { - bundlename = options.ProjectData.Name + ".app" - } - - contentsDirectory := filepath.Join(options.BinDirectory, bundlename, "/Contents") - exeDir := filepath.Join(contentsDirectory, "/MacOS") - err = fs.MkDirs(exeDir, 0o755) - if err != nil { - return err - } - resourceDir := filepath.Join(contentsDirectory, "/Resources") - err = fs.MkDirs(resourceDir, 0o755) - if err != nil { - return err - } - // Copy binary - packedBinaryPath := filepath.Join(exeDir, options.ProjectData.OutputFilename) - err = fs.MoveFile(options.CompiledBinary, packedBinaryPath) - if err != nil { - return errors.Wrap(err, "Cannot move file: "+options.CompiledBinary) - } - - // Generate Info.plist - err = processPList(options, contentsDirectory) - if err != nil { - return err - } - - // Generate App Icon - err = processDarwinIcon(options.ProjectData, "appicon", resourceDir, "iconfile") - if err != nil { - return err - } - - // Generate FileAssociation Icons - for _, fileAssociation := range options.ProjectData.Info.FileAssociations { - err = processDarwinIcon(options.ProjectData, fileAssociation.IconName, resourceDir, "") +// Gets (and creates) the build base directory +func getBuildBaseDirectory(options *Options) (string, error) { + buildDirectory := filepath.Join(options.ProjectData.Path, "build") + if !fs.DirExists(buildDirectory) { + err := os.MkdirAll(buildDirectory, 0700) if err != nil { - return err + return "", err } } - - options.CompiledBinary = packedBinaryPath - - return nil + return buildDirectory, nil } -func processPList(options *Options, contentsDirectory string) error { - sourcePList := "Info.plist" - if options.Mode == Dev { - // Use Info.dev.plist if using build mode - sourcePList = "Info.dev.plist" - } - - // Read the resolved BuildAssets file and copy it to the destination - content, err := buildassets.ReadFileWithProjectData(options.ProjectData, "darwin/"+sourcePList) - if err != nil { - return err - } - - targetFile := filepath.Join(contentsDirectory, "Info.plist") - return os.WriteFile(targetFile, content, 0o644) -} - -func processDarwinIcon(projectData *project.Project, iconName string, resourceDir string, destIconName string) (err error) { - appIcon, err := buildassets.ReadFile(projectData, iconName+".png") - if err != nil { - return err - } - - srcImg, _, err := image.Decode(bytes.NewBuffer(appIcon)) - if err != nil { - return err - } - - if destIconName == "" { - destIconName = iconName - } - - tgtBundle := filepath.Join(resourceDir, destIconName+".icns") - dest, err := os.Create(tgtBundle) - if err != nil { - return err - } - defer func() { - err = dest.Close() - if err == nil { - return - } - }() - return icns.Encode(dest, srcImg) -} - -func packageApplicationForWindows(options *Options) error { - // Generate app icon - var err error - err = generateIcoFile(options, "appicon", "icon") - if err != nil { - return err - } - - // Generate FileAssociation Icons - for _, fileAssociation := range options.ProjectData.Info.FileAssociations { - err = generateIcoFile(options, fileAssociation.IconName, "") - if err != nil { - return err - } - } - - // Create syso file - err = compileResources(options) - if err != nil { - return err - } - - return nil -} - -func packageApplicationForLinux(_ *Options) error { - return nil -} - -func generateIcoFile(options *Options, iconName string, destIconName string) error { - content, err := buildassets.ReadFile(options.ProjectData, iconName+".png") - if err != nil { - return err - } - - if destIconName == "" { - destIconName = iconName - } - - // Check ico file exists already - icoFile := buildassets.GetLocalPath(options.ProjectData, "windows/"+destIconName+".ico") - if !fs.FileExists(icoFile) { - if dir := filepath.Dir(icoFile); !fs.DirExists(dir) { - if err := fs.MkDirs(dir, 0o755); err != nil { - return err - } - } - - output, err := os.OpenFile(icoFile, os.O_CREATE|os.O_WRONLY, 0o644) - if err != nil { - return err - } - defer output.Close() - - err = winicon.GenerateIcon(bytes.NewBuffer(content), output, []int{256, 128, 64, 48, 32, 16}) - if err != nil { - return err - } - } - return nil -} - -func compileResources(options *Options) error { - currentDir, err := os.Getwd() - if err != nil { - return err - } - defer func() { - _ = os.Chdir(currentDir) - }() - windowsDir := filepath.Join(options.ProjectData.GetBuildDir(), "windows") - err = os.Chdir(windowsDir) - if err != nil { - return err - } - rs := winres.ResourceSet{} - icon := filepath.Join(windowsDir, "icon.ico") - iconFile, err := os.Open(icon) - if err != nil { - return err - } - defer iconFile.Close() - ico, err := winres.LoadICO(iconFile) - if err != nil { - return fmt.Errorf("couldn't load icon from icon.ico: %w", err) - } - err = rs.SetIcon(winres.RT_ICON, ico) - if err != nil { - return err - } - - manifestData, err := buildassets.ReadFileWithProjectData(options.ProjectData, "windows/wails.exe.manifest") - if err != nil { - return err - } - - xmlData, err := winres.AppManifestFromXML(manifestData) - if err != nil { - return err - } - rs.SetManifest(xmlData) - - versionInfo, err := buildassets.ReadFileWithProjectData(options.ProjectData, "windows/info.json") - if err != nil { - return err - } - - if len(versionInfo) != 0 { - var v version.Info - if err := v.UnmarshalJSON(versionInfo); err != nil { - return err - } - rs.SetVersionInfo(v) - } - - // replace spaces with underscores as go build behaves weirdly with spaces in syso filename - targetFile := filepath.Join(options.ProjectData.Path, strings.ReplaceAll(options.ProjectData.Name, " ", "_")+"-res.syso") - fout, err := os.Create(targetFile) - if err != nil { - return err - } - defer fout.Close() - - archs := map[string]winres.Arch{ - "amd64": winres.ArchAMD64, - "arm64": winres.ArchARM64, - "386": winres.ArchI386, - } - targetArch, supported := archs[options.Arch] - if !supported { - return fmt.Errorf("arch '%s' not supported", options.Arch) - } - - err = rs.WriteObject(fout, targetArch) - if err != nil { - return err - } - return nil +// Gets the platform dependent package assets directory +func getPackageAssetsDirectory() string { + return fs.RelativePath("internal/packager", runtime.GOOS) } diff --git a/v2/pkg/commands/build/packager_darwin.go b/v2/pkg/commands/build/packager_darwin.go new file mode 100644 index 000000000..76aab0002 --- /dev/null +++ b/v2/pkg/commands/build/packager_darwin.go @@ -0,0 +1,181 @@ +package build + +import ( + "bytes" + "image" + "io/ioutil" + "os" + "path" + "path/filepath" + "strings" + "text/template" + + "github.com/wailsapp/wails/v2/pkg/buildassets" + + "github.com/jackmordaunt/icns" + "github.com/pkg/errors" + "github.com/wailsapp/wails/v2/internal/fs" +) + +func packageApplication(options *Options) error { + + var err error + + // Create directory structure + bundlename := options.ProjectData.Name + ".app" + + contentsDirectory := filepath.Join(options.BuildDirectory, bundlename, "/Contents") + exeDir := filepath.Join(contentsDirectory, "/MacOS") + err = fs.MkDirs(exeDir, 0755) + if err != nil { + return err + } + resourceDir := filepath.Join(contentsDirectory, "/Resources") + err = fs.MkDirs(resourceDir, 0755) + if err != nil { + return err + } + // Copy binary + packedBinaryPath := filepath.Join(exeDir, options.ProjectData.Name) + err = fs.MoveFile(options.CompiledBinary, packedBinaryPath) + if err != nil { + return errors.Wrap(err, "Cannot move file: "+options.ProjectData.OutputFilename) + } + + // Generate Info.plist + err = processPList(options, contentsDirectory) + if err != nil { + return err + } + + // Generate Icons + err = processApplicationIcon(resourceDir, options.ProjectData.BuildDir) + if err != nil { + return err + } + + options.CompiledBinary = packedBinaryPath + + return nil +} + +func processPList(options *Options, contentsDirectory string) error { + + // Check if plist already exists in project dir + plistFile := filepath.Join(options.ProjectData.BuildDir, "darwin", "Info.plist") + + // If the file doesn't exist, generate it + if !fs.FileExists(plistFile) { + err := generateDefaultPlist(options, plistFile) + if err != nil { + return err + } + } + + // Copy it to the contents directory + targetFile := filepath.Join(contentsDirectory, "Info.plist") + return fs.CopyFile(plistFile, targetFile) +} + +func generateDefaultPlist(options *Options, targetPlistFile string) error { + name := defaultString(options.ProjectData.Name, "WailsTest") + exe := defaultString(options.OutputFile, name) + version := "1.0.0" + author := defaultString(options.ProjectData.Author.Name, "Anonymous") + packageID := strings.Join([]string{"wails", name}, ".") + plistData := newPlistData(name, exe, packageID, version, author) + + tmpl := template.New("infoPlist") + plistTemplate := fs.RelativePath("./internal/packager/darwin/Info.plist") + infoPlist, err := ioutil.ReadFile(plistTemplate) + if err != nil { + return errors.Wrap(err, "Cannot open plist template") + } + _, err = tmpl.Parse(string(infoPlist)) + if err != nil { + return err + } + // Write the template to a buffer + var tpl bytes.Buffer + err = tmpl.Execute(&tpl, plistData) + if err != nil { + return err + } + + // Create the directory if it doesn't exist + err = fs.MkDirs(filepath.Dir(targetPlistFile)) + if err != nil { + return err + } + // Save the file + return ioutil.WriteFile(targetPlistFile, tpl.Bytes(), 0644) +} + +func defaultString(val string, defaultVal string) string { + if val != "" { + return val + } + return defaultVal +} + +type plistData struct { + Title string + Exe string + PackageID string + Version string + Author string +} + +func newPlistData(title, exe, packageID, version, author string) *plistData { + return &plistData{ + Title: title, + Exe: exe, + Version: version, + PackageID: packageID, + Author: author, + } +} + +func processApplicationIcon(resourceDir string, iconsDir string) (err error) { + + appIcon := filepath.Join(iconsDir, "appicon.png") + + // Install default icon if one doesn't exist + if !fs.FileExists(appIcon) { + // No - Install default icon + err = buildassets.RegenerateAppIcon(appIcon) + if err != nil { + return + } + } + + tgtBundle := path.Join(resourceDir, "iconfile.icns") + imageFile, err := os.Open(appIcon) + if err != nil { + return err + } + + defer func() { + err = imageFile.Close() + if err == nil { + return + } + }() + srcImg, _, err := image.Decode(imageFile) + if err != nil { + return err + + } + dest, err := os.Create(tgtBundle) + if err != nil { + return err + + } + defer func() { + err = dest.Close() + if err == nil { + return + } + }() + return icns.Encode(dest, srcImg) +} diff --git a/v2/pkg/commands/build/packager_linux.go b/v2/pkg/commands/build/packager_linux.go index 6b297d3ec..61436eb70 100644 --- a/v2/pkg/commands/build/packager_linux.go +++ b/v2/pkg/commands/build/packager_linux.go @@ -1,5 +1,113 @@ package build func packageApplication(_ *Options) error { + // + //// Check we have AppImage tools + // + //// Create AppImage build directory + //buildDirectory, err := getApplicationBuildDirectory(options, "linux") + //if err != nil { + // return err + //} + // + //defer deleteLinuxPackFiles(buildDirectory) + // + //// Get the name of the application and ensure we lower+kebab case it + //name := filepath.Base(options.ProjectData.OutputFilename) + // + //// Calculate asset directory + //assetDir := getPackageAssetsDirectory() + // + //// Copy default icon if one doesn't exist + //baseBuildDirectory, err := getBuildBaseDirectory(options) + //if err != nil { + // return err + //} + //iconFile := filepath.Join(baseBuildDirectory, "icon.png") + //if !fs.FileExists(iconFile) { + // err = fs.CopyFile(defaultIconPath(), iconFile) + // if err != nil { + // return err + // } + //} + // + //// Copy Icon + //targetIcon := filepath.Join(buildDirectory, name+".png") + //err = fs.CopyFile(iconFile, targetIcon) + //if err != nil { + // return err + //} + // + //// Copy app.desktop + //dotDesktopFile := filepath.Join(baseBuildDirectory, "linux", name+".desktop") + //if !fs.FileExists(dotDesktopFile) { + // bytes, err := ioutil.ReadFile(filepath.Join(assetDir, "app.desktop")) + // if err != nil { + // return err + // } + // appDesktop := string(bytes) + // appDesktop = strings.ReplaceAll(appDesktop, `{{.Name}}`, name) + // err = ioutil.WriteFile(dotDesktopFile, []byte(appDesktop), 0644) + // if err != nil { + // return err + // } + //} + // + //// Copy AppRun file + //// targetFilename = filepath.Join(buildDirectory, "AppRun") + //// if !fs.FileExists(targetFilename) { + //// bytes, err := ioutil.ReadFile(filepath.Join(assetDir, "AppRun")) + //// if err != nil { + //// return err + //// } + //// appRun := string(bytes) + //// appRun = strings.ReplaceAll(appRun, `{{.OutputFilename}}`, name) + // + //// err = ioutil.WriteFile(targetFilename, []byte(appRun), 0644) + //// if err != nil { + //// return err + //// } + //// } + // + //// Copy Binary + //sourceFile := filepath.Join(options.ProjectData.Path, options.ProjectData.OutputFilename) + //targetFile := filepath.Join(buildDirectory, options.ProjectData.OutputFilename) + //err = fs.CopyFile(sourceFile, targetFile) + //if err != nil { + // return err + //} + //err = os.Chmod(targetFile, 0777) + //if err != nil { + // return err + //} + // + ///** Pack App **/ + // + //// Make file executable + //// Set environment variable: OUTPUT=outputfilename + //command := shell.NewCommand("linuxdeploy-x86_64.AppImage") + //command.Dir(buildDirectory) + // + //argslice := slicer.String() + //argslice.Add("--appdir", "AppDir") + //argslice.Add("-d", filepath.Join("..", name+".desktop")) + //argslice.Add("-i", name+".png") + //argslice.Add("-e", name) + //argslice.Add("--output", "appimage") + //command.AddArgs(argslice.AsSlice()) + // + //command.Env("OUTPUT", name+".AppImage") + // + //err = command.Run() + //if err != nil { + // println(command.Stdout()) + // println(command.Stderr()) + // return err + //} + // + //// Copy app to project dir + // + //println(buildDirectory) + return nil } diff --git a/v2/pkg/commands/build/packager_windows.go b/v2/pkg/commands/build/packager_windows.go new file mode 100644 index 000000000..85b395568 --- /dev/null +++ b/v2/pkg/commands/build/packager_windows.go @@ -0,0 +1,129 @@ +package build + +import ( + "fmt" + "github.com/leaanthony/winicon" + "github.com/tc-hib/winres" + "github.com/wailsapp/wails/v2/internal/fs" + "github.com/wailsapp/wails/v2/pkg/buildassets" + "os" + "path/filepath" +) + +func packageApplication(options *Options) error { + // Generate icon + var err error + err = generateIcoFile(options) + if err != nil { + return err + } + + // Ensure Manifest is present + err = generateManifest(options) + if err != nil { + return err + } + + // Create syso file + err = compileResources(options) + if err != nil { + return err + } + + return nil +} + +func generateManifest(options *Options) error { + filename := options.ProjectData.Name + ".exe.manifest" + manifestFile := filepath.Join(options.ProjectData.Path, "build", "windows", filename) + if !fs.FileExists(manifestFile) { + return buildassets.RegenerateManifest(manifestFile) + } + return nil +} + +func generateIcoFile(options *Options) error { + // Check ico file exists already + icoFile := filepath.Join(options.ProjectData.Path, "build", "windows", "icon.ico") + if !fs.FileExists(icoFile) { + // Check icon exists + appicon := filepath.Join(options.ProjectData.Path, "build", "appicon.png") + if !fs.FileExists(appicon) { + return fmt.Errorf("application icon missing: %s", appicon) + } + // Load icon + input, err := os.Open(appicon) + if err != nil { + return err + } + output, err := os.OpenFile(icoFile, os.O_CREATE, 0644) + if err != nil { + return err + } + err = winicon.GenerateIcon(input, output, []int{256, 128, 64, 48, 32, 16}) + if err != nil { + return err + } + } + return nil +} + +func compileResources(options *Options) error { + + currentDir, err := os.Getwd() + if err != nil { + return err + } + defer func() { + os.Chdir(currentDir) + }() + windowsDir := filepath.Join(options.ProjectData.Path, "build", "windows") + err = os.Chdir(windowsDir) + if err != nil { + return err + } + rs := winres.ResourceSet{} + icon := filepath.Join(windowsDir, "icon.ico") + iconFile, err := os.Open(icon) + if err != nil { + return err + } + defer iconFile.Close() + ico, err := winres.LoadICO(iconFile) + if err != nil { + return err + } + err = rs.SetIcon(winres.RT_ICON, ico) + if err != nil { + return err + } + + ManifestFilename := options.ProjectData.Name + ".exe.manifest" + manifestData, err := os.ReadFile(ManifestFilename) + xmlData, err := winres.AppManifestFromXML(manifestData) + if err != nil { + return err + } + rs.SetManifest(xmlData) + + targetFile := filepath.Join(options.ProjectData.Path, options.ProjectData.Name+"-res.syso") + fout, err := os.Create(targetFile) + if err != nil { + return err + } + defer fout.Close() + + archs := map[string]winres.Arch{ + "amd64": winres.ArchAMD64, + } + targetArch, supported := archs[options.Arch] + if !supported { + return fmt.Errorf("arch '%s' not supported", options.Arch) + } + + err = rs.WriteObject(fout, targetArch) + if err != nil { + return err + } + return nil +} diff --git a/v2/pkg/commands/build/server-assetdb.go.template b/v2/pkg/commands/build/server-assetdb.go.template new file mode 100644 index 000000000..f4720fee4 --- /dev/null +++ b/v2/pkg/commands/build/server-assetdb.go.template @@ -0,0 +1,11 @@ +package webserver + +// This sets up the assets that are defined in `webassets.go` +func init() { + html = []byte{$HTMLBYTES$} + js = []byte{$JSBYTES$} + css = []byte{$CSSBYTES$} + wailsjs = []byte{$WAILSJSBYTES$} + jsurl = []byte{$JSURLBYTES$} + cssurl = []byte{$CSSURLBYTES$} +} \ No newline at end of file diff --git a/v2/pkg/commands/build/server.go b/v2/pkg/commands/build/server.go new file mode 100644 index 000000000..fd37aebf8 --- /dev/null +++ b/v2/pkg/commands/build/server.go @@ -0,0 +1,113 @@ +package build + +import ( + "fmt" + "io/ioutil" + "os" + "strings" + + "github.com/wailsapp/wails/v2/internal/fs" + "github.com/wailsapp/wails/v2/internal/html" +) + +// ServerBuilder builds applications as a server +type ServerBuilder struct { + *BaseBuilder +} + +func newServerBuilder(options *Options) *ServerBuilder { + result := &ServerBuilder{ + BaseBuilder: NewBaseBuilder(options), + } + return result +} + +// BuildAssets builds the assets for the desktop application +func (s *ServerBuilder) BuildAssets(_ *Options) error { + var err error + + assets, err := s.BaseBuilder.ExtractAssets() + if err != nil { + return err + } + + // Build embedded assets (HTML/JS/CSS/etc) + err = s.BuildBaseAssets(assets) + if err != nil { + return err + } + + return nil +} + +// PostCompilation is called after the compilation step, if successful +func (s *ServerBuilder) PostCompilation(_ *Options) error { + return nil +} + +// BuildBaseAssets builds the base assets +func (s *ServerBuilder) BuildBaseAssets(assets *html.AssetBundle) error { + db, err := assets.ConvertToAssetDB() + if err != nil { + return err + } + + // Fetch, update, and reinject index.html + index, err := db.Read("index.html") + if err != nil { + return fmt.Errorf(`failed to locate "index.html"`) + } + splits := strings.Split(string(index), "") + if len(splits) != 2 { + return fmt.Errorf("unable to locate a tag in your frontend/index.html") + } + injectScript := `` + result := []string{} + result = append(result, splits[0]) + result = append(result, injectScript) + result = append(result, "") + result = append(result, splits[1]) + + db.Remove("index.html") // Remove the non-prefixed index.html + db.AddAsset("/index.html", []byte(strings.Join(result, ""))) + + // Add wails.js + wailsjsPath := fs.RelativePath("../../../internal/runtime/assets/server.js") + if rawData, err := ioutil.ReadFile(wailsjsPath); err == nil { + db.AddAsset("/wails.js", rawData) + } + + targetFile := fs.RelativePath("../../../internal/webserver/webassetsdb.go") + s.addFileToDelete(targetFile) + f, err := os.Create(targetFile) + if err != nil { + return err + } + + _, err = f.WriteString(db.Serialize("db", "webserver")) + if err != nil { + // Ignore error - we already have one! + _ = f.Close() + return err + } + return f.Close() +} + +// BuildRuntime builds the javascript runtime used by the HTML client to connect to the websocket +func (s *ServerBuilder) BuildRuntime(options *Options) error { + + sourceDir := fs.RelativePath("../../../internal/runtime/js") + if err := s.NpmInstall(sourceDir, options.Verbosity == VERBOSE); err != nil { + return err + } + + options.Logger.Print(" - Embedding Runtime...") + envvars := []string{"WAILSPLATFORM=" + options.Platform} + var err error + if err = s.NpmRunWithEnvironment(sourceDir, "build:server", false, envvars); err != nil { + return err + } + + options.Logger.Println("done.") + return nil +} diff --git a/v2/pkg/commands/buildtags/buildtags.go b/v2/pkg/commands/buildtags/buildtags.go deleted file mode 100644 index 5cca16acf..000000000 --- a/v2/pkg/commands/buildtags/buildtags.go +++ /dev/null @@ -1,52 +0,0 @@ -package buildtags - -import ( - "errors" - "strings" - - "github.com/samber/lo" -) - -// Parse parses the given tags string and returns -// a cleaned slice of strings. Both comma and space delimited -// tags are supported but not mixed. If mixed, an error is returned. -func Parse(tags string) ([]string, error) { - if tags == "" { - return nil, nil - } - - separator := "" - if strings.Contains(tags, ",") { - separator = "," - } - if strings.Contains(tags, " ") { - if separator != "" { - return nil, errors.New("cannot use both space and comma separated values with `-tags` flag") - } - separator = " " - } - if separator == "" { - // We couldn't find any separator, so the whole string is used as user tag - // Otherwise we would end up with a list of every single character of the tags string, - // e.g.: `t,e,s,t` - return []string{tags}, nil - } - - var userTags []string - for _, tag := range strings.Split(tags, separator) { - thisTag := strings.TrimSpace(tag) - if thisTag != "" { - userTags = append(userTags, thisTag) - } - } - return userTags, nil -} - -// Stringify converts the given tags slice to a string compatible -// with the go build -tags flag -func Stringify(tags []string) string { - tags = lo.Map(tags, func(tag string, _ int) string { - return strings.TrimSpace(tag) - }) - return strings.Join(tags, ",") -} diff --git a/v2/pkg/commands/buildtags/buildtags_test.go b/v2/pkg/commands/buildtags/buildtags_test.go deleted file mode 100644 index c13a158c7..000000000 --- a/v2/pkg/commands/buildtags/buildtags_test.go +++ /dev/null @@ -1,78 +0,0 @@ -package buildtags - -import ( - "reflect" - "testing" -) - -func TestParse(t *testing.T) { - tests := []struct { - name string - tags string - want []string - wantErr bool - }{ - { - name: "should support single tags", - tags: "test", - want: []string{"test"}, - wantErr: false, - }, - { - name: "should support space delimited tags", - tags: "test test2", - want: []string{"test", "test2"}, - wantErr: false, - }, - { - name: "should support comma delimited tags", - tags: "test,test2", - want: []string{"test", "test2"}, - wantErr: false, - }, - { - name: "should error if mixed tags", - tags: "test,test2 test3", - want: nil, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := Parse(tt.tags) - if (err != nil) != tt.wantErr { - t.Errorf("Parse() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("Parse() got = %v, want %v", got, tt.want) - } - }) - } -} - -func TestStringify(t *testing.T) { - tests := []struct { - name string - tags []string - want string - }{ - { - name: "should support single tags", - tags: []string{"test"}, - want: "test", - }, - { - name: "should support multiple tags", - tags: []string{"test", "test2"}, - want: "test,test2", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := Stringify(tt.tags); got != tt.want { - t.Errorf("Stringify() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/v2/pkg/git/git.go b/v2/pkg/git/git.go index a0ac68ca9..844fd452f 100644 --- a/v2/pkg/git/git.go +++ b/v2/pkg/git/git.go @@ -1,10 +1,7 @@ package git import ( - "encoding/json" - "fmt" "runtime" - "strings" "github.com/wailsapp/wails/v2/internal/shell" ) @@ -31,31 +28,8 @@ func Email() (string, error) { // Name tries to retrieve the func Name() (string, error) { - errMsg := "failed to retrieve git user name: %w" stdout, _, err := shell.RunCommand(".", gitcommand(), "config", "user.name") - if err != nil { - return "", fmt.Errorf(errMsg, err) - } - name := strings.TrimSpace(stdout) - return EscapeName(name) -} - -func EscapeName(str string) (string, error) { - b, err := json.Marshal(str) - if err != nil { - return "", err - } - // Remove the surrounding quotes - escaped := string(b[1 : len(b)-1]) - - // Check if username is JSON compliant - var js json.RawMessage - jsonVal := fmt.Sprintf(`{"name": "%s"}`, escaped) - err = json.Unmarshal([]byte(jsonVal), &js) - if err != nil { - return "", fmt.Errorf("failed to retrieve git user name: %w", err) - } - return escaped, nil + return stdout, err } func InitRepo(projectDir string) error { diff --git a/v2/pkg/git/git_test.go b/v2/pkg/git/git_test.go deleted file mode 100644 index 238008ec3..000000000 --- a/v2/pkg/git/git_test.go +++ /dev/null @@ -1,44 +0,0 @@ -package git - -import ( - "testing" -) - -func TestEscapeName1(t *testing.T) { - type args struct { - str string - } - tests := []struct { - name string - args args - want string - wantErr bool - }{ - { - name: "Escape Apostrophe", - args: args{ - str: `John O'Keefe`, - }, - want: `John O'Keefe`, - }, - { - name: "Escape backslash", - args: args{ - str: `MYDOMAIN\USER`, - }, - want: `MYDOMAIN\\USER`, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := EscapeName(tt.args.str) - if (err != nil) != tt.wantErr { - t.Errorf("EscapeName() error = %v, wantErr %v", err, tt.wantErr) - return - } - if got != tt.want { - t.Errorf("EscapeName() got = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/v2/pkg/logger/filelogger.go b/v2/pkg/logger/filelogger.go index 954c46f59..5cf68fc1a 100644 --- a/v2/pkg/logger/filelogger.go +++ b/v2/pkg/logger/filelogger.go @@ -19,7 +19,7 @@ func NewFileLogger(filename string) Logger { // Print works like Sprintf. func (l *FileLogger) Print(message string) { - f, err := os.OpenFile(l.filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644) + f, err := os.OpenFile(l.filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if err != nil { log.Fatal(err) } diff --git a/v2/pkg/logger/logger.go b/v2/pkg/logger/logger.go index 990dffe75..abc288265 100644 --- a/v2/pkg/logger/logger.go +++ b/v2/pkg/logger/logger.go @@ -41,24 +41,6 @@ func StringToLogLevel(input string) (LogLevel, error) { return result, nil } -// String returns the string representation of the LogLevel -func (l LogLevel) String() string { - switch l { - case TRACE: - return "trace" - case DEBUG: - return "debug" - case INFO: - return "info" - case WARNING: - return "warning" - case ERROR: - return "error" - default: - return "debug" - } -} - // Logger specifies the methods required to attach // a logger to a Wails application type Logger interface { diff --git a/v2/pkg/mac/login_darwin.go b/v2/pkg/mac/login_darwin.go index b2390e305..2ff49be83 100644 --- a/v2/pkg/mac/login_darwin.go +++ b/v2/pkg/mac/login_darwin.go @@ -33,7 +33,7 @@ func StartAtLogin(enabled bool) error { } _, stde, err := shell.RunCommand("/tmp", "osascript", "-e", command) if err != nil { - return errors.Wrap(err, stde) + errors.Wrap(err, stde) } return nil } diff --git a/v2/pkg/mac/notification_darwin.go b/v2/pkg/mac/notification_darwin.go index 243f07c78..a06ecb53a 100644 --- a/v2/pkg/mac/notification_darwin.go +++ b/v2/pkg/mac/notification_darwin.go @@ -8,7 +8,7 @@ import ( "github.com/wailsapp/wails/v2/internal/shell" ) -// ShowNotification will either add or remove this application to/from the login +// StartAtLogin will either add or remove this application to/from the login // items, depending on the given boolean flag. The limitation is that the // currently running app must be in an app bundle. func ShowNotification(title string, subtitle string, message string, sound string) error { @@ -24,7 +24,7 @@ func ShowNotification(title string, subtitle string, message string, sound strin } _, stde, err := shell.RunCommand("/tmp", "osascript", "-e", command) if err != nil { - return errors.Wrap(err, stde) + errors.Wrap(err, stde) } return nil } diff --git a/v2/pkg/menu/callback.go b/v2/pkg/menu/callback.go index a02664ac0..fe6160361 100644 --- a/v2/pkg/menu/callback.go +++ b/v2/pkg/menu/callback.go @@ -2,7 +2,7 @@ package menu type CallbackData struct { MenuItem *MenuItem - // ContextData string + //ContextData string } type Callback func(*CallbackData) diff --git a/v2/pkg/menu/colours/colours.go b/v2/pkg/menu/colours/colours.go index 5fb74eabd..c0f1da05c 100644 --- a/v2/pkg/menu/colours/colours.go +++ b/v2/pkg/menu/colours/colours.go @@ -4,7 +4,7 @@ import ( "bytes" _ "embed" "encoding/json" - "io" + "io/ioutil" "log" "net/http" "os" @@ -36,6 +36,7 @@ type InputCol struct { var Template string func main() { + var Cols []InputCol resp, err := http.Get("https://jonasjacek.github.io/colors/data.json") @@ -43,7 +44,7 @@ func main() { log.Fatal(err) } defer resp.Body.Close() - data, err := io.ReadAll(resp.Body) + data, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } @@ -61,8 +62,5 @@ func main() { if err != nil { log.Fatal(err) } - err = os.WriteFile(filepath.Join("..", "cols.go"), buffer.Bytes(), 0o755) - if err != nil { - log.Fatal(err) - } + os.WriteFile(filepath.Join("..", "cols.go"), buffer.Bytes(), 0755) } diff --git a/v2/pkg/menu/keys/keys.go b/v2/pkg/menu/keys/keys.go index 961edab2d..73bc9414f 100644 --- a/v2/pkg/menu/keys/keys.go +++ b/v2/pkg/menu/keys/keys.go @@ -16,7 +16,7 @@ const ( // ShiftKey represents the shift key on all systems ShiftKey Modifier = "shift" // SuperKey represents Command on Mac and the Windows key on the other platforms - // SuperKey Modifier = "super" + //SuperKey Modifier = "super" // ControlKey represents the control key on all systems ControlKey Modifier = "ctrl" ) @@ -99,6 +99,8 @@ func Combo(key string, modifier1 Modifier, modifier2 Modifier, rest ...Modifier) Key: key, Modifiers: []Modifier{modifier1, modifier2}, } - result.Modifiers = append(result.Modifiers, rest...) + for _, extra := range rest { + result.Modifiers = append(result.Modifiers, extra) + } return result } diff --git a/v2/pkg/menu/keys/macmodifiers.go b/v2/pkg/menu/keys/macmodifiers.go deleted file mode 100644 index 7da618b4e..000000000 --- a/v2/pkg/menu/keys/macmodifiers.go +++ /dev/null @@ -1,26 +0,0 @@ -package keys - -const ( - NSEventModifierFlagShift = 1 << 17 // Set if Shift key is pressed. - NSEventModifierFlagControl = 1 << 18 // Set if Control key is pressed. - NSEventModifierFlagOption = 1 << 19 // Set if Option or Alternate key is pressed. - NSEventModifierFlagCommand = 1 << 20 // Set if Command key is pressed. -) - -var macModifierMap = map[Modifier]int{ - CmdOrCtrlKey: NSEventModifierFlagCommand, - ControlKey: NSEventModifierFlagControl, - OptionOrAltKey: NSEventModifierFlagOption, - ShiftKey: NSEventModifierFlagShift, -} - -func ToMacModifier(accelerator *Accelerator) int { - if accelerator == nil { - return 0 - } - result := 0 - for _, modifier := range accelerator.Modifiers { - result |= macModifierMap[modifier] - } - return result -} diff --git a/v2/pkg/menu/keys/macmodifiers_test.go b/v2/pkg/menu/keys/macmodifiers_test.go deleted file mode 100644 index 8be1bd05a..000000000 --- a/v2/pkg/menu/keys/macmodifiers_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package keys - -import "testing" - -func TestToMacModifier(t *testing.T) { - - tests := []struct { - name string - accelerator *Accelerator - want int - }{ - // TODO: Add test cases. - {"nil", nil, 0}, - {"empty", &Accelerator{}, 0}, - {"key", &Accelerator{Key: "p"}, 0}, - {"cmd", CmdOrCtrl(""), NSEventModifierFlagCommand}, - {"ctrl", Control(""), NSEventModifierFlagControl}, - {"shift", Shift(""), NSEventModifierFlagShift}, - {"option", OptionOrAlt(""), NSEventModifierFlagOption}, - {"cmd+ctrl", Combo("", CmdOrCtrlKey, ControlKey), NSEventModifierFlagCommand | NSEventModifierFlagControl}, - {"cmd+ctrl+shift", Combo("", CmdOrCtrlKey, ControlKey, ShiftKey), NSEventModifierFlagCommand | NSEventModifierFlagControl | NSEventModifierFlagShift}, - {"cmd+ctrl+shift+option", Combo("", CmdOrCtrlKey, ControlKey, ShiftKey, OptionOrAltKey), NSEventModifierFlagCommand | NSEventModifierFlagControl | NSEventModifierFlagShift | NSEventModifierFlagOption}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := ToMacModifier(tt.accelerator); got != tt.want { - t.Errorf("ToMacModifier() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/v2/pkg/menu/keys/parser.go b/v2/pkg/menu/keys/parser.go index 6e8e12376..91a05783d 100644 --- a/v2/pkg/menu/keys/parser.go +++ b/v2/pkg/menu/keys/parser.go @@ -11,6 +11,7 @@ import ( var namedKeys = slicer.String([]string{"backspace", "tab", "return", "enter", "escape", "left", "right", "up", "down", "space", "delete", "home", "end", "page up", "page down", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", "f32", "f33", "f34", "f35", "numlock"}) func parseKey(key string) (string, bool) { + // Lowercase! key = strings.ToLower(key) @@ -37,9 +38,11 @@ func parseKey(key string) (string, bool) { } return "", false + } func Parse(shortcut string) (*Accelerator, error) { + var result Accelerator // Split the shortcut by + diff --git a/v2/pkg/menu/keys/parser_test.go b/v2/pkg/menu/keys/parser_test.go index f63f22bed..703861da1 100644 --- a/v2/pkg/menu/keys/parser_test.go +++ b/v2/pkg/menu/keys/parser_test.go @@ -32,6 +32,6 @@ func TestParse(t *testing.T) { for _, d := range baddata { result, err := Parse(d) i.True(err != nil) - i.Equal(result, nil) + i.Equal(result, "") } } diff --git a/v2/pkg/menu/keys/stringify.go b/v2/pkg/menu/keys/stringify.go index 92498f5d4..ccc8c5e9e 100644 --- a/v2/pkg/menu/keys/stringify.go +++ b/v2/pkg/menu/keys/stringify.go @@ -1,9 +1,8 @@ package keys import ( - "strings" - "github.com/leaanthony/slicer" + "strings" ) var modifierStringMap = map[string]map[Modifier]string{ @@ -12,21 +11,21 @@ var modifierStringMap = map[string]map[Modifier]string{ ControlKey: "Ctrl", OptionOrAltKey: "Alt", ShiftKey: "Shift", - // SuperKey: "Win", + //SuperKey: "Win", }, "darwin": { CmdOrCtrlKey: "Cmd", ControlKey: "Ctrl", OptionOrAltKey: "Option", ShiftKey: "Shift", - // SuperKey: "Cmd", + //SuperKey: "Cmd", }, "linux": { CmdOrCtrlKey: "Ctrl", ControlKey: "Ctrl", OptionOrAltKey: "Alt", ShiftKey: "Shift", - // SuperKey: "Super", + //SuperKey: "Super", }, } diff --git a/v2/pkg/menu/menu.go b/v2/pkg/menu/menu.go index 86acbd1d0..be04820d3 100644 --- a/v2/pkg/menu/menu.go +++ b/v2/pkg/menu/menu.go @@ -1,7 +1,5 @@ package menu -import "github.com/wailsapp/wails/v2/pkg/menu/keys" - type Menu struct { Items []*MenuItem } @@ -17,41 +15,9 @@ func (m *Menu) Append(item *MenuItem) { // Merge will append the items in the given menu // into this menu func (m *Menu) Merge(menu *Menu) { - m.Items = append(m.Items, menu.Items...) -} - -// AddText adds a TextMenu item to the menu -func (m *Menu) AddText(label string, accelerator *keys.Accelerator, click Callback) *MenuItem { - item := Text(label, accelerator, click) - m.Append(item) - return item -} - -// AddCheckbox adds a CheckboxMenu item to the menu -func (m *Menu) AddCheckbox(label string, checked bool, accelerator *keys.Accelerator, click Callback) *MenuItem { - item := Checkbox(label, checked, accelerator, click) - m.Append(item) - return item -} - -// AddRadio adds a radio item to the menu -func (m *Menu) AddRadio(label string, checked bool, accelerator *keys.Accelerator, click Callback) *MenuItem { - item := Radio(label, checked, accelerator, click) - m.Append(item) - return item -} - -// AddSeparator adds a separator to the menu -func (m *Menu) AddSeparator() { - item := Separator() - m.Append(item) -} - -func (m *Menu) AddSubmenu(label string) *Menu { - submenu := NewMenu() - item := SubMenu(label, submenu) - m.Append(item) - return submenu + for _, item := range menu.Items { + m.Items = append(m.Items, item) + } } func (m *Menu) Prepend(item *MenuItem) { @@ -59,7 +25,8 @@ func (m *Menu) Prepend(item *MenuItem) { } func NewMenuFromItems(first *MenuItem, rest ...*MenuItem) *Menu { - result := NewMenu() + + var result = NewMenu() result.Append(first) for _, item := range rest { result.Append(item) diff --git a/v2/pkg/menu/menuitem.go b/v2/pkg/menu/menuitem.go index bffc522d8..2a55b5fbc 100644 --- a/v2/pkg/menu/menuitem.go +++ b/v2/pkg/menu/menuitem.go @@ -11,9 +11,9 @@ type MenuItem struct { // Label is what appears as the menu text Label string // Role is a predefined menu type - Role Role + //Role Role `json:"Role,omitempty"` // Accelerator holds a representation of a key binding - Accelerator *keys.Accelerator + Accelerator *keys.Accelerator `json:"Accelerator,omitempty"` // Type of MenuItem, EG: Checkbox, Text, Separator, Radio, Submenu Type Type // Disabled makes the item unselectable @@ -22,12 +22,12 @@ type MenuItem struct { Hidden bool // Checked indicates if the item is selected (used by Checkbox and Radio types only) Checked bool - // SubMenu contains a list of menu items that will be shown as a submenu - // SubMenu []*MenuItem `json:"SubMenu,omitempty"` - SubMenu *Menu + // Submenu contains a list of menu items that will be shown as a submenu + //SubMenu []*MenuItem `json:"SubMenu,omitempty"` + SubMenu *Menu `json:"SubMenu,omitempty"` // Callback function when menu clicked - Click Callback + Click Callback `json:"-"` /* // Text Colour RGBA string @@ -106,6 +106,7 @@ func (m *MenuItem) removeChild(item *MenuItem) { // menu. If there is no parent menu (we are a top level menu) then false is // returned func (m *MenuItem) InsertAfter(item *MenuItem) bool { + // We need to find my parent if m.parent == nil { return false @@ -119,6 +120,7 @@ func (m *MenuItem) InsertAfter(item *MenuItem) bool { // menu. If there is no parent menu (we are a top level menu) then false is // returned func (m *MenuItem) InsertBefore(item *MenuItem) bool { + // We need to find my parent if m.parent == nil { return false @@ -132,8 +134,8 @@ func (m *MenuItem) InsertBefore(item *MenuItem) bool { // in this item's submenu. If we are not a submenu, // then something bad has happened :/ func (m *MenuItem) insertNewItemAfterGivenItem(target *MenuItem, - newItem *MenuItem, -) bool { + newItem *MenuItem) bool { + if !m.isSubMenu() { return false } @@ -152,8 +154,8 @@ func (m *MenuItem) insertNewItemAfterGivenItem(target *MenuItem, // target in this item's submenu. If we are not a submenu, then something bad // has happened :/ func (m *MenuItem) insertNewItemBeforeGivenItem(target *MenuItem, - newItem *MenuItem, -) bool { + newItem *MenuItem) bool { + if !m.isSubMenu() { return false } @@ -174,6 +176,7 @@ func (m *MenuItem) isSubMenu() bool { // getItemIndex returns the index of the given target relative to this menu func (m *MenuItem) getItemIndex(target *MenuItem) int { + // This should only be called on submenus if !m.isSubMenu() { return -1 @@ -193,6 +196,7 @@ func (m *MenuItem) getItemIndex(target *MenuItem) int { // the given index // Credit: https://stackoverflow.com/a/61822301 func (m *MenuItem) insertItemAtIndex(index int, target *MenuItem) bool { + // If index is OOB, return false if index > len(m.SubMenu.Items) { return false @@ -212,70 +216,6 @@ func (m *MenuItem) insertItemAtIndex(index int, target *MenuItem) bool { return true } -func (m *MenuItem) SetLabel(name string) { - if m.Label == name { - return - } - m.Label = name -} - -func (m *MenuItem) IsSeparator() bool { - return m.Type == SeparatorType -} - -func (m *MenuItem) IsCheckbox() bool { - return m.Type == CheckboxType -} - -func (m *MenuItem) Disable() *MenuItem { - m.Disabled = true - return m -} - -func (m *MenuItem) Enable() *MenuItem { - m.Disabled = false - return m -} - -func (m *MenuItem) OnClick(click Callback) *MenuItem { - m.Click = click - return m -} - -func (m *MenuItem) SetAccelerator(acc *keys.Accelerator) *MenuItem { - m.Accelerator = acc - return m -} - -func (m *MenuItem) SetChecked(value bool) *MenuItem { - m.Checked = value - if m.Type != RadioType { - m.Type = CheckboxType - } - return m -} - -func (m *MenuItem) Hide() *MenuItem { - m.Hidden = true - return m -} - -func (m *MenuItem) Show() *MenuItem { - m.Hidden = false - return m -} - -func (m *MenuItem) IsRadio() bool { - return m.Type == RadioType -} - -func Label(label string) *MenuItem { - return &MenuItem{ - Type: TextType, - Label: label, - } -} - // Text is a helper to create basic Text menu items func Text(label string, accelerator *keys.Accelerator, click Callback) *MenuItem { return &MenuItem{ @@ -327,3 +267,16 @@ func SubMenu(label string, menu *Menu) *MenuItem { return result } + +// SubMenuWithID is a helper to create Submenus with an ID +func SubMenuWithID(label string, menu *Menu) *MenuItem { + result := &MenuItem{ + Label: label, + SubMenu: menu, + Type: SubmenuType, + } + + menu.setParent(result) + + return result +} diff --git a/v2/pkg/menu/menuroles.go b/v2/pkg/menu/menuroles.go index bcc0657fc..55f666a75 100644 --- a/v2/pkg/menu/menuroles.go +++ b/v2/pkg/menu/menuroles.go @@ -3,40 +3,37 @@ // Electron License: https://github.com/electron/electron/blob/master/LICENSE package menu -// Role is a type to identify menu roles -type Role int +/* +type Role string -// These constants need to be kept in sync with `v2/internal/frontend/desktop/darwin/Role.h` const ( - AppMenuRole Role = 1 - EditMenuRole = 2 - WindowMenuRole = 3 - // AboutRole Role = "about" - // UndoRole Role = "undo" - // RedoRole Role = "redo" - // CutRole Role = "cut" - // CopyRole Role = "copy" - // PasteRole Role = "paste" - // PasteAndMatchStyleRole Role = "pasteAndMatchStyle" - // SelectAllRole Role = "selectAll" - // DeleteRole Role = "delete" - // MinimizeRole Role = "minimize" - // QuitRole Role = "quit" - // TogglefullscreenRole Role = "togglefullscreen" - // FileMenuRole Role = "fileMenu" - // ViewMenuRole Role = "viewMenu" - // WindowMenuRole Role = "windowMenu" - // HideRole Role = "hide" - // HideOthersRole Role = "hideOthers" - // UnhideRole Role = "unhide" - // FrontRole Role = "front" - // ZoomRole Role = "zoom" - // WindowSubMenuRole Role = "windowSubMenu" - // HelpSubMenuRole Role = "helpSubMenu" - // SeparatorItemRole Role = "separatorItem" + AboutRole Role = "about" + UndoRole Role = "undo" + RedoRole Role = "redo" + CutRole Role = "cut" + CopyRole Role = "copy" + PasteRole Role = "paste" + PasteAndMatchStyleRole Role = "pasteAndMatchStyle" + SelectAllRole Role = "selectAll" + DeleteRole Role = "delete" + MinimizeRole Role = "minimize" + QuitRole Role = "quit" + TogglefullscreenRole Role = "togglefullscreen" + FileMenuRole Role = "fileMenu" + EditMenuRole Role = "editMenu" + ViewMenuRole Role = "viewMenu" + WindowMenuRole Role = "windowMenu" + AppMenuRole Role = "appMenu" + HideRole Role = "hide" + HideOthersRole Role = "hideOthers" + UnhideRole Role = "unhide" + FrontRole Role = "front" + ZoomRole Role = "zoom" + WindowSubMenuRole Role = "windowSubMenu" + HelpSubMenuRole Role = "helpSubMenu" + SeparatorItemRole Role = "separatorItem" ) -/* // About provides a MenuItem with the About role func About() *MenuItem { return &MenuItem{ @@ -114,8 +111,8 @@ func Quit() *MenuItem { } } -// ToggleFullscreen provides a MenuItem with the ToggleFullscreen role -func ToggleFullscreen() *MenuItem { +// Togglefullscreen provides a MenuItem with the Togglefullscreen role +func Togglefullscreen() *MenuItem { return &MenuItem{ Role: TogglefullscreenRole, } @@ -127,7 +124,6 @@ func FileMenu() *MenuItem { Role: FileMenuRole, } } -*/ // EditMenu provides a MenuItem with the whole default "Edit" menu (Undo, Copy, etc.). func EditMenu() *MenuItem { @@ -136,17 +132,14 @@ func EditMenu() *MenuItem { } } -/* // ViewMenu provides a MenuItem with the whole default "View" menu (Reload, Toggle Developer Tools, etc.) func ViewMenu() *MenuItem { return &MenuItem{ Role: ViewMenuRole, } } -*/ // WindowMenu provides a MenuItem with the whole default "Window" menu (Minimize, Zoom, etc.). -// On MacOS currently all options in there won't work if the window is frameless. func WindowMenu() *MenuItem { return &MenuItem{ Role: WindowMenuRole, @@ -162,7 +155,6 @@ func AppMenu() *MenuItem { } } -/* // Hide provides a MenuItem that maps to the hide action. func Hide() *MenuItem { return &MenuItem{ @@ -177,8 +169,8 @@ func HideOthers() *MenuItem { } } -// UnHide provides a MenuItem that maps to the unHideAllApplications action. -func UnHide() *MenuItem { +// Unhide provides a MenuItem that maps to the unhideAllApplications action. +func Unhide() *MenuItem { return &MenuItem{ Role: UnhideRole, } diff --git a/v2/pkg/menu/styledlabel.go b/v2/pkg/menu/styledlabel.go index 1e996b971..9179cd2dc 100644 --- a/v2/pkg/menu/styledlabel.go +++ b/v2/pkg/menu/styledlabel.go @@ -29,31 +29,24 @@ type StyledText struct { func (s *StyledText) Bold() bool { return s.Style&Bold == Bold } - func (s *StyledText) Faint() bool { return s.Style&Faint == Faint } - func (s *StyledText) Italic() bool { return s.Style&Italic == Italic } - func (s *StyledText) Blinking() bool { return s.Style&Blinking == Blinking } - func (s *StyledText) Inversed() bool { return s.Style&Inversed == Inversed } - func (s *StyledText) Invisible() bool { return s.Style&Invisible == Invisible } - func (s *StyledText) Underlined() bool { return s.Style&Underlined == Underlined } - func (s *StyledText) Strikethrough() bool { return s.Style&Strikethrough == Strikethrough } @@ -258,4 +251,6 @@ func ParseANSI(input string) ([]*StyledText, error) { } } } + + return result, nil } diff --git a/v2/pkg/menu/styledlabel_test.go b/v2/pkg/menu/styledlabel_test.go index 1c43480e8..204190b7e 100644 --- a/v2/pkg/menu/styledlabel_test.go +++ b/v2/pkg/menu/styledlabel_test.go @@ -18,7 +18,7 @@ func TestParseAnsi16SingleColour(t *testing.T) { {"No formatting", "Hello World", "Hello World", "", false}, {"Black", "\u001b[0;30mHello World\033[0m", "Hello World", "Black", false}, {"Red", "\u001b[0;31mHello World\033[0m", "Hello World", "Maroon", false}, - {"Green", "\u001b[0;32mHello World\033[0m", "Hello World", "Green", false}, + {"Green", "\u001b[0;32m\033[0m", "", "Green", false}, {"Yellow", "\u001b[0;33m😀\033[0m", "😀", "Olive", false}, {"Blue", "\u001b[0;34m123\033[0m", "123", "Navy", false}, {"Purple", "\u001b[0;35m👩🏽‍🔧\u001B[0m", "👩🏽‍🔧", "Purple", false}, @@ -26,7 +26,7 @@ func TestParseAnsi16SingleColour(t *testing.T) { {"White", "\u001b[0;37m[0;37m\033[0m", "[0;37m", "Silver", false}, {"Black Bold", "\u001b[1;30mHello World\033[0m", "Hello World", "Grey", false}, {"Red Bold", "\u001b[1;31mHello World\033[0m", "Hello World", "Red", false}, - {"Green Bold", "\u001b[1;32mTest\033[0m", "Test", "Lime", false}, + {"Green Bold", "\u001b[1;32m\033[0m", "", "Lime", false}, {"Yellow Bold", "\u001b[1;33m😀\033[0m", "😀", "Yellow", false}, {"Blue Bold", "\u001b[1;34m123\033[0m", "123", "Blue", false}, {"Purple Bold", "\u001b[1;35m👩🏽‍🔧\u001B[0m", "👩🏽‍🔧", "Fuchsia", false}, @@ -109,7 +109,7 @@ func TestParseAnsi16MultiColour(t *testing.T) { }, false}, {"Green Invisible & Yellow Invisible & Strikethrough", "\u001B[8;32m👩🏽‍🔧\u001B[0m\u001B[9;33m👩🏽‍🔧\u001B[0m", []*StyledText{ {Label: "👩🏽‍🔧", FgCol: &Col{Name: "Green"}, Style: Invisible}, - {Label: "👩🏽‍🔧", FgCol: &Col{Name: "Olive"}, Style: Strikethrough}, + {Label: "👩🏽‍🔧", FgCol: &Col{Name: "Olive"}, Style: Invisible | Strikethrough}, }, false}, } for _, tt := range tests { diff --git a/v2/pkg/menu/tray.go b/v2/pkg/menu/tray.go index c8728f1f7..7554795ad 100644 --- a/v2/pkg/menu/tray.go +++ b/v2/pkg/menu/tray.go @@ -2,6 +2,7 @@ package menu // TrayMenu are the options type TrayMenu struct { + // Label is the text we wish to display in the tray Label string @@ -26,7 +27,7 @@ type TrayMenu struct { Tooltip string // Callback function when menu clicked - // Click Callback `json:"-"` + //Click Callback `json:"-"` // Disabled makes the item unselectable Disabled bool diff --git a/v2/pkg/options/assetserver/middleware.go b/v2/pkg/options/assetserver/middleware.go deleted file mode 100644 index b3826ab7d..000000000 --- a/v2/pkg/options/assetserver/middleware.go +++ /dev/null @@ -1,20 +0,0 @@ -package assetserver - -import ( - "net/http" -) - -// Middleware defines a HTTP middleware that can be applied to the AssetServer. -// The handler passed as next is the next handler in the chain. One can decide to call the next handler -// or implement a specialized handling. -type Middleware func(next http.Handler) http.Handler - -// ChainMiddleware allows chaining multiple middlewares to one middleware. -func ChainMiddleware(middleware ...Middleware) Middleware { - return func(h http.Handler) http.Handler { - for i := len(middleware) - 1; i >= 0; i-- { - h = middleware[i](h) - } - return h - } -} diff --git a/v2/pkg/options/assetserver/options.go b/v2/pkg/options/assetserver/options.go deleted file mode 100644 index 674451a0c..000000000 --- a/v2/pkg/options/assetserver/options.go +++ /dev/null @@ -1,45 +0,0 @@ -package assetserver - -import ( - "fmt" - "io/fs" - "net/http" -) - -// Options defines the configuration of the AssetServer. -type Options struct { - // Assets defines the static assets to be used. A GET request is first tried to be served from this Assets. If the Assets returns - // `os.ErrNotExist` for that file, the request handling will fallback to the Handler and tries to serve the GET - // request from it. - // - // If set to nil, all GET requests will be forwarded to Handler. - Assets fs.FS - - // Handler will be called for every GET request that can't be served from Assets, due to `os.ErrNotExist`. Furthermore all - // non GET requests will always be served from this Handler. - // - // If not defined, the result is the following in cases where the Handler would have been called: - // GET request: `http.StatusNotFound` - // Other request: `http.StatusMethodNotAllowed` - Handler http.Handler - - // Middleware is a HTTP Middleware which allows to hook into the AssetServer request chain. It allows to skip the default - // request handler dynamically, e.g. implement specialized Routing etc. - // The Middleware is called to build a new `http.Handler` used by the AssetSever and it also receives the default - // handler used by the AssetServer as an argument. - // - // If not defined, the default AssetServer request chain is executed. - // - // Multiple Middlewares can be chained together with: - // ChainMiddleware(middleware ...Middleware) Middleware - Middleware Middleware -} - -// Validate the options -func (o Options) Validate() error { - if o.Assets == nil && o.Handler == nil && o.Middleware == nil { - return fmt.Errorf("AssetServer options invalid: either Assets, Handler or Middleware must be set") - } - - return nil -} diff --git a/v2/pkg/options/debug.go b/v2/pkg/options/debug.go deleted file mode 100644 index b1e989b9a..000000000 --- a/v2/pkg/options/debug.go +++ /dev/null @@ -1,7 +0,0 @@ -package options - -// Debug options which are taken into account in debug builds. -type Debug struct { - // OpenInspectorOnStartup opens the inspector on startup of the app. - OpenInspectorOnStartup bool -} diff --git a/v2/pkg/options/default.go b/v2/pkg/options/default.go new file mode 100644 index 000000000..df3f3d52c --- /dev/null +++ b/v2/pkg/options/default.go @@ -0,0 +1,13 @@ +package options + +import ( + "github.com/wailsapp/wails/v2/pkg/logger" +) + +// Default options for creating the App +var Default = &App{ + Width: 1024, + Height: 768, + Logger: logger.NewDefaultLogger(), + LogLevel: logger.INFO, +} diff --git a/v2/pkg/options/linux/linux.go b/v2/pkg/options/linux/linux.go deleted file mode 100644 index 797450c27..000000000 --- a/v2/pkg/options/linux/linux.go +++ /dev/null @@ -1,56 +0,0 @@ -package linux - -// WebviewGpuPolicy values used for determining the webview's hardware acceleration policy. -type WebviewGpuPolicy int - -const ( - // WebviewGpuPolicyAlways Hardware acceleration is always enabled. - WebviewGpuPolicyAlways WebviewGpuPolicy = iota - // WebviewGpuPolicyOnDemand Hardware acceleration is enabled/disabled as request by web contents. - WebviewGpuPolicyOnDemand - // WebviewGpuPolicyNever Hardware acceleration is always disabled. - WebviewGpuPolicyNever -) - -// Options specific to Linux builds -type Options struct { - // Icon Sets up the icon representing the window. This icon is used when the window is minimized - // (also known as iconified). - Icon []byte - - // WindowIsTranslucent sets the window's background to transparent when enabled. - WindowIsTranslucent bool - - // Messages are messages that can be customised - Messages *Messages - - // WebviewGpuPolicy used for determining the hardware acceleration policy for the webview. - // - WebviewGpuPolicyAlways - // - WebviewGpuPolicyOnDemand - // - WebviewGpuPolicyNever - // - // Due to https://github.com/wailsapp/wails/issues/2977, if options.Linux is nil - // in the call to wails.Run(), WebviewGpuPolicy is set by default to WebviewGpuPolicyNever. - // Client code may override this behavior by passing a non-nil Options and set - // WebviewGpuPolicy as needed. - WebviewGpuPolicy WebviewGpuPolicy - - // ProgramName is used to set the program's name for the window manager via GTK's g_set_prgname(). - //This name should not be localized. [see the docs] - // - //When a .desktop file is created this value helps with window grouping and desktop icons when the .desktop file's Name - //property differs form the executable's filename. - // - //[see the docs]: https://docs.gtk.org/glib/func.set_prgname.html - ProgramName string -} - -type Messages struct { - WebKit2GTKMinRequired string -} - -func DefaultMessages() *Messages { - return &Messages{ - WebKit2GTKMinRequired: "This application requires at least WebKit2GTK %s to be installed.", - } -} diff --git a/v2/pkg/options/mac/mac.go b/v2/pkg/options/mac/mac.go index 152145114..63e4e6194 100644 --- a/v2/pkg/options/mac/mac.go +++ b/v2/pkg/options/mac/mac.go @@ -1,31 +1,19 @@ package mac -//type ActivationPolicy int -// -//const ( -// NSApplicationActivationPolicyRegular ActivationPolicy = 0 -// NSApplicationActivationPolicyAccessory ActivationPolicy = 1 -// NSApplicationActivationPolicyProhibited ActivationPolicy = 2 -//) +type ActivationPolicy int -type AboutInfo struct { - Title string - Message string - Icon []byte -} +const ( + NSApplicationActivationPolicyRegular ActivationPolicy = 0 + NSApplicationActivationPolicyAccessory ActivationPolicy = 1 + NSApplicationActivationPolicyProhibited ActivationPolicy = 2 +) // Options are options specific to Mac type Options struct { TitleBar *TitleBar Appearance AppearanceType - ContentProtection bool WebviewIsTransparent bool WindowIsTranslucent bool - Preferences *Preferences - DisableZoom bool - // ActivationPolicy ActivationPolicy - About *AboutInfo - OnFileOpen func(filePath string) `json:"-"` - OnUrlOpen func(filePath string) `json:"-"` - // URLHandlers map[string]func(string) + ActivationPolicy ActivationPolicy + //URLHandlers map[string]func(string) } diff --git a/v2/pkg/options/mac/preferences.go b/v2/pkg/options/mac/preferences.go deleted file mode 100644 index 0749ccb18..000000000 --- a/v2/pkg/options/mac/preferences.go +++ /dev/null @@ -1,21 +0,0 @@ -package mac - -import "github.com/leaanthony/u" - -var ( - Enabled = u.True - Disabled = u.False -) - -// Preferences allows to set webkit preferences -type Preferences struct { - // A Boolean value that indicates whether pressing the tab key changes the focus to links and form controls. - // Set to false by default. - TabFocusesLinks u.Bool - // A Boolean value that indicates whether to allow people to select or otherwise interact with text. - // Set to true by default. - TextInteractionEnabled u.Bool - // A Boolean value that indicates whether a web view can display content full screen. - // Set to false by default - FullscreenEnabled u.Bool -} diff --git a/v2/pkg/options/mac/titlebar.go b/v2/pkg/options/mac/titlebar.go index 51e0832ca..c18c4eea8 100644 --- a/v2/pkg/options/mac/titlebar.go +++ b/v2/pkg/options/mac/titlebar.go @@ -41,6 +41,7 @@ func TitleBarHidden() *TitleBar { // TitleBarHiddenInset results in a hidden title bar with an alternative look where // the traffic light buttons are slightly more inset from the window edge. func TitleBarHiddenInset() *TitleBar { + return &TitleBar{ TitlebarAppearsTransparent: true, HideTitle: true, @@ -49,4 +50,5 @@ func TitleBarHiddenInset() *TitleBar { UseToolbar: true, HideToolbarSeparator: true, } + } diff --git a/v2/pkg/options/options.go b/v2/pkg/options/options.go index 0f62d5e4b..61c800d52 100644 --- a/v2/pkg/options/options.go +++ b/v2/pkg/options/options.go @@ -2,34 +2,18 @@ package options import ( "context" - "html" - "io/fs" - "net/http" - "os" - "path/filepath" - "runtime" + "embed" + "log" - "github.com/wailsapp/wails/v2/pkg/options/assetserver" - "github.com/wailsapp/wails/v2/pkg/options/linux" "github.com/wailsapp/wails/v2/pkg/options/mac" "github.com/wailsapp/wails/v2/pkg/options/windows" "github.com/wailsapp/wails/v2/pkg/menu" + "github.com/imdario/mergo" "github.com/wailsapp/wails/v2/pkg/logger" ) -type WindowStartState int - -const ( - Normal WindowStartState = 0 - Maximised WindowStartState = 1 - Minimised WindowStartState = 2 - Fullscreen WindowStartState = 3 -) - -type Experimental struct{} - // App contains options for creating the App type App struct { Title string @@ -45,69 +29,22 @@ type App struct { StartHidden bool HideWindowOnClose bool AlwaysOnTop bool - // BackgroundColour is the background colour of the window - // You can use the options.NewRGB and options.NewRGBA functions to create a new colour - BackgroundColour *RGBA - // Deprecated: Use AssetServer.Assets instead. - Assets fs.FS - // Deprecated: Use AssetServer.Handler instead. - AssetsHandler http.Handler - // AssetServer configures the Assets for the application - AssetServer *assetserver.Options - Menu *menu.Menu - Logger logger.Logger `json:"-"` - LogLevel logger.LogLevel - LogLevelProduction logger.LogLevel - OnStartup func(ctx context.Context) `json:"-"` - OnDomReady func(ctx context.Context) `json:"-"` - OnShutdown func(ctx context.Context) `json:"-"` - OnBeforeClose func(ctx context.Context) (prevent bool) `json:"-"` - Bind []interface{} - EnumBind []interface{} - WindowStartState WindowStartState - - // ErrorFormatter overrides the formatting of errors returned by backend methods - ErrorFormatter ErrorFormatter - - // CSS property to test for draggable elements. Default "--wails-draggable" - CSSDragProperty string - - // The CSS Value that the CSSDragProperty must have to be draggable, EG: "drag" - CSSDragValue string - - // EnableDefaultContextMenu enables the browser's default context-menu in production - // This menu is already enabled in development and debug builds - EnableDefaultContextMenu bool - - // EnableFraudulentWebsiteDetection enables scan services for fraudulent content, such as malware or phishing attempts. - // These services might send information from your app like URLs navigated to and possibly other content to cloud - // services of Apple and Microsoft. - EnableFraudulentWebsiteDetection bool - - SingleInstanceLock *SingleInstanceLock + RGBA *RGBA + Assets embed.FS + Menu *menu.Menu + Logger logger.Logger `json:"-"` + LogLevel logger.LogLevel + OnStartup func(ctx context.Context) `json:"-"` + OnDomReady func(ctx context.Context) `json:"-"` + OnShutdown func(ctx context.Context) `json:"-"` + Bind []interface{} + //ContextMenus []*menu.ContextMenu + //TrayMenus []*menu.TrayMenu Windows *windows.Options Mac *mac.Options - Linux *linux.Options - - // Experimental options - Experimental *Experimental - - // Debug options for debug builds. These options will be ignored in a production build. - Debug Debug - - // DragAndDrop options for drag and drop behavior - DragAndDrop *DragAndDrop - - // DisablePanicRecovery disables the panic recovery system in messages processing - DisablePanicRecovery bool - - // List of additional allowed origins for bindings in format "https://*.myapp.com,https://example.com" - BindingsAllowedOrigins string } -type ErrorFormatter func(error) any - type RGBA struct { R uint8 `json:"r"` G uint8 `json:"g"` @@ -115,61 +52,16 @@ type RGBA struct { A uint8 `json:"a"` } -// NewRGBA creates a new RGBA struct with the given values -func NewRGBA(r, g, b, a uint8) *RGBA { - return &RGBA{ - R: r, - G: g, - B: b, - A: a, - } -} - -// NewRGB creates a new RGBA struct with the given values and Alpha set to 255 -func NewRGB(r, g, b uint8) *RGBA { - return &RGBA{ - R: r, - G: g, - B: b, - A: 255, - } -} - // MergeDefaults will set the minimum default values for an application func MergeDefaults(appoptions *App) { - // Do set defaults - if appoptions.Width <= 0 { - appoptions.Width = 1024 + err := mergo.Merge(appoptions, Default) + if err != nil { + log.Fatal(err) } - if appoptions.Height <= 0 { - appoptions.Height = 768 - } - if appoptions.Logger == nil { - appoptions.Logger = logger.NewDefaultLogger() - } - if appoptions.LogLevel == 0 { - appoptions.LogLevel = logger.INFO - } - if appoptions.LogLevelProduction == 0 { - appoptions.LogLevelProduction = logger.ERROR - } - if appoptions.CSSDragProperty == "" { - appoptions.CSSDragProperty = "--wails-draggable" - } - if appoptions.CSSDragValue == "" { - appoptions.CSSDragValue = "drag" - } - if appoptions.DragAndDrop == nil { - appoptions.DragAndDrop = &DragAndDrop{} - } - if appoptions.DragAndDrop.CSSDropProperty == "" { - appoptions.DragAndDrop.CSSDropProperty = "--wails-drop-target" - } - if appoptions.DragAndDrop.CSSDropValue == "" { - appoptions.DragAndDrop.CSSDropValue = "drop" - } - if appoptions.BackgroundColour == nil { - appoptions.BackgroundColour = &RGBA{ + + // DEfault colour. Doesn't work well with mergo + if appoptions.RGBA == nil { + appoptions.RGBA = &RGBA{ R: 255, G: 255, B: 255, @@ -178,73 +70,6 @@ func MergeDefaults(appoptions *App) { } // Ensure max and min are valid - processMinMaxConstraints(appoptions) - - // Default menus - processMenus(appoptions) - - // Process Drag Options - processDragOptions(appoptions) -} - -type SingleInstanceLock struct { - // uniqueId that will be used for setting up messaging between instances - UniqueId string - OnSecondInstanceLaunch func(secondInstanceData SecondInstanceData) -} - -type SecondInstanceData struct { - Args []string - WorkingDirectory string -} - -type DragAndDrop struct { - - // EnableFileDrop enables wails' drag and drop functionality that returns the dropped in files' absolute paths. - EnableFileDrop bool - - // Disable webview's drag and drop functionality. - // - // It can be used to prevent accidental file opening of dragged in files in the webview, when there is no need for drag and drop. - DisableWebViewDrop bool - - // CSS property to test for drag and drop target elements. Default "--wails-drop-target" - CSSDropProperty string - - // The CSS Value that the CSSDropProperty must have to be a valid drop target. Default "drop" - CSSDropValue string -} - -func NewSecondInstanceData() (*SecondInstanceData, error) { - ex, err := os.Executable() - if err != nil { - return nil, err - } - workingDirectory := filepath.Dir(ex) - - return &SecondInstanceData{ - Args: os.Args[1:], - WorkingDirectory: workingDirectory, - }, nil -} - -func processMenus(appoptions *App) { - switch runtime.GOOS { - case "darwin": - if appoptions.Menu == nil { - items := []*menu.MenuItem{ - menu.EditMenu(), - } - if !appoptions.Frameless { - items = append(items, menu.WindowMenu()) // Current options in Window Menu only work if not frameless - } - - appoptions.Menu = menu.NewMenuFromItems(menu.AppMenu(), items...) - } - } -} - -func processMinMaxConstraints(appoptions *App) { if appoptions.MinWidth > 0 && appoptions.MaxWidth > 0 { if appoptions.MinWidth > appoptions.MaxWidth { appoptions.MinWidth = appoptions.MaxWidth @@ -268,9 +93,5 @@ func processMinMaxConstraints(appoptions *App) { if appoptions.MaxHeight > 0 && appoptions.Height > appoptions.MaxHeight { appoptions.Height = appoptions.MaxHeight } -} -func processDragOptions(appoptions *App) { - appoptions.CSSDragProperty = html.EscapeString(appoptions.CSSDragProperty) - appoptions.CSSDragValue = html.EscapeString(appoptions.CSSDragValue) } diff --git a/v2/pkg/options/options_test.go b/v2/pkg/options/options_test.go index 0cacd702d..5f75b5acc 100644 --- a/v2/pkg/options/options_test.go +++ b/v2/pkg/options/options_test.go @@ -14,8 +14,8 @@ func TestMergeDefaultsWH(t *testing.T) { { name: "No width and height", appoptions: &App{}, - wantWidth: 1024, - wantHeight: 768, + wantWidth: Default.Width, + wantHeight: Default.Height, }, { name: "Basic width and height", diff --git a/v2/pkg/options/windows/windows.go b/v2/pkg/options/windows/windows.go index 1fe351455..33c842b2a 100644 --- a/v2/pkg/options/windows/windows.go +++ b/v2/pkg/options/windows/windows.go @@ -1,167 +1,8 @@ package windows -type Theme int - -type Messages struct { - InstallationRequired string - UpdateRequired string - MissingRequirements string - Webview2NotInstalled string - Error string - FailedToInstall string - DownloadPage string - PressOKToInstall string - ContactAdmin string - InvalidFixedWebview2 string - WebView2ProcessCrash string -} - -const ( - // SystemDefault will use whatever the system theme is. The application will follow system theme changes. - SystemDefault Theme = 0 - // Dark Mode - Dark Theme = 1 - // Light Mode - Light Theme = 2 -) - -type BackdropType int32 - -const ( - Auto BackdropType = 0 - None BackdropType = 1 - Mica BackdropType = 2 - Acrylic BackdropType = 3 - Tabbed BackdropType = 4 -) - -const ( - // Default is 0, which means no changes to the default Windows DLL search behavior - DLLSearchDefault uint32 = 0 - // LoadLibrary flags for determining from where to search for a DLL - DLLSearchDontResolveDllReferences uint32 = 0x1 // windows.DONT_RESOLVE_DLL_REFERENCES - DLLSearchAsDataFile uint32 = 0x2 // windows.LOAD_LIBRARY_AS_DATAFILE - DLLSearchWithAlteredPath uint32 = 0x8 // windows.LOAD_WITH_ALTERED_SEARCH_PATH - DLLSearchIgnoreCodeAuthzLevel uint32 = 0x10 // windows.LOAD_IGNORE_CODE_AUTHZ_LEVEL - DLLSearchAsImageResource uint32 = 0x20 // windows.LOAD_LIBRARY_AS_IMAGE_RESOURCE - DLLSearchAsDataFileExclusive uint32 = 0x40 // windows.LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE - DLLSearchRequireSignedTarget uint32 = 0x80 // windows.LOAD_LIBRARY_REQUIRE_SIGNED_TARGET - DLLSearchDllLoadDir uint32 = 0x100 // windows.LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR - DLLSearchApplicationDir uint32 = 0x200 // windows.LOAD_LIBRARY_SEARCH_APPLICATION_DIR - DLLSearchUserDirs uint32 = 0x400 // windows.LOAD_LIBRARY_SEARCH_USER_DIRS - DLLSearchSystem32 uint32 = 0x800 // windows.LOAD_LIBRARY_SEARCH_SYSTEM32 - DLLSearchDefaultDirs uint32 = 0x1000 // windows.LOAD_LIBRARY_SEARCH_DEFAULT_DIRS - DLLSearchSafeCurrentDirs uint32 = 0x2000 // windows.LOAD_LIBRARY_SAFE_CURRENT_DIRS - DLLSearchSystem32NoForwarder uint32 = 0x4000 // windows.LOAD_LIBRARY_SEARCH_SYSTEM32_NO_FORWARDER - DLLSearchOsIntegrityContinuity uint32 = 0x8000 // windows.LOAD_LIBRARY_OS_INTEGRITY_CONTINUITY -) - -func RGB(r, g, b uint8) int32 { - col := int32(b) - col = col<<8 | int32(g) - col = col<<8 | int32(r) - return col -} - -// ThemeSettings contains optional colours to use. -// They may be set using the hex values: 0x00BBGGRR -type ThemeSettings struct { - DarkModeTitleBar int32 - DarkModeTitleBarInactive int32 - DarkModeTitleText int32 - DarkModeTitleTextInactive int32 - DarkModeBorder int32 - DarkModeBorderInactive int32 - LightModeTitleBar int32 - LightModeTitleBarInactive int32 - LightModeTitleText int32 - LightModeTitleTextInactive int32 - LightModeBorder int32 - LightModeBorderInactive int32 -} - // Options are options specific to Windows type Options struct { - ContentProtection bool WebviewIsTransparent bool WindowIsTranslucent bool DisableWindowIcon bool - - IsZoomControlEnabled bool - ZoomFactor float64 - - DisablePinchZoom bool - - // Disable all window decorations in Frameless mode, which means no "Aero Shadow" and no "Rounded Corner" will be shown. - // "Rounded Corners" are only available on Windows 11. - DisableFramelessWindowDecorations bool - - // Path where the WebView2 stores the user data. If empty %APPDATA%\[BinaryName.exe] will be used. - // If the path is not valid, a messagebox will be displayed with the error and the app will exit with error code. - WebviewUserDataPath string - - // Path to the directory with WebView2 executables. If empty WebView2 installed in the system will be used. - WebviewBrowserPath string - - // Dark/Light or System Default Theme - Theme Theme - - // Custom settings for dark/light mode - CustomTheme *ThemeSettings - - // Select the type of translucent backdrop. Requires Windows 11 22621 or later. - BackdropType BackdropType - - // User messages that can be customised - Messages *Messages - - // ResizeDebounceMS is the amount of time to debounce redraws of webview2 - // when resizing the window - ResizeDebounceMS uint16 - - // OnSuspend is called when Windows enters low power mode - OnSuspend func() - - // OnResume is called when Windows resumes from low power mode - OnResume func() - - // WebviewGpuIsDisabled is used to enable / disable GPU acceleration for the webview - WebviewGpuIsDisabled bool - - // WebviewDisableRendererCodeIntegrity disables the `RendererCodeIntegrity` of WebView2. Some Security Endpoint - // Protection Software inject themself into the WebView2 with unsigned or wrongly signed dlls, which is not allowed - // and will stop the WebView2 processes. Those security software need an update to fix this issue or one can disable - // the integrity check with this flag. - // - // The event viewer log contains `Code Integrity Errors` like mentioned here: https://github.com/MicrosoftEdge/WebView2Feedback/issues/2051 - // - // !! Please keep in mind when disabling this feature, this also allows malicious software to inject into the WebView2 !! - WebviewDisableRendererCodeIntegrity bool - - // Configure whether swipe gestures should be enabled - EnableSwipeGestures bool - - // Class name for the window. If empty, 'wailsWindow' will be used. - WindowClassName string - - // DLLSearchPaths controls which directories are searched when loading DLLs - // Set to 0 for default behavior, or combine multiple flags with bitwise OR - // Example: DLLSearchApplicationDir | DLLSearchSystem32 - DLLSearchPaths uint32 -} - -func DefaultMessages() *Messages { - return &Messages{ - InstallationRequired: "The WebView2 runtime is required. Press Ok to download and install. Note: The installer will download silently so please wait.", - UpdateRequired: "The WebView2 runtime needs updating. Press Ok to download and install. Note: The installer will download silently so please wait.", - MissingRequirements: "Missing Requirements", - Webview2NotInstalled: "WebView2 runtime not installed", - Error: "Error", - FailedToInstall: "The runtime failed to install correctly. Please try again.", - DownloadPage: "This application requires the WebView2 runtime. Press OK to open the download page. Minimum version required: ", - PressOKToInstall: "Press Ok to install.", - ContactAdmin: "The WebView2 runtime is required to run this application. Please contact your system administrator.", - InvalidFixedWebview2: "The WebView2 runtime is manually specified, but It is not valid. Check minimum required version and webview2 path.", - WebView2ProcessCrash: "The WebView2 process crashed and the application needs to be restarted.", - } } diff --git a/v2/pkg/parser/applicationVariableName.go b/v2/pkg/parser/applicationVariableName.go new file mode 100644 index 000000000..de4252933 --- /dev/null +++ b/v2/pkg/parser/applicationVariableName.go @@ -0,0 +1,50 @@ +package parser + +import "go/ast" + +func (p *Package) getApplicationVariableName(file *ast.File, wailsImportName string) string { + + // Iterate through the whole file looking for the application name + applicationVariableName := "" + + // Inspect the file + ast.Inspect(file, func(n ast.Node) bool { + // Parse Assignments looking for application name + if assignStmt, ok := n.(*ast.AssignStmt); ok { + + // Check the RHS is of the form: + // `app := wails.CreateApp()` or + // `app := wails.CreateAppWithOptions` + for _, rhs := range assignStmt.Rhs { + ce, ok := rhs.(*ast.CallExpr) + if !ok { + continue + } + se, ok := ce.Fun.(*ast.SelectorExpr) + if !ok { + continue + } + i, ok := se.X.(*ast.Ident) + if !ok { + continue + } + // Have we found the wails import name? + if i.Name == wailsImportName { + // Check we are calling a function to create the app + if se.Sel.Name == "CreateApp" || se.Sel.Name == "CreateAppWithOptions" { + if len(assignStmt.Lhs) == 1 { + i, ok := assignStmt.Lhs[0].(*ast.Ident) + if ok { + // Found the app variable name + applicationVariableName = i.Name + return false + } + } + } + } + } + } + return true + }) + return applicationVariableName +} diff --git a/v2/pkg/parser/comments.go b/v2/pkg/parser/comments.go new file mode 100644 index 000000000..019e9880c --- /dev/null +++ b/v2/pkg/parser/comments.go @@ -0,0 +1,21 @@ +package parser + +import ( + "go/ast" + "strings" +) + +func parseComments(comments *ast.CommentGroup) []string { + var result []string + + if comments == nil { + return result + } + + for _, comment := range comments.List { + commentText := strings.TrimPrefix(comment.Text, "//") + result = append(result, commentText) + } + + return result +} diff --git a/v2/pkg/parser/conversion.go b/v2/pkg/parser/conversion.go new file mode 100644 index 000000000..99daa62f2 --- /dev/null +++ b/v2/pkg/parser/conversion.go @@ -0,0 +1,156 @@ +package parser + +import ( + "fmt" + "strings" + + "github.com/leaanthony/slicer" +) + +// JSType represents a javascript type +type JSType string + +const ( + // JsString is a JS string + JsString JSType = "string" + // JsBoolean is a JS bool + JsBoolean = "boolean" + // JsInt is a JS number + JsInt = "number" + // JsFloat is a JS number + JsFloat = "number" + // JsArray is a JS array + JsArray = "Array" + // JsObject is a JS object + JsObject = "Object" + // JsUnsupported represents a type that cannot be converted + JsUnsupported = "*" +) + +func goTypeToJS(input *Field) string { + switch input.Type { + case "string": + return "string" + case "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64": + return "number" + case "float32", "float64": + return "number" + case "bool": + return "boolean" + // case reflect.Array, reflect.Slice: + // return JsArray + // case reflect.Ptr, reflect.Struct, reflect.Map, reflect.Interface: + // return JsObject + case "struct": + return input.Struct.Name + default: + fmt.Printf("Unsupported input to goTypeToJS: %+v", input) + return "*" + } +} + +// goTypeToTS converts the given field into a Typescript type +// The pkgName is the package that the field is being output in. +// This is used to ensure we don't qualify local structs. +func goTypeToTS(input *Field, pkgName string) string { + var result string + switch input.Type { + case "string": + result = "string" + case "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64": + result = "number" + case "float32", "float64": + result = "number" + case "bool": + result = "boolean" + case "struct": + if input.Struct.Package.Name != "" { + if input.Struct.Package.Name != pkgName { + result = input.Struct.Package.Name + "." + } + } + result += input.Struct.Name + // case reflect.Array, reflect.Slice: + // return string(JsArray) + // case reflect.Ptr, reflect.Struct: + // fqt := input.Type().String() + // return strings.Split(fqt, ".")[1] + // case reflect.Map, reflect.Interface: + // return string(JsObject) + default: + fmt.Printf("Unsupported input to goTypeToTS: %+v", input) + return JsUnsupported + } + + if input.IsArray { + result = result + "[]" + } + + return result +} + +func goTypeToTSDeclaration(input *Field, pkgName string) string { + var result string + switch input.Type { + case "string": + result = "string" + case "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64": + result = "number" + case "float32", "float64": + result = "number" + case "bool": + result = "boolean" + case "struct": + if input.Struct.Package.Name != "" { + if input.Struct.Package.Name != pkgName { + result = `import("./_` + input.Struct.Package.Name + `").` + } + } + result += input.Struct.Name + // case reflect.Array, reflect.Slice: + // return string(JsArray) + // case reflect.Ptr, reflect.Struct: + // fqt := input.Type().String() + // return strings.Split(fqt, ".")[1] + // case reflect.Map, reflect.Interface: + // return string(JsObject) + default: + fmt.Printf("Unsupported input to goTypeToTS: %+v", input) + return JsUnsupported + } + + if input.IsArray { + result = result + "[]" + } + + return result +} + +func isUnresolvedType(typeName string) bool { + switch typeName { + case "string": + return false + case "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64": + return false + case "float32", "float64": + return false + case "bool": + return false + case "struct": + return false + default: + return true + } +} + +var reservedJSWords []string = []string{"abstract", "arguments", "await", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue", "debugger", "default", "delete", "do", "double", "else", "enum", "eval", "export", "extends", "false", "final", "finally", "float", "for", "function", "goto", "if", "implements", "import", "in", "instanceof", "int", "interface", "let", "long", "native", "new", "null", "package", "private", "protected", "public", "return", "short", "static", "super", "switch", "synchronized", "this", "throw", "throws", "transient", "true", "try", "typeof", "var", "void", "volatile", "while", "with", "yield", "Array", "Date", "eval", "function", "hasOwnProperty", "Infinity", "isFinite", "isNaN", "isPrototypeOf", "length", "Math", "NaN", "Number", "Object", "prototype", "String", "toString", "undefined", "valueOf"} +var jsReservedWords *slicer.StringSlicer = slicer.String(reservedJSWords) + +func isJSReservedWord(input string) bool { + return jsReservedWords.Contains(input) +} + +func startsWithLowerCaseLetter(input string) bool { + firstLetter := string(input[0]) + return strings.ToLower(firstLetter) == firstLetter +} diff --git a/v2/pkg/parser/field.go b/v2/pkg/parser/field.go new file mode 100644 index 000000000..bcdc76427 --- /dev/null +++ b/v2/pkg/parser/field.go @@ -0,0 +1,309 @@ +package parser + +import ( + "fmt" + "go/ast" + "strings" + + "github.com/fatih/structtag" +) + +// Field defines a parsed struct field +type Field struct { + + // Name of the field + Name string + + // The type of the field. + // "struct" if it's a struct + Type string + + // A pointer to the struct if the Type is "struct" + Struct *Struct + + // User comments on the field + Comments []string + + // Indicates if the Field is an array of type "Type" + IsArray bool + + // JSON field name defined by a json tag + JSONOptions +} + +type JSONOptions struct { + Name string + IsOptional bool + Ignored bool +} + +// JSType returns the Javascript type for this field +func (f *Field) JSType() string { + return string(goTypeToJS(f)) +} + +// JSName returns the Javascript name for this field +func (f *Field) JSName() string { + if f.JSONOptions.Name != "" { + return f.JSONOptions.Name + } + return f.Name +} + +// TSName returns the Typescript name for this field +func (f *Field) TSName() string { + result := f.Name + if f.JSONOptions.Name != "" { + result = f.JSONOptions.Name + } + if f.IsOptional { + result += "?" + } + return result +} + +// AsTSDeclaration returns a TS definition of a single type field +func (f *Field) AsTSDeclaration(pkgName string) string { + return f.TSName() + ": " + f.TypeAsTSType(pkgName) +} + +// NameForPropertyDoc returns a formatted name for the jsdoc @property declaration +func (f *Field) NameForPropertyDoc() string { + if f.IsOptional { + return "[" + f.JSName() + "]" + } + return f.JSName() +} + +// TypeForPropertyDoc returns a formatted name for the jsdoc @property declaration +func (f *Field) TypeForPropertyDoc() string { + result := goTypeToJS(f) + if f.IsArray { + result += "[]" + } + return result +} + +// TypeAsTSType converts the Field type to something TS wants +func (f *Field) TypeAsTSType(pkgName string) string { + var result = "" + switch f.Type { + case "string": + result = "string" + case "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64": + result = "number" + case "float32", "float64": + result = "number" + case "bool": + result = "boolean" + case "struct": + if f.Struct.Package != nil { + if f.Struct.Package.Name != pkgName { + result = f.Struct.Package.Name + "." + } + } + result = result + f.Struct.Name + default: + result = "any" + } + + return result +} + +func (p *Parser) parseField(file *ast.File, field *ast.Field, pkg *Package) ([]*Field, error) { + var result []*Field + + var fieldType string + var strct *Struct + var isArray bool + + var jsonOptions JSONOptions + + // Determine type + switch t := field.Type.(type) { + case *ast.Ident: + fieldType = t.Name + + unresolved := isUnresolvedType(fieldType) + + // Check if this type is actually a struct + if unresolved { + // Assume it is a struct + // Parse the struct + var err error + strct, err = p.parseStruct(pkg, t.Name) + if err != nil { + return nil, err + } + + if strct == nil { + fieldName := "" + if len(field.Names) > 0 { + fieldName = field.Names[0].Name + } + return nil, fmt.Errorf("unresolved type in field %s: %s", fieldName, fieldType) + } + + fieldType = "struct" + + } + case *ast.StarExpr: + fieldType = "struct" + packageName, structName, err := parseStructNameFromStarExpr(t) + if err != nil { + return nil, err + } + + // If this is an external package, find it + if packageName != "" { + referencedGoPackage := pkg.getImportByName(packageName, file) + referencedPackage := p.getPackageByID(referencedGoPackage.ID) + + // If we found the struct, save it as an external package reference + if referencedPackage != nil { + pkg.addExternalReference(referencedPackage) + } + + // We save this to pkg anyway, because we want to know if this package + // was NOT found + pkg = referencedPackage + } + + // If this is a package in our project, parse the struct! + if pkg != nil { + + // Parse the struct + strct, err = p.parseStruct(pkg, structName) + if err != nil { + return nil, err + } + + } + + case *ast.ArrayType: + isArray = true + // Parse the Elt (There must be a better way!) + switch t := t.Elt.(type) { + case *ast.Ident: + fieldType = t.Name + case *ast.StarExpr: + fieldType = "struct" + packageName, structName, err := parseStructNameFromStarExpr(t) + if err != nil { + return nil, err + } + + // If this is an external package, find it + if packageName != "" { + referencedGoPackage := pkg.getImportByName(packageName, file) + referencedPackage := p.getPackageByID(referencedGoPackage.ID) + + // If we found the struct, save it as an external package reference + if referencedPackage != nil { + pkg.addExternalReference(referencedPackage) + } + + // We save this to pkg anyway, because we want to know if this package + // was NOT found + pkg = referencedPackage + } + + // If this is a package in our project, parse the struct! + if pkg != nil { + + // Parse the struct + strct, err = p.parseStruct(pkg, structName) + if err != nil { + return nil, err + } + + } + default: + // We will default to "Array" for eg nested arrays + fieldType = "any" + } + + default: + return nil, fmt.Errorf("unsupported field found in struct: %+v", t) + } + + // Parse json tag if available + if field.Tag != nil { + err := parseJSONOptions(field.Tag.Value, &jsonOptions) + if err != nil { + return nil, err + } + } + + // Loop over names if we have + if len(field.Names) > 0 { + + for _, name := range field.Names { + + // TODO: Check field names are valid in JS + if isJSReservedWord(name.Name) { + return nil, fmt.Errorf("unable to use field name %s - reserved word in Javascript", name.Name) + } + + // Create a field per name + thisField := &Field{ + Comments: parseComments(field.Doc), + } + thisField.Name = name.Name + thisField.Type = fieldType + thisField.Struct = strct + thisField.IsArray = isArray + thisField.JSONOptions = jsonOptions + + result = append(result, thisField) + } + return result, nil + } + + // When we have no name + thisField := &Field{ + Comments: parseComments(field.Doc), + } + thisField.Type = fieldType + thisField.Struct = strct + thisField.IsArray = isArray + result = append(result, thisField) + + return result, nil +} + +func parseJSONOptions(fieldTag string, jsonOptions *JSONOptions) error { + + // Remove backticks + fieldTag = strings.Trim(fieldTag, "`") + + // Parse the tag + tags, err := structtag.Parse(fieldTag) + if err != nil { + return err + } + + jsonTag, err := tags.Get("json") + if err != nil { + return err + } + + if jsonTag == nil { + return nil + } + + // Save the name + jsonOptions.Name = jsonTag.Name + + // Check if this field is ignored + if jsonTag.Name == "-" { + jsonOptions.Ignored = true + } + + // Check if this field is optional + if jsonTag.HasOption("omitempty") { + jsonOptions.IsOptional = true + } + + return nil +} diff --git a/v2/pkg/parser/findBoundStructs.go b/v2/pkg/parser/findBoundStructs.go new file mode 100644 index 000000000..91876a8b2 --- /dev/null +++ b/v2/pkg/parser/findBoundStructs.go @@ -0,0 +1,152 @@ +package parser + +import ( + "fmt" + "go/ast" +) + +// findBoundStructs will search through the Wails project looking +// for which structs have been bound using the `Bind()` method +func (p *Parser) findBoundStructs(pkg *Package) error { + + // Iterate through the files in the package looking for the bound structs + for _, fileAst := range pkg.Gopackage.Syntax { + + // Find the wails import name + wailsImportName := pkg.getWailsImportName(fileAst) + + // If this file doesn't import wails, continue + if wailsImportName == "" { + continue + } + + applicationVariableName := pkg.getApplicationVariableName(fileAst, wailsImportName) + if applicationVariableName == "" { + continue + } + + var parseError error + + ast.Inspect(fileAst, func(n ast.Node) bool { + // Parse Call expressions looking for bind calls + callExpr, ok := n.(*ast.CallExpr) + if !ok { + return true + } + // Check this is the right kind of expression (something.something()) + f, ok := callExpr.Fun.(*ast.SelectorExpr) + if !ok { + return true + } + ident, ok := f.X.(*ast.Ident) + if !ok { + return true + } + + if ident.Name != applicationVariableName { + return true + } + + if f.Sel.Name != "Bind" { + return true + } + + if len(callExpr.Args) != 1 { + return true + } + + // Work out what was bound + switch boundItem := callExpr.Args[0].(type) { + + // app.Bind( someFunction() ) + case *ast.CallExpr: + switch fn := boundItem.Fun.(type) { + case *ast.Ident: + // boundStructs = append(boundStructs, newStruct(pkg.Name, fn.Name)) + strct, err := p.getFunctionReturnType(pkg, fn.Name) + if err != nil { + parseError = err + return false + } + if strct == nil { + parseError = fmt.Errorf("unable to resolve function returntype: %s", fn.Name) + return false + } + strct.Package.boundStructs.Add(strct.Name) + case *ast.SelectorExpr: + ident, ok := fn.X.(*ast.Ident) + if !ok { + return true + } + packageName := ident.Name + functionName := fn.Sel.Name + println("Found bound function:", packageName+"."+functionName) + + // Get package for package name + externalPackageName := pkg.getImportByName(packageName, fileAst) + externalPackage := p.getPackageByID(externalPackageName.ID) + + strct, err := p.getFunctionReturnType(externalPackage, functionName) + if err != nil { + parseError = err + return false + } + if strct == nil { + // Unable to resolve function + return true + } + externalPackage.boundStructs.Add(strct.Name) + } + + // Binding struct pointer literals + case *ast.UnaryExpr: + + if boundItem.Op.String() != "&" { + return true + } + + cl, ok := boundItem.X.(*ast.CompositeLit) + if !ok { + return true + } + + switch boundStructExp := cl.Type.(type) { + + // app.Bind( &myStruct{} ) + case *ast.Ident: + pkg.boundStructs.Add(boundStructExp.Name) + + // app.Bind( &mypackage.myStruct{} ) + case *ast.SelectorExpr: + var structName = "" + var packageName = "" + switch x := boundStructExp.X.(type) { + case *ast.Ident: + packageName = x.Name + default: + // TODO: Save these warnings + // println("Identifier in binding not supported:") + return true + } + structName = boundStructExp.Sel.Name + referencedPackage := pkg.getImportByName(packageName, fileAst) + packageWrapper := p.getPackageByID(referencedPackage.ID) + packageWrapper.boundStructs.Add(structName) + } + + default: + // TODO: Save these warnings + // println("Unsupported bind expression:") + // spew.Dump(boundItem) + } + + return true + }) + + if parseError != nil { + return parseError + } + } + + return nil +} diff --git a/v2/pkg/parser/generate.go b/v2/pkg/parser/generate.go new file mode 100644 index 000000000..b45a524c5 --- /dev/null +++ b/v2/pkg/parser/generate.go @@ -0,0 +1,251 @@ +package parser + +import ( + "bytes" + _ "embed" + "io/ioutil" + "os" + "path/filepath" + "text/template" + + "github.com/pkg/errors" + "github.com/wailsapp/wails/v2/internal/fs" +) + +//go:embed index.template +var indexTemplate string + +//go:embed index.d.template +var indexDTemplate string + +//go:embed package.template +var packageTemplate string + +//go:embed package.d.template +var packageDTemplate string + +//go:embed globals.d.template +var globalsDTemplate string + +//go:embed package.json +var packageJSON string + +// GenerateWailsFrontendPackage will generate a Javascript/Typescript +// package in `/frontend/wails` that defines which methods +// and structs are bound to your frontend +func GenerateWailsFrontendPackage() (*ParserReport, error) { + + dir, err := os.Getwd() + if err != nil { + return nil, err + } + + p := NewParser() + + err = p.ParseProject(dir) + if err != nil { + return nil, err + } + + err = p.generateModule() + + return p.parserReport(), err +} + +func (p *Parser) generateModule() error { + + moduleDir, err := createBackendJSDirectory() + if err != nil { + return err + } + + packagesToGenerate := p.packagesToGenerate() + + for _, pkg := range packagesToGenerate { + + err := generatePackage(pkg, moduleDir) + if err != nil { + return err + } + } + + // Copy the standard files + tgtFile := filepath.Join(moduleDir, "package.json") + err = fs.CopyFile(packageJSON, tgtFile) + if err != nil { + return err + } + + // Generate the globals.d.ts file + err = generateGlobalsTS(moduleDir, packagesToGenerate) + if err != nil { + return err + } + + // Generate the index.js file + err = generateIndexJS(moduleDir, packagesToGenerate) + if err != nil { + return err + } + // Generate the index.d.ts file + err = generateIndexTS(moduleDir, packagesToGenerate) + if err != nil { + return err + } + + return nil +} + +func createBackendJSDirectory() (string, error) { + + // Calculate the package directory + // Note this is *always* called from the project directory + // so using paths relative to CWD is fine + dir, err := fs.RelativeToCwd("./frontend/backend") + if err != nil { + return "", errors.Wrap(err, "Error creating backend module directory") + } + + // Remove directory if it exists - REGENERATION! + err = os.RemoveAll(dir) + if err != nil { + return "", errors.Wrap(err, "Error removing module directory") + } + + // Make the directory + err = fs.Mkdir(dir) + + return dir, err +} + +func generatePackage(pkg *Package, moduledir string) error { + + // Load typescript template + typescriptTemplateData := fs.MustLoadString(packageDTemplate) + typescriptTemplate, err := template.New("typescript").Parse(typescriptTemplateData) + if err != nil { + return errors.Wrap(err, "Error creating template") + } + + // Execute javascript template + var buffer bytes.Buffer + err = typescriptTemplate.Execute(&buffer, pkg) + if err != nil { + return errors.Wrap(err, "Error generating code") + } + + // Save typescript file + err = ioutil.WriteFile(filepath.Join(moduledir, "_"+pkg.Name+".d.ts"), buffer.Bytes(), 0755) + if err != nil { + return errors.Wrap(err, "Error writing backend package file") + } + + // Load javascript template + javascriptTemplateData := fs.MustLoadString(packageTemplate) + javascriptTemplate, err := template.New("javascript").Parse(javascriptTemplateData) + if err != nil { + return errors.Wrap(err, "Error creating template") + } + + // Reset the buffer + buffer.Reset() + + err = javascriptTemplate.Execute(&buffer, pkg) + if err != nil { + return errors.Wrap(err, "Error generating code") + } + + // Save javascript file + err = ioutil.WriteFile(filepath.Join(moduledir, "_"+pkg.Name+".js"), buffer.Bytes(), 0755) + if err != nil { + return errors.Wrap(err, "Error writing backend package file") + } + + return nil +} + +func generateIndexJS(dir string, packages []*Package) error { + + // Load template + templateData := fs.MustLoadString(indexTemplate) + packagesTemplate, err := template.New("index").Parse(templateData) + if err != nil { + return errors.Wrap(err, "Error creating template") + } + + // Execute template + var buffer bytes.Buffer + err = packagesTemplate.Execute(&buffer, packages) + if err != nil { + return errors.Wrap(err, "Error generating code") + } + + // Calculate target filename + indexJS := filepath.Join(dir, "index.js") + + err = ioutil.WriteFile(indexJS, buffer.Bytes(), 0755) + if err != nil { + return errors.Wrap(err, "Error writing backend package index.js file") + } + + return nil +} +func generateIndexTS(dir string, packages []*Package) error { + + // Load template + templateData := fs.MustLoadString(indexDTemplate) + indexTSTemplate, err := template.New("index.d").Parse(templateData) + if err != nil { + return errors.Wrap(err, "Error creating template") + } + + // Execute template + var buffer bytes.Buffer + err = indexTSTemplate.Execute(&buffer, packages) + if err != nil { + return errors.Wrap(err, "Error generating code") + } + + // Calculate target filename + indexJS := filepath.Join(dir, "index.d.ts") + + err = ioutil.WriteFile(indexJS, buffer.Bytes(), 0755) + if err != nil { + return errors.Wrap(err, "Error writing backend package index.d.ts file") + } + + return nil +} + +func generateGlobalsTS(dir string, packages []*Package) error { + + // Load template + templateData := fs.MustLoadString(globalsDTemplate) + packagesTemplate, err := template.New("globals").Parse(templateData) + if err != nil { + return errors.Wrap(err, "Error creating template") + } + + // Execute template + var buffer bytes.Buffer + err = packagesTemplate.Execute(&buffer, packages) + if err != nil { + return errors.Wrap(err, "Error generating code") + } + + // Calculate target filename + indexJS := filepath.Join(dir, "globals.d.ts") + + err = ioutil.WriteFile(indexJS, buffer.Bytes(), 0755) + if err != nil { + return errors.Wrap(err, "Error writing backend package globals.d.ts file") + } + + return nil +} + +func (p *Parser) parserReport() *ParserReport { + return &ParserReport{ + Packages: p.packagesToGenerate(), + } +} diff --git a/v2/pkg/parser/getFunctionReturnType.go b/v2/pkg/parser/getFunctionReturnType.go new file mode 100644 index 000000000..f5f2c6cd9 --- /dev/null +++ b/v2/pkg/parser/getFunctionReturnType.go @@ -0,0 +1,69 @@ +package parser + +import ( + "fmt" + "go/ast" +) + +func (p *Parser) getFunctionReturnType(pkg *Package, functionName string) (*Struct, error) { + + var result *Struct + + // Iterate through the files in the package looking for the bound structs + for _, fileAst := range pkg.Gopackage.Syntax { + + var parseError error + + ast.Inspect(fileAst, func(n ast.Node) bool { + // Parse Call expressions looking for bind calls + funcDecl, ok := n.(*ast.FuncDecl) + if !ok { + return true + } + + if funcDecl.Name.Name == functionName { + result, parseError = p.parseFunctionReturnType(fileAst, funcDecl, pkg) + return false + } + + return true + }) + + if parseError != nil { + return nil, parseError + } + + if result != nil { + return result, nil + } + } + + return result, nil +} + +func (p *Parser) parseFunctionReturnType(file *ast.File, funcDecl *ast.FuncDecl, pkg *Package) (*Struct, error) { + + var result *Struct + + if funcDecl.Type.Results == nil { + return nil, fmt.Errorf("bound function %s has no return values", funcDecl.Name.Name) + } + + // We expect only 1 return value for a function return + if len(funcDecl.Type.Results.List) > 1 { + return nil, fmt.Errorf("bound function %s has more than 1 return value", funcDecl.Name.Name) + } + + parsedFields, err := p.parseField(file, funcDecl.Type.Results.List[0], pkg) + if err != nil { + return nil, err + } + + if len(parsedFields) > 1 { + return nil, fmt.Errorf("bound function %s has more than 1 return value", funcDecl.Name.Name) + } + + result = parsedFields[0].Struct + + return result, nil +} diff --git a/v2/pkg/parser/globals.d.template b/v2/pkg/parser/globals.d.template new file mode 100644 index 000000000..acf85a7ae --- /dev/null +++ b/v2/pkg/parser/globals.d.template @@ -0,0 +1,27 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +interface Window { + + go: { + + {{- range . }}{{$packageName:=.Name}} + {{- if .HasBoundStructs }} + {{ $packageName }}: { + {{- range .Structs }} + {{- if .IsBound }} + {{if .Comments }}{{range .Comments}}// {{ . }}{{end}}{{end}} + {{.Name}}: { + {{range .Methods}} + {{if .Comments }}{{range .Comments}}// {{ . }}{{end}}{{end}} + {{.Name}}: ({{.InputsAsTSText $packageName}}) => Promise<{{.OutputsAsTSText $packageName}}>, + {{end}} + } + {{- end}} + {{- end}} + } + {{- end}} + {{- end}} + } +} \ No newline at end of file diff --git a/v2/pkg/parser/index.d.template b/v2/pkg/parser/index.d.template new file mode 100644 index 000000000..f48417d09 --- /dev/null +++ b/v2/pkg/parser/index.d.template @@ -0,0 +1,7 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +{{- range .}} +export const {{.Name}}: typeof import("./_{{.Name}}"); +{{- end}} diff --git a/v2/pkg/parser/index.template b/v2/pkg/parser/index.template new file mode 100644 index 000000000..f1801e04e --- /dev/null +++ b/v2/pkg/parser/index.template @@ -0,0 +1,13 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +{{- range .}} +const {{.Name}} = require('./_{{.Name}}'); +{{- end}} + +module.exports = { + {{- range .}} + {{.Name}}: {{.Name}}, + {{- end}} +} \ No newline at end of file diff --git a/v2/pkg/parser/method.go b/v2/pkg/parser/method.go new file mode 100644 index 000000000..3ba3b10c1 --- /dev/null +++ b/v2/pkg/parser/method.go @@ -0,0 +1,174 @@ +package parser + +import ( + "fmt" + "go/ast" + "strings" +) + +// Method defines a struct method +type Method struct { + Name string + Comments []string + Inputs []*Field + Returns []*Field +} + +func (p *Parser) parseStructMethods(boundStruct *Struct) error { + + for _, fileAst := range boundStruct.Package.Gopackage.Syntax { + + // Track errors + var parseError error + + ast.Inspect(fileAst, func(n ast.Node) bool { + + if funcDecl, ok := n.(*ast.FuncDecl); ok { + + if funcDecl.Recv == nil { + return true + } + + // This is a struct method + for _, field := range funcDecl.Recv.List { + switch f := field.Type.(type) { + case *ast.StarExpr: + // This is a struct pointer method + ident, ok := f.X.(*ast.Ident) // _ ? + if !ok { + continue + } + + // Check this method is for this struct + if ident.Name != boundStruct.Name { + continue + } + + // If this method is not Public, ignore + if string(funcDecl.Name.Name[0]) != strings.ToUpper((string(funcDecl.Name.Name[0]))) { + continue + } + + // Create our struct + structMethod := &Method{ + Name: funcDecl.Name.Name, + Comments: parseComments(funcDecl.Doc), + } + + // Save the input parameters + if funcDecl.Type.Params != nil { + for _, inputField := range funcDecl.Type.Params.List { + fields, err := p.parseField(fileAst, inputField, boundStruct.Package) + if err != nil { + parseError = err + return false + } + + // If this field was a struct, flag that it is used as data + if len(fields) > 0 { + if fields[0].Struct != nil { + fields[0].Struct.IsUsedAsData = true + } + } + + structMethod.Inputs = append(structMethod.Inputs, fields...) + } + } + + // Save the output parameters + if funcDecl.Type.Results != nil { + for _, outputField := range funcDecl.Type.Results.List { + fields, err := p.parseField(fileAst, outputField, boundStruct.Package) + if err != nil { + parseError = err + return false + } + + // If this field was a struct, flag that it is used as data + if len(fields) > 0 { + if fields[0].Struct != nil { + fields[0].Struct.IsUsedAsData = true + } + } + + structMethod.Returns = append(structMethod.Returns, fields...) + } + } + + // Append this method to the parsed struct + boundStruct.Methods = append(boundStruct.Methods, structMethod) + + default: + // Unsupported + continue + } + } + } + return true + }) + + // If we got an error, return it + if parseError != nil { + return parseError + } + } + + return nil +} + +// InputsAsTSText generates a string with the method inputs +// formatted in a way acceptable to Typescript +func (m *Method) InputsAsTSText(pkgName string) string { + var inputs []string + + for _, input := range m.Inputs { + inputText := fmt.Sprintf("%s: %s", input.Name, goTypeToTS(input, pkgName)) + inputs = append(inputs, inputText) + } + + return strings.Join(inputs, ", ") +} + +// OutputsAsTSText generates a string with the method inputs +// formatted in a way acceptable to Javascript +func (m *Method) OutputsAsTSText(pkgName string) string { + + if len(m.Returns) == 0 { + return "void" + } + + var result []string + + for _, output := range m.Returns { + result = append(result, goTypeToTS(output, pkgName)) + } + return strings.Join(result, ", ") +} + +// OutputsAsTSDeclarationText generates a string with the method inputs +// formatted in a way acceptable to Javascript +func (m *Method) OutputsAsTSDeclarationText(pkgName string) string { + + if len(m.Returns) == 0 { + return "void" + } + + var result []string + + for _, output := range m.Returns { + result = append(result, goTypeToTSDeclaration(output, pkgName)) + } + return strings.Join(result, ", ") +} + +// InputsAsJSText generates a string with the method inputs +// formatted in a way acceptable to Javascript +func (m *Method) InputsAsJSText() string { + var inputs []string + + for _, input := range m.Inputs { + inputs = append(inputs, input.Name) + } + + return strings.Join(inputs, ", ") +} diff --git a/v2/pkg/parser/package.d copy.template b/v2/pkg/parser/package.d copy.template new file mode 100644 index 000000000..5206b9621 --- /dev/null +++ b/v2/pkg/parser/package.d copy.template @@ -0,0 +1,31 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +{{- if .DeclarationReferences }} +{{range .DeclarationReferences}} +/// {{end}}{{- end}} + +export namespace {{.Name}} { {{range .Structs}} + {{- if or .IsBound .IsUsedAsData}} + {{if .Comments }}{{range .Comments}}// {{ . }}{{end}}{{- end}} + interface {{.Name}} { {{ if .IsUsedAsData }} + {{- range .Fields}}{{if .Comments }} + {{range .Comments}}//{{ . }}{{end}}{{- end}} + {{.Name}}: {{.TypeAsTSType $.Name}}; {{- end}} {{ end }} + {{- if .IsBound }} + {{- range .Methods}} + /**{{if .Comments }} +{{range .Comments}} * {{ . }}{{end}} + *{{end}} + * @function {{.Name}} +{{range .Inputs}} * @param {{"{"}}{{.JSType}}{{"}"}} {{.Name}} +{{end}} * + * @returns {Promise<{{.OutputsAsTSText $.Name}}>} + */ + {{.Name}}({{.InputsAsTSText $.Name}}): Promise<{{.OutputsAsTSText $.Name}}>; + {{- end}}{{end}} + }{{- end}} + {{end}} + +} + diff --git a/v2/pkg/parser/package.d.template b/v2/pkg/parser/package.d.template new file mode 100644 index 000000000..6eccdb0fe --- /dev/null +++ b/v2/pkg/parser/package.d.template @@ -0,0 +1,42 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +{{- range .Structs}} +{{- if .IsBound}} +export namespace {{.Name}} { + {{- range .Methods}} + {{- if .Comments }} + {{range .Comments}} + // {{ . }}{{end}} + {{- end}} + function {{.Name}}({{.InputsAsTSText $.Name}}): Promise<{{.OutputsAsTSDeclarationText $.Name}}>; + {{- end}} +} +{{- end}} +{{- if .IsUsedAsData}} +{{if .Comments }} +/** +{{range .Comments}} *{{ . }}{{end}} + */ +export type {{.Name}} = { +{{- range .Fields}} + {{- if not .Ignored}} + {{- if .Comments }}{{range .Comments}} + //{{ . }}{{end}}{{- end}} + {{ .AsTSDeclaration $.Name}}; {{- end}} +{{- end}} +}; + +/** +{{if .Comments }}{{range .Comments}} *{{ . }}{{end}}{{end}} + * @typedef {object} {{.Name}} +{{- range .Fields}}{{- if not .JSONOptions.Ignored }} + * @property {{"{"}}{{.TypeForPropertyDoc}}{{"}"}} {{.NameForPropertyDoc}} {{- if .Comments}} - {{- range .Comments}}{{ . }}{{- end}}{{- end}}{{- end}} +{{- end}} + */ +export var {{.Name}}: any; + +{{- end}} +{{- end}} +{{- end}} diff --git a/v2/pkg/parser/package.go b/v2/pkg/parser/package.go new file mode 100644 index 000000000..e9357efd0 --- /dev/null +++ b/v2/pkg/parser/package.go @@ -0,0 +1,152 @@ +package parser + +import ( + "go/ast" + "strings" + + "github.com/leaanthony/slicer" + "golang.org/x/tools/go/packages" +) + +// Package is a wrapper around the go parsed package +type Package struct { + + // A unique Name for this package. + // This is calculated and may not be the same as the one + // defined in Go - but that's ok! + Name string + + // the package we are wrapping + Gopackage *packages.Package + + // a list of struct names that are bound in this package + boundStructs slicer.StringSlicer + + // Structs used in this package + parsedStructs map[string]*Struct + + // A list of external packages we reference from this package + externalReferences slicer.InterfaceSlicer +} + +func newPackage(pkg *packages.Package) *Package { + return &Package{ + Gopackage: pkg, + parsedStructs: make(map[string]*Struct), + } +} + +func (p *Package) getWailsImportName(file *ast.File) string { + // Scan the imports for the wails v2 import + for _, details := range file.Imports { + if details.Path.Value == `"github.com/wailsapp/wails/v2"` { + if details.Name != nil { + return details.Name.Name + } + + // Get the import name from the package + imp := p.getImportByPath("github.com/wailsapp/wails/v2") + if imp != nil { + return imp.Name + } + } + } + return "" +} + +func (p *Package) getImportByName(importName string, file *ast.File) *packages.Package { + + // Check if the file has aliased the import + for _, imp := range file.Imports { + if imp.Name != nil { + if imp.Name.Name == importName { + // Yes it has. Get the import by path + return p.getImportByPath(imp.Path.Value) + } + } + } + + // We need to find which package import has this name + for _, imp := range p.Gopackage.Imports { + if imp.Name == importName { + return imp + } + } + + // Looks like this package is outside the project... + return nil +} + +func (p *Package) getImportByPath(packagePath string) *packages.Package { + packagePath = strings.Trim(packagePath, "\"") + return p.Gopackage.Imports[packagePath] +} + +func (p *Package) getStruct(structName string) *Struct { + return p.parsedStructs[structName] +} + +func (p *Package) addStruct(strct *Struct) { + p.parsedStructs[strct.Name] = strct +} + +// HasBoundStructs returns true if any of its structs +// are bound +func (p *Package) HasBoundStructs() bool { + + for _, strct := range p.parsedStructs { + if strct.IsBound { + return true + } + } + + return false +} + +// HasDataStructs returns true if any of its structs +// are used as data +func (p *Package) HasDataStructs() bool { + for _, strct := range p.parsedStructs { + if strct.IsUsedAsData { + return true + } + } + + return false +} + +// ShouldGenerate returns true when this package should be generated +func (p *Package) ShouldGenerate() bool { + return p.HasBoundStructs() || p.HasDataStructs() +} + +// DeclarationReferences returns a list of external packages +// we reference from this package +func (p *Package) DeclarationReferences() []string { + + var referenceNames slicer.StringSlicer + + // Generics can't come soon enough! + p.externalReferences.Each(func(p interface{}) { + referenceNames.Add(p.(*Package).Name) + }) + + return referenceNames.AsSlice() +} + +// addExternalReference saves the given package as an external reference +func (p *Package) addExternalReference(pkg *Package) { + p.externalReferences.AddUnique(pkg) +} + +// Structs returns the structs that we want to generate +func (p *Package) Structs() []*Struct { + + var result []*Struct + + for _, elem := range p.parsedStructs { + result = append(result, elem) + } + + return result +} diff --git a/v2/pkg/parser/package.json b/v2/pkg/parser/package.json new file mode 100644 index 000000000..5d0ddb820 --- /dev/null +++ b/v2/pkg/parser/package.json @@ -0,0 +1,13 @@ +{ + "name": "go", + "version": "1.0.0", + "description": "Auto generated module wrapping your Wails backend", + "main": "index.js", + "types": "index.d.ts", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/v2/pkg/parser/package.template b/v2/pkg/parser/package.template new file mode 100644 index 000000000..2c7362df1 --- /dev/null +++ b/v2/pkg/parser/package.template @@ -0,0 +1,44 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +{{- if .DeclarationReferences }} +{{range .DeclarationReferences}} +const {{.}} = require('./_{{.}}');{{end}}{{- end}} + +{{- range $struct := .Structs }} +{{- if .IsUsedAsData }} + +/** +{{if .Comments }}{{range .Comments}} *{{ . }}{{end}}{{end}} + * @typedef {object} {{.Name}} +{{- range .Fields}}{{- if not .JSONOptions.Ignored }} + * @property {{"{"}}{{.TypeForPropertyDoc}}{{"}"}} {{.NameForPropertyDoc}} {{- if .Comments}} - {{- range .Comments}}{{ . }}{{- end}}{{- end}}{{- end}} +{{- end}} + */ +export var {{.Name}}; + +{{- end}} +{{- if .IsBound }} +{{- if .Methods }} + +{{if .Comments }}{{range .Comments}}// {{ . }}{{end}}{{end}} +export const {{.Name}} = { +{{range .Methods }} + /**{{if .Comments }} +{{range .Comments}} * {{ . }}{{end}} + *{{end}} + * @function {{.Name}} +{{range .Inputs}} * @param {{"{"}}{{.JSType}}{{"}"}} {{.Name}} +{{end}} * + * @returns {Promise<{{.OutputsAsTSText $.Name}}>} + */ + {{.Name}}: function({{.InputsAsJSText}}) { + return window.backend.{{$.Name}}.{{$struct.Name}}.{{.Name}}({{.InputsAsJSText}}); + }, +{{end}} +} + +{{- end}} +{{- end}} +{{- end}} diff --git a/v2/pkg/parser/parseBoundStructs.go b/v2/pkg/parser/parseBoundStructs.go new file mode 100644 index 000000000..c26839433 --- /dev/null +++ b/v2/pkg/parser/parseBoundStructs.go @@ -0,0 +1,75 @@ +package parser + +import "go/ast" + +func (p *Parser) parseBoundStructs(pkg *Package) error { + + // Loop over the bound structs + for _, structName := range pkg.boundStructs.AsSlice() { + strct, err := p.parseStruct(pkg, structName) + if err != nil { + return err + } + strct.IsBound = true + } + + return nil +} + +// ParseStruct will attempt to parse the given struct using +// the package it references +func (p *Parser) parseStruct(pkg *Package, structName string) (*Struct, error) { + + // Check the parser cache for this struct + result := pkg.getStruct(structName) + if result != nil { + return result, nil + } + + // Iterate through the whole package looking for the bound structs + for _, fileAst := range pkg.Gopackage.Syntax { + + // Track errors + var parseError error + + ast.Inspect(fileAst, func(n ast.Node) bool { + if genDecl, ok := n.(*ast.GenDecl); ok { + for _, spec := range genDecl.Specs { + if typeSpec, ok := spec.(*ast.TypeSpec); ok { + if structType, ok := typeSpec.Type.(*ast.StructType); ok { + structDefinitionName := typeSpec.Name.Name + if structDefinitionName == structName { + + // Create the new struct + result = &Struct{Name: structName, Package: pkg} + + // Save comments + result.Comments = parseComments(genDecl.Doc) + + parseError = p.parseStructMethods(result) + if parseError != nil { + return false + } + + // Parse the struct fields + parseError = p.parseStructFields(fileAst, structType, result) + + // Save this struct + pkg.addStruct(result) + + return false + } + } + } + } + } + return true + }) + + // If we got an error, return it + if parseError != nil { + return nil, parseError + } + } + return result, nil +} diff --git a/v2/pkg/parser/parseStructFields.go b/v2/pkg/parser/parseStructFields.go new file mode 100644 index 000000000..cdca538d1 --- /dev/null +++ b/v2/pkg/parser/parseStructFields.go @@ -0,0 +1,35 @@ +package parser + +import ( + "go/ast" + + "github.com/pkg/errors" +) + +func (p *Parser) parseStructFields(fileAst *ast.File, structType *ast.StructType, boundStruct *Struct) error { + + // Parse the fields + for _, field := range structType.Fields.List { + fields, err := p.parseField(fileAst, field, boundStruct.Package) + if err != nil { + return errors.Wrap(err, "error parsing struct "+boundStruct.Name) + } + + // If this field was a struct, flag that it is used as data + if len(fields) > 0 { + if fields[0].Struct != nil { + fields[0].Struct.IsUsedAsData = true + } + } + + // If this field name is lowercase, it won't be exported + for _, field := range fields { + if !startsWithLowerCaseLetter(field.Name) { + boundStruct.Fields = append(boundStruct.Fields, field) + } + } + + } + + return nil +} diff --git a/v2/pkg/parser/parser.go b/v2/pkg/parser/parser.go new file mode 100644 index 000000000..5b49b42da --- /dev/null +++ b/v2/pkg/parser/parser.go @@ -0,0 +1,122 @@ +// Package parser provides the ability to parse the data that is bound in Wails projects. +// Using this, it can also generate a Javascript module that represents the DTOs used, as +// well as providing wrappers for bound methods. +package parser + +import ( + "go/token" + + "github.com/pkg/errors" + "golang.org/x/tools/go/packages" +) + +// Parser is the Wails project parser +type Parser struct { + + // Placeholders for Go's parser + fileSet *token.FileSet + + // The packages we parse + // The map key is the package ID + packages map[string]*Package +} + +// NewParser creates a new Wails project parser +func NewParser() *Parser { + return &Parser{ + fileSet: token.NewFileSet(), + packages: make(map[string]*Package), + } +} + +// ParseProject will parse the Wails project in the given directory +func (p *Parser) ParseProject(dir string) error { + + var err error + + err = p.loadPackages(dir) + if err != nil { + return err + } + + // Find all the bound structs + for _, pkg := range p.packages { + err = p.findBoundStructs(pkg) + if err != nil { + return err + } + } + + // Parse the structs + for _, pkg := range p.packages { + err = p.parseBoundStructs(pkg) + if err != nil { + return err + } + } + + // Resolve package names + // We do this because some packages may have the same name + p.resolvePackageNames() + + return nil +} + +func (p *Parser) loadPackages(projectPath string) error { + mode := packages.NeedName | + packages.NeedFiles | + packages.NeedSyntax | + packages.NeedTypes | + packages.NeedImports | + packages.NeedTypesInfo | + packages.NeedModule + + cfg := &packages.Config{Fset: p.fileSet, Mode: mode, Dir: projectPath} + pkgs, err := packages.Load(cfg, "./...") + if err != nil { + return errors.Wrap(err, "Problem loading packages") + } + // Check for errors + var parseError error + for _, pkg := range pkgs { + for _, err := range pkg.Errors { + if parseError == nil { + parseError = errors.New(err.Error()) + } else { + parseError = errors.Wrap(parseError, err.Error()) + } + } + } + + if parseError != nil { + return parseError + } + + // Create a map of packages + for _, pkg := range pkgs { + p.packages[pkg.ID] = newPackage(pkg) + } + + return nil +} + +func (p *Parser) getPackageByID(id string) *Package { + return p.packages[id] +} + +func (p *Parser) packagesToGenerate() []*Package { + + var result []*Package + + for _, pkg := range p.packages { + if pkg.ShouldGenerate() { + result = append(result, pkg) + } + } + + return result +} + +type ParserReport struct { + Packages []*Package +} diff --git a/v2/pkg/parser/resolvePackageReferences.go b/v2/pkg/parser/resolvePackageReferences.go new file mode 100644 index 000000000..081b3f8cb --- /dev/null +++ b/v2/pkg/parser/resolvePackageReferences.go @@ -0,0 +1,35 @@ +package parser + +import ( + "fmt" + + "github.com/leaanthony/slicer" +) + +// resolvePackageNames will deterine the names for the packages, allowing +// us to create a flat structure for the imports in the frontend module +func (p *Parser) resolvePackageNames() { + + // A cache for the names + var packageNameCache slicer.StringSlicer + + // Process each package + for _, pkg := range p.packages { + pkgName := pkg.Gopackage.Name + + // Check for collision + if packageNameCache.Contains(pkgName) { + // https://www.youtube.com/watch?v=otNNGROI0Cs !!!!! + + // We start at 2 because having both "pkg" and "pkg1" is 🙄 + count := 2 + for ok := true; ok; ok = packageNameCache.Contains(pkgName) { + pkgName = fmt.Sprintf("%s%d", pkg.Gopackage.Name, count) + } + } + + // Save the name! + packageNameCache.Add(pkgName) + pkg.Name = pkgName + } +} diff --git a/v2/pkg/parser/struct.go b/v2/pkg/parser/struct.go new file mode 100644 index 000000000..6108309bd --- /dev/null +++ b/v2/pkg/parser/struct.go @@ -0,0 +1,68 @@ +package parser + +import ( + "fmt" + "go/ast" + + "github.com/pkg/errors" +) + +// Struct represents a struct that is used by the frontend +// in a Wails project +type Struct struct { + + // The name of the struct + Name string + + // The package this was declared in + Package *Package + + // Comments for the struct + Comments []string + + // The fields used in this struct + Fields []*Field + + // The methods available to the front end + Methods []*Method + + // Indicates if this struct is bound to the app + IsBound bool + + // Indicates if this struct is used as data + IsUsedAsData bool +} + +func parseStructNameFromStarExpr(starExpr *ast.StarExpr) (string, string, error) { + pkg := "" + name := "" + // Determine the FQN + switch x := starExpr.X.(type) { + case *ast.SelectorExpr: + switch i := x.X.(type) { + case *ast.Ident: + pkg = i.Name + default: + // TODO: Store warnings? + return "", "", errors.WithStack(fmt.Errorf("unknown type in selector for *ast.SelectorExpr: %+v", i)) + } + + name = x.Sel.Name + + // TODO: IS this used? + case *ast.StarExpr: + switch s := x.X.(type) { + case *ast.Ident: + name = s.Name + default: + // TODO: Store warnings? + return "", "", errors.WithStack(fmt.Errorf("unknown type in selector for *ast.StarExpr: %+v", s)) + } + case *ast.Ident: + name = x.Name + default: + // TODO: Store warnings? + return "", "", errors.WithStack(fmt.Errorf("unknown type in selector for *ast.StarExpr: %+v", starExpr)) + } + return pkg, name, nil +} diff --git a/v2/pkg/parser/testproject/basic.go b/v2/pkg/parser/testproject/basic.go new file mode 100644 index 000000000..cce57e18f --- /dev/null +++ b/v2/pkg/parser/testproject/basic.go @@ -0,0 +1,66 @@ +package main + +import ( + "fmt" + + "testproject/mypackage" + + "github.com/wailsapp/wails/v2" +) + +// Basic application struct +type Basic struct { + runtime *wails.Runtime +} + +// // Another application struct +// type Another struct { +// runtime *wails.Runtime +// } + +// func (a *Another) Doit() { + +// } + +// // newBasicPointer creates a new Basic application struct +// func newBasicPointer() *Basic { +// return &Basic{} +// } + +// // newBasic creates a new Basic application struct +// func newBasic() Basic { +// return Basic{} +// } + +// WailsInit is called at application startup +func (b *Basic) WailsInit(runtime *wails.Runtime) error { + // Perform your setup here + b.runtime = runtime + runtime.Window.SetTitle("jsbundle") + return nil +} + +// WailsShutdown is called at application termination +func (b *Basic) WailsShutdown() { + // Perform your teardown here +} + +// NewPerson creates a new person +func (b *Basic) NewPerson(name string, age int) *mypackage.Person { + return &mypackage.Person{Name: name, Age: age} +} + +// Greet returns a greeting for the given name +func (b *Basic) Greet(name string) string { + return fmt.Sprintf("Hello %s!", name) +} + +// MultipleGreets returns greetings for the given name +func (b *Basic) MultipleGreets(_ string) []string { + return []string{"hi", "hello", "croeso!"} +} + +// RemovePerson Removes the given person +func (b *Basic) RemovePerson(_ *mypackage.Person) { + // dummy +} diff --git a/v2/pkg/parser/testproject/go.mod b/v2/pkg/parser/testproject/go.mod new file mode 100644 index 000000000..21f9e0d7e --- /dev/null +++ b/v2/pkg/parser/testproject/go.mod @@ -0,0 +1,9 @@ +module testproject + +go 1.13 + +require ( + github.com/wailsapp/wails/v2 v2.0.0-alpha +) + +replace github.com/wailsapp/wails/v2 v2.0.0-alpha => /home/lea/Data/projects/wails/v2 diff --git a/v2/pkg/parser/testproject/go.sum b/v2/pkg/parser/testproject/go.sum new file mode 100644 index 000000000..dae10ccef --- /dev/null +++ b/v2/pkg/parser/testproject/go.sum @@ -0,0 +1,83 @@ +github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/leaanthony/clir v1.0.4/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0= +github.com/leaanthony/gosod v0.0.4/go.mod h1:nGMCb1PJfXwBDbOAike78jEYlpqge+xUKFf0iBKjKxU= +github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= +github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2/go.mod h1:0KeJpeMD6o+O4hW7qJOT7vyQPKrWmj26uf5wMc/IiIs= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/tdewolff/minify v2.3.6+incompatible/go.mod h1:9Ov578KJUmAWpS6NeZwRZyT56Uf6o3Mcz9CEsg8USYs= +github.com/tdewolff/minify/v2 v2.9.5/go.mod h1:jshtBj/uUJH6JX1fuxTLnnHOA1RVJhF5MM+leJzDKb4= +github.com/tdewolff/parse v2.3.4+incompatible/go.mod h1:8oBwCsVmUkgHO8M5iCzSIDtpzXOT0WXX9cWhz+bIzJQ= +github.com/tdewolff/parse/v2 v2.5.3/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho= +github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/xyproto/xpm v1.2.1/go.mod h1:cMnesLsD0PBXLgjDfTDEaKr8XyTFsnP1QycSqRw7BiY= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200902012652-d1954cc86c82/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= diff --git a/v2/pkg/parser/testproject/main.go b/v2/pkg/parser/testproject/main.go new file mode 100644 index 000000000..0968d9112 --- /dev/null +++ b/v2/pkg/parser/testproject/main.go @@ -0,0 +1,21 @@ +package main + +import ( + "testproject/mypackage" + + "github.com/wailsapp/wails/v2" +) + +func main() { + // Create application with options + app := wails.CreateApp("jsbundle", 1024, 768) + + /***** Struct Literal *****/ + + // Local struct pointer literal *WORKING* + app.Bind(&Basic{}) + + // External struct pointer literal + app.Bind(&mypackage.Manager{}) + +} diff --git a/v2/pkg/parser/testproject/mypackage/mypackage.go b/v2/pkg/parser/testproject/mypackage/mypackage.go new file mode 100644 index 000000000..5dcac83e3 --- /dev/null +++ b/v2/pkg/parser/testproject/mypackage/mypackage.go @@ -0,0 +1,36 @@ +// Package mypackage does all the things a mypackage can do +package mypackage + +type Address struct { + Number int + Street string + Town string + Postcode string +} + +// Person defines a Person in the application +type Person struct { + // Name is a name + Name string + Age int + Address *Address +} + +// Manager is the Mr Manager +type Manager struct { + Name string + TwoIC *Person +} + +// Hire me some peoples! +func (m *Manager) Hire(name, test string, bob int) *Person { + return &Person{Name: name} +} + +// func NewManagerPointer() *Manager { +// return &Manager{} +// } + +// func NewManager() Manager { +// return Manager{} +// } diff --git a/v2/pkg/runtime/clipboard.go b/v2/pkg/runtime/clipboard.go deleted file mode 100644 index fab9e9e54..000000000 --- a/v2/pkg/runtime/clipboard.go +++ /dev/null @@ -1,13 +0,0 @@ -package runtime - -import "context" - -func ClipboardGetText(ctx context.Context) (string, error) { - appFrontend := getFrontend(ctx) - return appFrontend.ClipboardGetText() -} - -func ClipboardSetText(ctx context.Context, text string) error { - appFrontend := getFrontend(ctx) - return appFrontend.ClipboardSetText(text) -} diff --git a/v2/pkg/runtime/dialog.go b/v2/pkg/runtime/dialog.go index 16ae659e1..c8b6333a8 100644 --- a/v2/pkg/runtime/dialog.go +++ b/v2/pkg/runtime/dialog.go @@ -2,10 +2,7 @@ package runtime import ( "context" - "fmt" - "github.com/wailsapp/wails/v2/internal/frontend" - "github.com/wailsapp/wails/v2/internal/fs" ) // FileFilter defines a filter for dialog boxes @@ -32,44 +29,24 @@ type MessageDialogOptions = frontend.MessageDialogOptions // OpenDirectoryDialog prompts the user to select a directory func OpenDirectoryDialog(ctx context.Context, dialogOptions OpenDialogOptions) (string, error) { appFrontend := getFrontend(ctx) - if dialogOptions.DefaultDirectory != "" { - if !fs.DirExists(dialogOptions.DefaultDirectory) { - return "", fmt.Errorf("default directory '%s' does not exist", dialogOptions.DefaultDirectory) - } - } return appFrontend.OpenDirectoryDialog(dialogOptions) } // OpenFileDialog prompts the user to select a file func OpenFileDialog(ctx context.Context, dialogOptions OpenDialogOptions) (string, error) { appFrontend := getFrontend(ctx) - if dialogOptions.DefaultDirectory != "" { - if !fs.DirExists(dialogOptions.DefaultDirectory) { - return "", fmt.Errorf("default directory '%s' does not exist", dialogOptions.DefaultDirectory) - } - } return appFrontend.OpenFileDialog(dialogOptions) } // OpenMultipleFilesDialog prompts the user to select a file func OpenMultipleFilesDialog(ctx context.Context, dialogOptions OpenDialogOptions) ([]string, error) { appFrontend := getFrontend(ctx) - if dialogOptions.DefaultDirectory != "" { - if !fs.DirExists(dialogOptions.DefaultDirectory) { - return nil, fmt.Errorf("default directory '%s' does not exist", dialogOptions.DefaultDirectory) - } - } return appFrontend.OpenMultipleFilesDialog(dialogOptions) } // SaveFileDialog prompts the user to select a file func SaveFileDialog(ctx context.Context, dialogOptions SaveDialogOptions) (string, error) { appFrontend := getFrontend(ctx) - if dialogOptions.DefaultDirectory != "" { - if !fs.DirExists(dialogOptions.DefaultDirectory) { - return "", fmt.Errorf("default directory '%s' does not exist", dialogOptions.DefaultDirectory) - } - } return appFrontend.SaveFileDialog(dialogOptions) } diff --git a/v2/pkg/runtime/draganddrop.go b/v2/pkg/runtime/draganddrop.go deleted file mode 100644 index 2db9c773c..000000000 --- a/v2/pkg/runtime/draganddrop.go +++ /dev/null @@ -1,37 +0,0 @@ -package runtime - -import ( - "context" - "fmt" -) - -// OnFileDrop returns a slice of file path strings when a drop is finished. -func OnFileDrop(ctx context.Context, callback func(x, y int, paths []string)) { - if callback == nil { - LogError(ctx, "OnFileDrop called with a nil callback") - return - } - EventsOn(ctx, "wails:file-drop", func(optionalData ...interface{}) { - if len(optionalData) != 3 { - callback(0, 0, nil) - } - x, ok := optionalData[0].(int) - if !ok { - LogError(ctx, fmt.Sprintf("invalid x coordinate in drag and drop: %v", optionalData[0])) - } - y, ok := optionalData[1].(int) - if !ok { - LogError(ctx, fmt.Sprintf("invalid y coordinate in drag and drop: %v", optionalData[1])) - } - paths, ok := optionalData[2].([]string) - if !ok { - LogError(ctx, fmt.Sprintf("invalid path data in drag and drop: %v", optionalData[2])) - } - callback(x, y, paths) - }) -} - -// OnFileDropOff removes the drag and drop listeners and handlers. -func OnFileDropOff(ctx context.Context) { - EventsOff(ctx, "wails:file-drop") -} diff --git a/v2/pkg/runtime/events.go b/v2/pkg/runtime/events.go index 84aff7d74..440c7bdf6 100644 --- a/v2/pkg/runtime/events.go +++ b/v2/pkg/runtime/events.go @@ -4,42 +4,29 @@ import ( "context" ) -// EventsOn registers a listener for the given event name. It returns a function to cancel the listener -func EventsOn(ctx context.Context, eventName string, callback func(optionalData ...interface{})) func() { +// EventsOn registers a listener for the given event name +func EventsOn(ctx context.Context, eventName string, callback func(optionalData ...interface{})) { events := getEvents(ctx) - return events.On(eventName, callback) + events.On(eventName, callback) } -// EventsOff unregisters a listener for the given event name, optionally multiple listeners can be unregistered via `additionalEventNames` -func EventsOff(ctx context.Context, eventName string, additionalEventNames ...string) { +// EventsOff unregisters a listener for the given event name +func EventsOff(ctx context.Context, eventName string) { events := getEvents(ctx) events.Off(eventName) - - if len(additionalEventNames) > 0 { - for _, eventName := range additionalEventNames { - events.Off(eventName) - } - } -} - -// EventsOff unregisters a listener for the given event name, optionally multiple listeners can be unregistered via `additionalEventNames` -func EventsOffAll(ctx context.Context) { - events := getEvents(ctx) - events.OffAll() } // EventsOnce registers a listener for the given event name. After the first callback, the -// listener is deleted. It returns a function to cancel the listener -func EventsOnce(ctx context.Context, eventName string, callback func(optionalData ...interface{})) func() { +// listener is deleted. +func EventsOnce(ctx context.Context, eventName string, callback func(optionalData ...interface{})) { events := getEvents(ctx) - return events.Once(eventName, callback) + events.Once(eventName, callback) } -// EventsOnMultiple registers a listener for the given event name, that may be called a maximum of 'counter' times. It returns a function -// to cancel the listener -func EventsOnMultiple(ctx context.Context, eventName string, callback func(optionalData ...interface{}), counter int) func() { +// EventsOnMultiple registers a listener for the given event name, that may be called a maximum of 'counter' times +func EventsOnMultiple(ctx context.Context, eventName string, callback func(optionalData ...interface{}), counter int) { events := getEvents(ctx) - return events.OnMultiple(eventName, callback, counter) + events.OnMultiple(eventName, callback, counter) } // EventsEmit pass through diff --git a/v2/pkg/runtime/log.go b/v2/pkg/runtime/log.go index 3c2756f06..5f46c61df 100644 --- a/v2/pkg/runtime/log.go +++ b/v2/pkg/runtime/log.go @@ -2,8 +2,6 @@ package runtime import ( "context" - "fmt" - "github.com/wailsapp/wails/v2/pkg/logger" ) @@ -49,55 +47,6 @@ func LogFatal(ctx context.Context, message string) { myLogger.Fatal(message) } -// LogPrintf prints a Print level message -func LogPrintf(ctx context.Context, format string, args ...interface{}) { - msg := fmt.Sprintf(format, args...) - myLogger := getLogger(ctx) - myLogger.Print(msg) -} - -// LogTracef prints a Trace level message -func LogTracef(ctx context.Context, format string, args ...interface{}) { - msg := fmt.Sprintf(format, args...) - myLogger := getLogger(ctx) - myLogger.Trace(msg) -} - -// LogDebugf prints a Debug level message -func LogDebugf(ctx context.Context, format string, args ...interface{}) { - msg := fmt.Sprintf(format, args...) - myLogger := getLogger(ctx) - myLogger.Debug(msg) -} - -// LogInfof prints a Info level message -func LogInfof(ctx context.Context, format string, args ...interface{}) { - msg := fmt.Sprintf(format, args...) - myLogger := getLogger(ctx) - myLogger.Info(msg) -} - -// LogWarningf prints a Warning level message -func LogWarningf(ctx context.Context, format string, args ...interface{}) { - msg := fmt.Sprintf(format, args...) - myLogger := getLogger(ctx) - myLogger.Warning(msg) -} - -// LogErrorf prints a Error level message -func LogErrorf(ctx context.Context, format string, args ...interface{}) { - msg := fmt.Sprintf(format, args...) - myLogger := getLogger(ctx) - myLogger.Error(msg) -} - -// LogFatalf prints a Fatal level message -func LogFatalf(ctx context.Context, format string, args ...interface{}) { - msg := fmt.Sprintf(format, args...) - myLogger := getLogger(ctx) - myLogger.Fatal(msg) -} - // LogSetLogLevel sets the log level func LogSetLogLevel(ctx context.Context, level logger.LogLevel) { myLogger := getLogger(ctx) diff --git a/v2/pkg/runtime/menu.go b/v2/pkg/runtime/menu.go index 09bd640c5..176c9bb1d 100644 --- a/v2/pkg/runtime/menu.go +++ b/v2/pkg/runtime/menu.go @@ -2,7 +2,6 @@ package runtime import ( "context" - "github.com/wailsapp/wails/v2/pkg/menu" ) diff --git a/v2/pkg/runtime/runtime.go b/v2/pkg/runtime/runtime.go index 6de5ea798..9dbdffb8e 100644 --- a/v2/pkg/runtime/runtime.go +++ b/v2/pkg/runtime/runtime.go @@ -2,21 +2,17 @@ package runtime import ( "context" - "log" - goruntime "runtime" - "github.com/wailsapp/wails/v2/internal/frontend" "github.com/wailsapp/wails/v2/internal/logger" + "log" + goruntime "runtime" ) -const contextError = `An invalid context was passed. This method requires the specific context given in the lifecycle hooks: -https://wails.io/docs/reference/runtime/intro` - func getFrontend(ctx context.Context) frontend.Frontend { if ctx == nil { pc, _, _, _ := goruntime.Caller(1) funcName := goruntime.FuncForPC(pc).Name() - log.Fatalf("cannot call '%s': %s", funcName, contextError) + log.Fatalf("cannot call '%s': context is nil", funcName) } result := ctx.Value("frontend") if result != nil { @@ -24,15 +20,14 @@ func getFrontend(ctx context.Context) frontend.Frontend { } pc, _, _, _ := goruntime.Caller(1) funcName := goruntime.FuncForPC(pc).Name() - log.Fatalf("cannot call '%s': %s", funcName, contextError) + log.Fatalf("cannot call '%s': Application not initialised", funcName) return nil } - func getLogger(ctx context.Context) *logger.Logger { if ctx == nil { pc, _, _, _ := goruntime.Caller(1) funcName := goruntime.FuncForPC(pc).Name() - log.Fatalf("cannot call '%s': %s", funcName, contextError) + log.Fatalf("cannot call '%s': context is nil", funcName) } result := ctx.Value("logger") if result != nil { @@ -40,7 +35,7 @@ func getLogger(ctx context.Context) *logger.Logger { } pc, _, _, _ := goruntime.Caller(1) funcName := goruntime.FuncForPC(pc).Name() - log.Fatalf("cannot call '%s': %s", funcName, contextError) + log.Fatalf("cannot call '%s': Application not initialised", funcName) return nil } @@ -48,7 +43,7 @@ func getEvents(ctx context.Context) frontend.Events { if ctx == nil { pc, _, _, _ := goruntime.Caller(1) funcName := goruntime.FuncForPC(pc).Name() - log.Fatalf("cannot call '%s': %s", funcName, contextError) + log.Fatalf("cannot call '%s': context is nil", funcName) } result := ctx.Value("events") if result != nil { @@ -56,52 +51,15 @@ func getEvents(ctx context.Context) frontend.Events { } pc, _, _, _ := goruntime.Caller(1) funcName := goruntime.FuncForPC(pc).Name() - log.Fatalf("cannot call '%s': %s", funcName, contextError) + log.Fatalf("cannot call '%s': Application not initialised", funcName) return nil } // Quit the application func Quit(ctx context.Context) { if ctx == nil { - log.Fatalf("Error calling 'runtime.Quit': %s", contextError) + log.Fatalf("cannot call Quit: context is nil") } appFrontend := getFrontend(ctx) appFrontend.Quit() } - -// Hide the application -func Hide(ctx context.Context) { - if ctx == nil { - log.Fatalf("Error calling 'runtime.Hide': %s", contextError) - } - appFrontend := getFrontend(ctx) - appFrontend.Hide() -} - -// Show the application if it is hidden -func Show(ctx context.Context) { - if ctx == nil { - log.Fatalf("Error calling 'runtime.Show': %s", contextError) - } - appFrontend := getFrontend(ctx) - appFrontend.Show() -} - -// EnvironmentInfo contains information about the environment -type EnvironmentInfo struct { - BuildType string `json:"buildType"` - Platform string `json:"platform"` - Arch string `json:"arch"` -} - -// Environment returns information about the environment -func Environment(ctx context.Context) EnvironmentInfo { - var result EnvironmentInfo - buildType := ctx.Value("buildtype") - if buildType != nil { - result.BuildType = buildType.(string) - } - result.Platform = goruntime.GOOS - result.Arch = goruntime.GOARCH - return result -} diff --git a/v2/pkg/runtime/screen.go b/v2/pkg/runtime/screen.go deleted file mode 100644 index c4d526692..000000000 --- a/v2/pkg/runtime/screen.go +++ /dev/null @@ -1,15 +0,0 @@ -package runtime - -import ( - "context" - - "github.com/wailsapp/wails/v2/internal/frontend" -) - -type Screen = frontend.Screen - -// ScreenGetAll returns all screens -func ScreenGetAll(ctx context.Context) ([]Screen, error) { - appFrontend := getFrontend(ctx) - return appFrontend.ScreenGetAll() -} diff --git a/v2/pkg/runtime/signal_linux.go b/v2/pkg/runtime/signal_linux.go deleted file mode 100644 index 6a7ed5db3..000000000 --- a/v2/pkg/runtime/signal_linux.go +++ /dev/null @@ -1,65 +0,0 @@ -//go:build linux - -package runtime - -/* -#include -#include -#include -#include - -static void fix_signal(int signum) -{ - struct sigaction st; - - if (sigaction(signum, NULL, &st) < 0) { - return; - } - st.sa_flags |= SA_ONSTACK; - sigaction(signum, &st, NULL); -} - -static void fix_all_signals() -{ -#if defined(SIGSEGV) - fix_signal(SIGSEGV); -#endif -#if defined(SIGBUS) - fix_signal(SIGBUS); -#endif -#if defined(SIGFPE) - fix_signal(SIGFPE); -#endif -#if defined(SIGABRT) - fix_signal(SIGABRT); -#endif -} -*/ -import "C" - -// ResetSignalHandlers resets signal handlers to allow panic recovery. -// -// On Linux, WebKit (used for the webview) may install signal handlers without -// the SA_ONSTACK flag, which prevents Go from properly recovering from panics -// caused by nil pointer dereferences or other memory access violations. -// -// Call this function immediately before code that might panic to ensure -// the signal handlers are properly configured for Go's panic recovery mechanism. -// -// Example usage: -// -// go func() { -// defer func() { -// if err := recover(); err != nil { -// log.Printf("Recovered from panic: %v", err) -// } -// }() -// runtime.ResetSignalHandlers() -// // Code that might panic... -// }() -// -// Note: This function only has an effect on Linux. On other platforms, -// it is a no-op. -func ResetSignalHandlers() { - C.fix_all_signals() -} diff --git a/v2/pkg/runtime/signal_other.go b/v2/pkg/runtime/signal_other.go deleted file mode 100644 index 3171a700c..000000000 --- a/v2/pkg/runtime/signal_other.go +++ /dev/null @@ -1,18 +0,0 @@ -//go:build !linux - -package runtime - -// ResetSignalHandlers resets signal handlers to allow panic recovery. -// -// On Linux, WebKit (used for the webview) may install signal handlers without -// the SA_ONSTACK flag, which prevents Go from properly recovering from panics -// caused by nil pointer dereferences or other memory access violations. -// -// Call this function immediately before code that might panic to ensure -// the signal handlers are properly configured for Go's panic recovery mechanism. -// -// Note: This function only has an effect on Linux. On other platforms, -// it is a no-op. -func ResetSignalHandlers() { - // No-op on non-Linux platforms -} diff --git a/v2/pkg/runtime/window.go b/v2/pkg/runtime/window.go index 62345e2e4..e492134f1 100644 --- a/v2/pkg/runtime/window.go +++ b/v2/pkg/runtime/window.go @@ -18,10 +18,10 @@ func WindowFullscreen(ctx context.Context) { appFrontend.WindowFullscreen() } -// WindowUnfullscreen makes the window UnFullscreen -func WindowUnfullscreen(ctx context.Context) { +// WindowUnFullscreen makes the window UnFullscreen +func WindowUnFullscreen(ctx context.Context) { appFrontend := getFrontend(ctx) - appFrontend.WindowUnfullscreen() + appFrontend.WindowUnFullscreen() } // WindowCenter the window on the current screen @@ -36,27 +36,6 @@ func WindowReload(ctx context.Context) { appFrontend.WindowReload() } -// WindowReloadApp will reload the application -func WindowReloadApp(ctx context.Context) { - appFrontend := getFrontend(ctx) - appFrontend.WindowReloadApp() -} - -func WindowSetSystemDefaultTheme(ctx context.Context) { - appFrontend := getFrontend(ctx) - appFrontend.WindowSetSystemDefaultTheme() -} - -func WindowSetLightTheme(ctx context.Context) { - appFrontend := getFrontend(ctx) - appFrontend.WindowSetLightTheme() -} - -func WindowSetDarkTheme(ctx context.Context) { - appFrontend := getFrontend(ctx) - appFrontend.WindowSetDarkTheme() -} - // WindowShow shows the window if hidden func WindowShow(ctx context.Context) { appFrontend := getFrontend(ctx) @@ -92,21 +71,15 @@ func WindowSetMaxSize(ctx context.Context, width int, height int) { appFrontend.WindowSetMaxSize(width, height) } -// WindowSetAlwaysOnTop sets the window AlwaysOnTop or not on top -func WindowSetAlwaysOnTop(ctx context.Context, b bool) { - appFrontend := getFrontend(ctx) - appFrontend.WindowSetAlwaysOnTop(b) -} - // WindowSetPosition sets the position of the window func WindowSetPosition(ctx context.Context, x int, y int) { appFrontend := getFrontend(ctx) - appFrontend.WindowSetPosition(x, y) + appFrontend.WindowSetPos(x, y) } -func WindowGetPosition(ctx context.Context) (int, int) { +func WindowGetPos(ctx context.Context) (int, int) { appFrontend := getFrontend(ctx) - return appFrontend.WindowGetPosition() + return appFrontend.WindowGetPos() } // WindowMaximise the window @@ -115,12 +88,6 @@ func WindowMaximise(ctx context.Context) { appFrontend.WindowMaximise() } -// WindowToggleMaximise the window -func WindowToggleMaximise(ctx context.Context) { - appFrontend := getFrontend(ctx) - appFrontend.WindowToggleMaximise() -} - // WindowUnmaximise the window func WindowUnmaximise(ctx context.Context) { appFrontend := getFrontend(ctx) @@ -139,48 +106,7 @@ func WindowUnminimise(ctx context.Context) { appFrontend.WindowUnminimise() } -// WindowIsFullscreen get the window state is window Fullscreen -func WindowIsFullscreen(ctx context.Context) bool { +func WindowSetRGBA(ctx context.Context, col *options.RGBA) { appFrontend := getFrontend(ctx) - return appFrontend.WindowIsFullscreen() -} - -// WindowIsMaximised get the window state is window Maximised -func WindowIsMaximised(ctx context.Context) bool { - appFrontend := getFrontend(ctx) - return appFrontend.WindowIsMaximised() -} - -// WindowIsMinimised get the window state is window Minimised -func WindowIsMinimised(ctx context.Context) bool { - appFrontend := getFrontend(ctx) - return appFrontend.WindowIsMinimised() -} - -// WindowIsNormal get the window state is window Normal -func WindowIsNormal(ctx context.Context) bool { - appFrontend := getFrontend(ctx) - return appFrontend.WindowIsNormal() -} - -// WindowExecJS executes the given Js in the window -func WindowExecJS(ctx context.Context, js string) { - appFrontend := getFrontend(ctx) - appFrontend.ExecJS(js) -} - -func WindowSetBackgroundColour(ctx context.Context, R, G, B, A uint8) { - appFrontend := getFrontend(ctx) - col := &options.RGBA{ - R: R, - G: G, - B: B, - A: A, - } - appFrontend.WindowSetBackgroundColour(col) -} - -func WindowPrint(ctx context.Context) { - appFrontend := getFrontend(ctx) - appFrontend.WindowPrint() + appFrontend.WindowSetRGBA(col) } diff --git a/v2/pkg/str/str.go b/v2/pkg/str/str.go new file mode 100644 index 000000000..d27d5dad7 --- /dev/null +++ b/v2/pkg/str/str.go @@ -0,0 +1,10 @@ +package str + +import ( + "fmt" + "time" +) + +func UnixNow() string { + return fmt.Sprintf("%+v", time.Now().Unix()) +} diff --git a/v2/pkg/templates/base/.gitignore.tmpl b/v2/pkg/templates/base/.gitignore.tmpl deleted file mode 100644 index 129d52294..000000000 --- a/v2/pkg/templates/base/.gitignore.tmpl +++ /dev/null @@ -1,3 +0,0 @@ -build/bin -node_modules -frontend/dist diff --git a/v2/pkg/templates/base/README.md b/v2/pkg/templates/base/README.md deleted file mode 100644 index abd8b9cd2..000000000 --- a/v2/pkg/templates/base/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# README - -## About - -This is the official Wails $NAME template. - -You can configure the project by editing `wails.json`. More information about the project settings can be found -here: https://wails.io/docs/reference/project-config - -## Live Development - -To run in live development mode, run `wails dev` in the project directory. This will run a Vite development -server that will provide very fast hot reload of your frontend changes. If you want to develop in a browser -and have access to your Go methods, there is also a dev server that runs on http://localhost:34115. Connect -to this in your browser, and you can call your Go code from devtools. - -## Building - -To build a redistributable, production mode package, use `wails build`. diff --git a/v2/pkg/templates/base/app.tmpl.go b/v2/pkg/templates/base/app.tmpl.go deleted file mode 100644 index af53038a1..000000000 --- a/v2/pkg/templates/base/app.tmpl.go +++ /dev/null @@ -1,27 +0,0 @@ -package main - -import ( - "context" - "fmt" -) - -// App struct -type App struct { - ctx context.Context -} - -// NewApp creates a new App application struct -func NewApp() *App { - return &App{} -} - -// startup is called when the app starts. The context is saved -// so we can call the runtime methods -func (a *App) startup(ctx context.Context) { - a.ctx = ctx -} - -// Greet returns a greeting for the given name -func (a *App) Greet(name string) string { - return fmt.Sprintf("Hello %s, It's show time!", name) -} diff --git a/v2/pkg/templates/base/go.mod.tmpl b/v2/pkg/templates/base/go.mod.tmpl deleted file mode 100644 index 4b34d1668..000000000 --- a/v2/pkg/templates/base/go.mod.tmpl +++ /dev/null @@ -1,7 +0,0 @@ -module changeme - -go 1.23.0 - -require github.com/wailsapp/wails/v2 {{.WailsVersion}} - -// replace github.com/wailsapp/wails/v2 {{.WailsVersion}} => {{.WailsDirectory}} \ No newline at end of file diff --git a/v2/pkg/templates/base/main.go.tmpl b/v2/pkg/templates/base/main.go.tmpl deleted file mode 100644 index 571cf6b10..000000000 --- a/v2/pkg/templates/base/main.go.tmpl +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import ( -"embed" - -"github.com/wailsapp/wails/v2" -"github.com/wailsapp/wails/v2/pkg/options" -"github.com/wailsapp/wails/v2/pkg/options/assetserver" -) - -//go:embed frontend/dist -var assets embed.FS - -func main() { -// Create an instance of the app structure -app := NewApp() - -// Create application with options -err := wails.Run(&options.App{ -Title: "{{.ProjectName}}", -Width: 1024, -Height: 768, -AssetServer: &assetserver.Options{ - Assets: assets, -}, -BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, -OnStartup: app.startup, -Bind: []interface{}{ -app, -}, -}) - -if err != nil { -println("Error:", err.Error()) -} -} diff --git a/v2/pkg/templates/base/template.json b/v2/pkg/templates/base/template.json deleted file mode 100644 index 8ba8f2193..000000000 --- a/v2/pkg/templates/base/template.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "$NAME", - "shortname": "$SHORTNAME", - "author": "Lea Anthony", - "description": "$DESCRIPTION", - "helpurl": "https://wails.io" -} \ No newline at end of file diff --git a/v2/pkg/templates/base/wails.tmpl.json b/v2/pkg/templates/base/wails.tmpl.json deleted file mode 100644 index ce4ffe365..000000000 --- a/v2/pkg/templates/base/wails.tmpl.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "$scheme": "https://wails.io/schemas/config.v2.json", - "name": "{{.ProjectName}}", - "outputfilename": "{{.BinaryName}}", - "frontend:install": "npm install", - "frontend:build": "npm run build", - "frontend:dev:watcher": "npm run dev", - "frontend:dev:serverUrl": "auto", - "author": { - "name": "{{.AuthorName}}", - "email": "{{.AuthorEmail}}" - } -} diff --git a/v2/pkg/templates/generate/assets/common/.gitignore.tmpl b/v2/pkg/templates/generate/assets/common/.gitignore.tmpl deleted file mode 100644 index d44c22f8c..000000000 --- a/v2/pkg/templates/generate/assets/common/.gitignore.tmpl +++ /dev/null @@ -1,3 +0,0 @@ -build/bin -node_modules -frontend/dist \ No newline at end of file diff --git a/v2/pkg/templates/generate/assets/common/frontend/src/assets/fonts/OFL.txt b/v2/pkg/templates/generate/assets/common/frontend/src/assets/fonts/OFL.txt deleted file mode 100644 index 9cac04ce8..000000000 --- a/v2/pkg/templates/generate/assets/common/frontend/src/assets/fonts/OFL.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com), - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/v2/pkg/templates/generate/assets/common/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 b/v2/pkg/templates/generate/assets/common/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 deleted file mode 100644 index 2f9cc5964..000000000 Binary files a/v2/pkg/templates/generate/assets/common/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 and /dev/null differ diff --git a/v2/pkg/templates/generate/assets/common/frontend/src/assets/images/logo-universal.png b/v2/pkg/templates/generate/assets/common/frontend/src/assets/images/logo-universal.png deleted file mode 100644 index 01c74ee9b..000000000 Binary files a/v2/pkg/templates/generate/assets/common/frontend/src/assets/images/logo-universal.png and /dev/null differ diff --git a/v2/pkg/templates/generate/assets/common/frontend/src/style.css b/v2/pkg/templates/generate/assets/common/frontend/src/style.css deleted file mode 100644 index 3940d6c63..000000000 --- a/v2/pkg/templates/generate/assets/common/frontend/src/style.css +++ /dev/null @@ -1,26 +0,0 @@ -html { - background-color: rgba(27, 38, 54, 1); - text-align: center; - color: white; -} - -body { - margin: 0; - color: white; - font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", - "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", - sans-serif; -} - -@font-face { - font-family: "Nunito"; - font-style: normal; - font-weight: 400; - src: local(""), - url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2"); -} - -#app { - height: 100vh; - text-align: center; -} diff --git a/v2/pkg/templates/generate/assets/common/frontend/wailsjs/go/main/App.d.ts b/v2/pkg/templates/generate/assets/common/frontend/wailsjs/go/main/App.d.ts deleted file mode 100644 index 43173cfce..000000000 --- a/v2/pkg/templates/generate/assets/common/frontend/wailsjs/go/main/App.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Greet(arg1: string): Promise; diff --git a/v2/pkg/templates/generate/assets/common/frontend/wailsjs/go/main/App.js b/v2/pkg/templates/generate/assets/common/frontend/wailsjs/go/main/App.js deleted file mode 100644 index 0ee085c95..000000000 --- a/v2/pkg/templates/generate/assets/common/frontend/wailsjs/go/main/App.js +++ /dev/null @@ -1,7 +0,0 @@ -// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Greet(arg1) { - return window['go']['main']['App']['Greet'](arg1); -} diff --git a/v2/pkg/templates/generate/assets/common/frontend/wailsjs/runtime/package.json b/v2/pkg/templates/generate/assets/common/frontend/wailsjs/runtime/package.json deleted file mode 100644 index 1e7c8a5d7..000000000 --- a/v2/pkg/templates/generate/assets/common/frontend/wailsjs/runtime/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "@wailsapp/runtime", - "version": "2.0.0", - "description": "Wails Javascript runtime library", - "main": "runtime.js", - "types": "runtime.d.ts", - "scripts": { - }, - "repository": { - "type": "git", - "url": "git+https://github.com/wailsapp/wails.git" - }, - "keywords": [ - "Wails", - "Javascript", - "Go" - ], - "author": "Lea Anthony ", - "license": "MIT", - "bugs": { - "url": "https://github.com/wailsapp/wails/issues" - }, - "homepage": "https://github.com/wailsapp/wails#readme" -} diff --git a/v2/pkg/templates/generate/assets/common/frontend/wailsjs/runtime/runtime.d.ts b/v2/pkg/templates/generate/assets/common/frontend/wailsjs/runtime/runtime.d.ts deleted file mode 100644 index 336fb07aa..000000000 --- a/v2/pkg/templates/generate/assets/common/frontend/wailsjs/runtime/runtime.d.ts +++ /dev/null @@ -1,211 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export interface Position { - x: number; - y: number; -} - -export interface Size { - w: number; - h: number; -} - -export interface Screen { - isCurrent: boolean; - isPrimary: boolean; - width: number - height: number -} - -// Environment information such as platform, buildtype, ... -export interface EnvironmentInfo { - buildType: string; - platform: string; - arch: string; -} - -// [EventsEmit](https://wails.io/docs/reference/runtime/events#eventsemit) -// emits the given event. Optional data may be passed with the event. -// This will trigger any event listeners. -export function EventsEmit(eventName: string, ...data: any): void; - -// [EventsOn](https://wails.io/docs/reference/runtime/events#eventson) sets up a listener for the given event name. -export function EventsOn(eventName: string, callback: (...data: any) => void): void; - -// [EventsOnMultiple](https://wails.io/docs/reference/runtime/events#eventsonmultiple) -// sets up a listener for the given event name, but will only trigger a given number times. -export function EventsOnMultiple(eventName: string, callback: (...data: any) => void, maxCallbacks: number): void; - -// [EventsOnce](https://wails.io/docs/reference/runtime/events#eventsonce) -// sets up a listener for the given event name, but will only trigger once. -export function EventsOnce(eventName: string, callback: (...data: any) => void): void; - -// [EventsOff](https://wails.io/docs/reference/runtime/events#eventsff) -// unregisters the listener for the given event name. -export function EventsOff(eventName: string): void; - -// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) -// unregisters all event listeners. -export function EventsOffAll(): void; - -// [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) -// logs the given message as a raw message -export function LogPrint(message: string): void; - -// [LogTrace](https://wails.io/docs/reference/runtime/log#logtrace) -// logs the given message at the `trace` log level. -export function LogTrace(message: string): void; - -// [LogDebug](https://wails.io/docs/reference/runtime/log#logdebug) -// logs the given message at the `debug` log level. -export function LogDebug(message: string): void; - -// [LogError](https://wails.io/docs/reference/runtime/log#logerror) -// logs the given message at the `error` log level. -export function LogError(message: string): void; - -// [LogFatal](https://wails.io/docs/reference/runtime/log#logfatal) -// logs the given message at the `fatal` log level. -// The application will quit after calling this method. -export function LogFatal(message: string): void; - -// [LogInfo](https://wails.io/docs/reference/runtime/log#loginfo) -// logs the given message at the `info` log level. -export function LogInfo(message: string): void; - -// [LogWarning](https://wails.io/docs/reference/runtime/log#logwarning) -// logs the given message at the `warning` log level. -export function LogWarning(message: string): void; - -// [WindowReload](https://wails.io/docs/reference/runtime/window#windowreload) -// Forces a reload by the main application as well as connected browsers. -export function WindowReload(): void; - -// [WindowReloadApp](https://wails.io/docs/reference/runtime/window#windowreloadapp) -// Reloads the application frontend. -export function WindowReloadApp(): void; - -// [WindowSetAlwaysOnTop](https://wails.io/docs/reference/runtime/window#windowsetalwaysontop) -// Sets the window AlwaysOnTop or not on top. -export function WindowSetAlwaysOnTop(b: boolean): void; - -// [WindowSetSystemDefaultTheme](https://wails.io/docs/next/reference/runtime/window#windowsetsystemdefaulttheme) -// *Windows only* -// Sets window theme to system default (dark/light). -export function WindowSetSystemDefaultTheme(): void; - -// [WindowSetLightTheme](https://wails.io/docs/next/reference/runtime/window#windowsetlighttheme) -// *Windows only* -// Sets window to light theme. -export function WindowSetLightTheme(): void; - -// [WindowSetDarkTheme](https://wails.io/docs/next/reference/runtime/window#windowsetdarktheme) -// *Windows only* -// Sets window to dark theme. -export function WindowSetDarkTheme(): void; - -// [WindowCenter](https://wails.io/docs/reference/runtime/window#windowcenter) -// Centers the window on the monitor the window is currently on. -export function WindowCenter(): void; - -// [WindowSetTitle](https://wails.io/docs/reference/runtime/window#windowsettitle) -// Sets the text in the window title bar. -export function WindowSetTitle(title: string): void; - -// [WindowFullscreen](https://wails.io/docs/reference/runtime/window#windowfullscreen) -// Makes the window full screen. -export function WindowFullscreen(): void; - -// [WindowUnfullscreen](https://wails.io/docs/reference/runtime/window#windowunfullscreen) -// Restores the previous window dimensions and position prior to full screen. -export function WindowUnfullscreen(): void; - -// [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize) -// Sets the width and height of the window. -export function WindowSetSize(width: number, height: number): void; - -// [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize) -// Gets the width and height of the window. -export function WindowGetSize(): Promise; - -// [WindowSetMaxSize](https://wails.io/docs/reference/runtime/window#windowsetmaxsize) -// Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMaxSize(width: number, height: number): void; - -// [WindowSetMinSize](https://wails.io/docs/reference/runtime/window#windowsetminsize) -// Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMinSize(width: number, height: number): void; - -// [WindowSetPosition](https://wails.io/docs/reference/runtime/window#windowsetposition) -// Sets the window position relative to the monitor the window is currently on. -export function WindowSetPosition(x: number, y: number): void; - -// [WindowGetPosition](https://wails.io/docs/reference/runtime/window#windowgetposition) -// Gets the window position relative to the monitor the window is currently on. -export function WindowGetPosition(): Promise; - -// [WindowHide](https://wails.io/docs/reference/runtime/window#windowhide) -// Hides the window. -export function WindowHide(): void; - -// [WindowShow](https://wails.io/docs/reference/runtime/window#windowshow) -// Shows the window, if it is currently hidden. -export function WindowShow(): void; - -// [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise) -// Maximises the window to fill the screen. -export function WindowMaximise(): void; - -// [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise) -// Toggles between Maximised and UnMaximised. -export function WindowToggleMaximise(): void; - -// [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise) -// Restores the window to the dimensions and position prior to maximising. -export function WindowUnmaximise(): void; - -// [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise) -// Minimises the window. -export function WindowMinimise(): void; - -// [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise) -// Restores the window to the dimensions and position prior to minimising. -export function WindowUnminimise(): void; - -// [WindowSetBackgroundColour](https://wails.io/docs/reference/runtime/window#windowsetbackgroundcolour) -// Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels. -export function WindowSetBackgroundColour(R: number, G: number, B: number, A: number): void; - -// [ScreenGetAll](https://wails.io/docs/reference/runtime/window#screengetall) -// Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system. -export function ScreenGetAll(): Promise; - -// [BrowserOpenURL](https://wails.io/docs/reference/runtime/browser#browseropenurl) -// Opens the given URL in the system browser. -export function BrowserOpenURL(url: string): void; - -// [Environment](https://wails.io/docs/reference/runtime/intro#environment) -// Returns information about the environment -export function Environment(): Promise; - -// [Quit](https://wails.io/docs/reference/runtime/intro#quit) -// Quits the application. -export function Quit(): void; - -// [Hide](https://wails.io/docs/reference/runtime/intro#hide) -// Hides the application. -export function Hide(): void; - -// [Show](https://wails.io/docs/reference/runtime/intro#show) -// Shows the application. -export function Show(): void; diff --git a/v2/pkg/templates/generate/assets/common/frontend/wailsjs/runtime/runtime.js b/v2/pkg/templates/generate/assets/common/frontend/wailsjs/runtime/runtime.js deleted file mode 100644 index b5ae16d56..000000000 --- a/v2/pkg/templates/generate/assets/common/frontend/wailsjs/runtime/runtime.js +++ /dev/null @@ -1,182 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export function LogPrint(message) { - window.runtime.LogPrint(message); -} - -export function LogTrace(message) { - window.runtime.LogTrace(message); -} - -export function LogDebug(message) { - window.runtime.LogDebug(message); -} - -export function LogInfo(message) { - window.runtime.LogInfo(message); -} - -export function LogWarning(message) { - window.runtime.LogWarning(message); -} - -export function LogError(message) { - window.runtime.LogError(message); -} - -export function LogFatal(message) { - window.runtime.LogFatal(message); -} - -export function EventsOnMultiple(eventName, callback, maxCallbacks) { - window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks); -} - -export function EventsOn(eventName, callback) { - EventsOnMultiple(eventName, callback, -1); -} - -export function EventsOff(eventName) { - return window.runtime.EventsOff(eventName); -} - -export function EventsOffAll() { - return window.runtime.EventsOffAll(); -} - -export function EventsOnce(eventName, callback) { - EventsOnMultiple(eventName, callback, 1); -} - -export function EventsEmit(eventName) { - let args = [eventName].slice.call(arguments); - return window.runtime.EventsEmit.apply(null, args); -} - -export function WindowReload() { - window.runtime.WindowReload(); -} - -export function WindowReloadApp() { - window.runtime.WindowReloadApp(); -} - -export function WindowSetAlwaysOnTop(b) { - window.runtime.WindowSetAlwaysOnTop(b); -} - -export function WindowSetSystemDefaultTheme() { - window.runtime.WindowSetSystemDefaultTheme(); -} - -export function WindowSetLightTheme() { - window.runtime.WindowSetLightTheme(); -} - -export function WindowSetDarkTheme() { - window.runtime.WindowSetDarkTheme(); -} - -export function WindowCenter() { - window.runtime.WindowCenter(); -} - -export function WindowSetTitle(title) { - window.runtime.WindowSetTitle(title); -} - -export function WindowFullscreen() { - window.runtime.WindowFullscreen(); -} - -export function WindowUnfullscreen() { - window.runtime.WindowUnfullscreen(); -} - -export function WindowGetSize() { - return window.runtime.WindowGetSize(); -} - -export function WindowSetSize(width, height) { - window.runtime.WindowSetSize(width, height); -} - -export function WindowSetMaxSize(width, height) { - window.runtime.WindowSetMaxSize(width, height); -} - -export function WindowSetMinSize(width, height) { - window.runtime.WindowSetMinSize(width, height); -} - -export function WindowSetPosition(x, y) { - window.runtime.WindowSetPosition(x, y); -} - -export function WindowGetPosition() { - return window.runtime.WindowGetPosition(); -} - -export function WindowHide() { - window.runtime.WindowHide(); -} - -export function WindowShow() { - window.runtime.WindowShow(); -} - -export function WindowMaximise() { - window.runtime.WindowMaximise(); -} - -export function WindowToggleMaximise() { - window.runtime.WindowToggleMaximise(); -} - -export function WindowUnmaximise() { - window.runtime.WindowUnmaximise(); -} - -export function WindowMinimise() { - window.runtime.WindowMinimise(); -} - -export function WindowUnminimise() { - window.runtime.WindowUnminimise(); -} - -export function WindowSetBackgroundColour(R, G, B, A) { - window.runtime.WindowSetBackgroundColour(R, G, B, A); -} - -export function ScreenGetAll() { - return window.runtime.ScreenGetAll(); -} - -export function BrowserOpenURL(url) { - window.runtime.BrowserOpenURL(url); -} - -export function Environment() { - return window.runtime.Environment(); -} - -export function Quit() { - window.runtime.Quit(); -} - -export function Hide() { - window.runtime.Hide(); -} - -export function Show() { - window.runtime.Show(); -} diff --git a/v2/pkg/templates/generate/assets/lit-ts/frontend/index.tmpl.html b/v2/pkg/templates/generate/assets/lit-ts/frontend/index.tmpl.html deleted file mode 100644 index febcb76cb..000000000 --- a/v2/pkg/templates/generate/assets/lit-ts/frontend/index.tmpl.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - {{.ProjectName}} - - - - - - - diff --git a/v2/pkg/templates/generate/assets/lit-ts/frontend/src/my-element.ts b/v2/pkg/templates/generate/assets/lit-ts/frontend/src/my-element.ts deleted file mode 100644 index 27fd71e45..000000000 --- a/v2/pkg/templates/generate/assets/lit-ts/frontend/src/my-element.ts +++ /dev/null @@ -1,102 +0,0 @@ -import {css, html, LitElement} from 'lit' -import logo from './assets/images/logo-universal.png' -import {Greet} from "../wailsjs/go/main/App"; -import {customElement, property} from 'lit/decorators.js' - -/** - * An example element. - * - * @slot - This element has a slot - * @csspart button - The button - */ -@customElement('my-element') -export class MyElement extends LitElement { - static styles = css` - #logo { - display: block; - width: 50%; - height: 50%; - margin: auto; - padding: 10% 0 0; - background-position: center; - background-repeat: no-repeat; - background-size: 100% 100%; - background-origin: content-box; - } - - .result { - height: 20px; - line-height: 20px; - margin: 1.5rem auto; - } - - .input-box .btn { - width: 60px; - height: 30px; - line-height: 30px; - border-radius: 3px; - border: none; - margin: 0 0 0 20px; - padding: 0 8px; - cursor: pointer; - } - - .input-box .btn:hover { - background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%); - color: #333333; - } - - .input-box .input { - border: none; - border-radius: 3px; - outline: none; - height: 30px; - line-height: 30px; - padding: 0 10px; - background-color: rgba(240, 240, 240, 1); - -webkit-font-smoothing: antialiased; - } - - .input-box .input:hover { - border: none; - background-color: rgba(255, 255, 255, 1); - } - - .input-box .input:focus { - border: none; - background-color: rgba(255, 255, 255, 1); - } - - ` - - @property() - resultText = "Please enter your name below 👇" - - greet() { - let thisName = (this.shadowRoot?.getElementById('name') as HTMLInputElement)?.value; - if (thisName) { - Greet(thisName).then(result => { - this.resultText = result - }); - } - } - - render() { - return html` -
- -
${this.resultText}
-
- - -
-
- ` - } -} - -declare global { - interface HTMLElementTagNameMap { - 'my-element': MyElement - } -} \ No newline at end of file diff --git a/v2/pkg/templates/generate/assets/lit-ts/frontend/vite.config.ts b/v2/pkg/templates/generate/assets/lit-ts/frontend/vite.config.ts deleted file mode 100644 index bbb7f5889..000000000 --- a/v2/pkg/templates/generate/assets/lit-ts/frontend/vite.config.ts +++ /dev/null @@ -1,4 +0,0 @@ -import {defineConfig} from 'vite' - -// https://vitejs.dev/config/ -export default defineConfig({}) diff --git a/v2/pkg/templates/generate/assets/lit/frontend/index.tmpl.html b/v2/pkg/templates/generate/assets/lit/frontend/index.tmpl.html deleted file mode 100644 index fbe3eb240..000000000 --- a/v2/pkg/templates/generate/assets/lit/frontend/index.tmpl.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - {{.ProjectName}} - - - - - - - diff --git a/v2/pkg/templates/generate/assets/lit/frontend/src/assets/fonts/OFL.txt b/v2/pkg/templates/generate/assets/lit/frontend/src/assets/fonts/OFL.txt deleted file mode 100644 index 9cac04ce8..000000000 --- a/v2/pkg/templates/generate/assets/lit/frontend/src/assets/fonts/OFL.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com), - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/v2/pkg/templates/generate/assets/lit/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 b/v2/pkg/templates/generate/assets/lit/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 deleted file mode 100644 index 2f9cc5964..000000000 Binary files a/v2/pkg/templates/generate/assets/lit/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 and /dev/null differ diff --git a/v2/pkg/templates/generate/assets/lit/frontend/src/assets/images/logo-universal.png b/v2/pkg/templates/generate/assets/lit/frontend/src/assets/images/logo-universal.png deleted file mode 100644 index 01c74ee9b..000000000 Binary files a/v2/pkg/templates/generate/assets/lit/frontend/src/assets/images/logo-universal.png and /dev/null differ diff --git a/v2/pkg/templates/generate/assets/lit/frontend/src/my-element.js b/v2/pkg/templates/generate/assets/lit/frontend/src/my-element.js deleted file mode 100644 index ed65e2225..000000000 --- a/v2/pkg/templates/generate/assets/lit/frontend/src/my-element.js +++ /dev/null @@ -1,105 +0,0 @@ -import {css, html, LitElement} from 'lit' -import logo from './assets/images/logo-universal.png' -import {Greet} from "../wailsjs/go/main/App"; - -/** - * An example element. - * - * @slot - This element has a slot - * @csspart button - The button - */ -export class MyElement extends LitElement { - constructor() { - super() - this.resultText = "Please enter your name below 👇" - } - - static get styles() { - return css` - #logo { - display: block; - width: 50%; - height: 50%; - margin: auto; - padding: 10% 0 0; - background-position: center; - background-repeat: no-repeat; - background-size: 100% 100%; - background-origin: content-box; - } - - .result { - height: 20px; - line-height: 20px; - margin: 1.5rem auto; - } - - .input-box .btn { - width: 60px; - height: 30px; - line-height: 30px; - border-radius: 3px; - border: none; - margin: 0 0 0 20px; - padding: 0 8px; - cursor: pointer; - } - - .input-box .btn:hover { - background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%); - color: #333333; - } - - .input-box .input { - border: none; - border-radius: 3px; - outline: none; - height: 30px; - line-height: 30px; - padding: 0 10px; - background-color: rgba(240, 240, 240, 1); - -webkit-font-smoothing: antialiased; - } - - .input-box .input:hover { - border: none; - background-color: rgba(255, 255, 255, 1); - } - - .input-box .input:focus { - border: none; - background-color: rgba(255, 255, 255, 1); - } - - ` - } - - static get properties() { - return { - resultText: {type: String}, - } - } - - greet() { - let thisName = this.shadowRoot.getElementById('name').value - Greet(thisName).then(result => { - this.resultText = result - }); - } - - render() { - return html` -
- -
${this.resultText}
-
- - -
-
- ` - } - -} - -window.customElements.define('my-element', MyElement) diff --git a/v2/pkg/templates/generate/assets/lit/frontend/src/style.css b/v2/pkg/templates/generate/assets/lit/frontend/src/style.css deleted file mode 100644 index 3940d6c63..000000000 --- a/v2/pkg/templates/generate/assets/lit/frontend/src/style.css +++ /dev/null @@ -1,26 +0,0 @@ -html { - background-color: rgba(27, 38, 54, 1); - text-align: center; - color: white; -} - -body { - margin: 0; - color: white; - font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", - "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", - sans-serif; -} - -@font-face { - font-family: "Nunito"; - font-style: normal; - font-weight: 400; - src: local(""), - url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2"); -} - -#app { - height: 100vh; - text-align: center; -} diff --git a/v2/pkg/templates/generate/assets/lit/frontend/vite.config.js b/v2/pkg/templates/generate/assets/lit/frontend/vite.config.js deleted file mode 100644 index bbb7f5889..000000000 --- a/v2/pkg/templates/generate/assets/lit/frontend/vite.config.js +++ /dev/null @@ -1,4 +0,0 @@ -import {defineConfig} from 'vite' - -// https://vitejs.dev/config/ -export default defineConfig({}) diff --git a/v2/pkg/templates/generate/assets/preact-ts/frontend/index.tmpl.html b/v2/pkg/templates/generate/assets/preact-ts/frontend/index.tmpl.html deleted file mode 100644 index 0fb692c96..000000000 --- a/v2/pkg/templates/generate/assets/preact-ts/frontend/index.tmpl.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - {{.ProjectName}} - - -
- - - - diff --git a/v2/pkg/templates/generate/assets/preact-ts/frontend/src/app.css b/v2/pkg/templates/generate/assets/preact-ts/frontend/src/app.css deleted file mode 100644 index f949d9c18..000000000 --- a/v2/pkg/templates/generate/assets/preact-ts/frontend/src/app.css +++ /dev/null @@ -1,59 +0,0 @@ -#app { - height: 100vh; - text-align: center; -} - -#logo { - display: block; - width: 50%; - height: 50%; - margin: auto; - padding: 10% 0 0; - background-position: center; - background-repeat: no-repeat; - background-size: 100% 100%; - background-origin: content-box; -} - -.result { - height: 20px; - line-height: 20px; - margin: 1.5rem auto; -} - -.input-box .btn { - width: 60px; - height: 30px; - line-height: 30px; - border-radius: 3px; - border: none; - margin: 0 0 0 20px; - padding: 0 8px; - cursor: pointer; -} - -.input-box .btn:hover { - background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%); - color: #333333; -} - -.input-box .input { - border: none; - border-radius: 3px; - outline: none; - height: 30px; - line-height: 30px; - padding: 0 10px; - background-color: rgba(240, 240, 240, 1); - -webkit-font-smoothing: antialiased; -} - -.input-box .input:hover { - border: none; - background-color: rgba(255, 255, 255, 1); -} - -.input-box .input:focus { - border: none; - background-color: rgba(255, 255, 255, 1); -} \ No newline at end of file diff --git a/v2/pkg/templates/generate/assets/preact-ts/frontend/src/app.tsx b/v2/pkg/templates/generate/assets/preact-ts/frontend/src/app.tsx deleted file mode 100644 index bb50c5ec7..000000000 --- a/v2/pkg/templates/generate/assets/preact-ts/frontend/src/app.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import './app.css' -import logo from "./assets/images/logo-universal.png" -import {Greet} from "../wailsjs/go/main/App"; -import {useState} from "preact/hooks"; - -export function App(props: any) { - const [resultText, setResultText] = useState("Please enter your name below 👇"); - const [name, setName] = useState(''); - const updateName = (e: any) => setName(e.target.value); - const updateResultText = (result: string) => setResultText(result); - - function greet() { - Greet(name).then(updateResultText); - } - - return ( - <> -
- -
{resultText}
-
- - -
-
- - ) -} diff --git a/v2/pkg/templates/generate/assets/preact-ts/frontend/src/main.tsx b/v2/pkg/templates/generate/assets/preact-ts/frontend/src/main.tsx deleted file mode 100644 index 05b147282..000000000 --- a/v2/pkg/templates/generate/assets/preact-ts/frontend/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import {render} from 'preact'; -import {App} from './app'; -import './style.css'; - -render(, document.getElementById('app')!); diff --git a/v2/pkg/templates/generate/assets/preact/frontend/index.tmpl.html b/v2/pkg/templates/generate/assets/preact/frontend/index.tmpl.html deleted file mode 100644 index c8bfd4b76..000000000 --- a/v2/pkg/templates/generate/assets/preact/frontend/index.tmpl.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - {{.ProjectName}} - - -
- - - - diff --git a/v2/pkg/templates/generate/assets/preact/frontend/src/app.css b/v2/pkg/templates/generate/assets/preact/frontend/src/app.css deleted file mode 100644 index f949d9c18..000000000 --- a/v2/pkg/templates/generate/assets/preact/frontend/src/app.css +++ /dev/null @@ -1,59 +0,0 @@ -#app { - height: 100vh; - text-align: center; -} - -#logo { - display: block; - width: 50%; - height: 50%; - margin: auto; - padding: 10% 0 0; - background-position: center; - background-repeat: no-repeat; - background-size: 100% 100%; - background-origin: content-box; -} - -.result { - height: 20px; - line-height: 20px; - margin: 1.5rem auto; -} - -.input-box .btn { - width: 60px; - height: 30px; - line-height: 30px; - border-radius: 3px; - border: none; - margin: 0 0 0 20px; - padding: 0 8px; - cursor: pointer; -} - -.input-box .btn:hover { - background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%); - color: #333333; -} - -.input-box .input { - border: none; - border-radius: 3px; - outline: none; - height: 30px; - line-height: 30px; - padding: 0 10px; - background-color: rgba(240, 240, 240, 1); - -webkit-font-smoothing: antialiased; -} - -.input-box .input:hover { - border: none; - background-color: rgba(255, 255, 255, 1); -} - -.input-box .input:focus { - border: none; - background-color: rgba(255, 255, 255, 1); -} \ No newline at end of file diff --git a/v2/pkg/templates/generate/assets/preact/frontend/src/app.jsx b/v2/pkg/templates/generate/assets/preact/frontend/src/app.jsx deleted file mode 100644 index d0543d081..000000000 --- a/v2/pkg/templates/generate/assets/preact/frontend/src/app.jsx +++ /dev/null @@ -1,29 +0,0 @@ -import './app.css'; -import logo from "./assets/images/logo-universal.png"; -import {Greet} from "../wailsjs/go/main/App"; -import {useState} from "preact/hooks"; - -export function App(props) { - const [resultText, setResultText] = useState("Please enter your name below 👇"); - const [name, setName] = useState(''); - const updateName = (e) => setName(e.target.value); - const updateResultText = (result) => setResultText(result); - - function greet() { - Greet(name).then(updateResultText); - } - - return ( - <> -
- -
{resultText}
-
- - -
-
- - ) -} diff --git a/v2/pkg/templates/generate/assets/preact/frontend/src/assets/fonts/OFL.txt b/v2/pkg/templates/generate/assets/preact/frontend/src/assets/fonts/OFL.txt deleted file mode 100644 index 9cac04ce8..000000000 --- a/v2/pkg/templates/generate/assets/preact/frontend/src/assets/fonts/OFL.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com), - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/v2/pkg/templates/generate/assets/preact/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 b/v2/pkg/templates/generate/assets/preact/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 deleted file mode 100644 index 2f9cc5964..000000000 Binary files a/v2/pkg/templates/generate/assets/preact/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 and /dev/null differ diff --git a/v2/pkg/templates/generate/assets/preact/frontend/src/assets/images/logo-universal.png b/v2/pkg/templates/generate/assets/preact/frontend/src/assets/images/logo-universal.png deleted file mode 100644 index 01c74ee9b..000000000 Binary files a/v2/pkg/templates/generate/assets/preact/frontend/src/assets/images/logo-universal.png and /dev/null differ diff --git a/v2/pkg/templates/generate/assets/preact/frontend/src/main.jsx b/v2/pkg/templates/generate/assets/preact/frontend/src/main.jsx deleted file mode 100644 index 6c42a5949..000000000 --- a/v2/pkg/templates/generate/assets/preact/frontend/src/main.jsx +++ /dev/null @@ -1,5 +0,0 @@ -import {render} from 'preact'; -import {App} from './app'; -import './style.css'; - -render(, document.getElementById('app')); \ No newline at end of file diff --git a/v2/pkg/templates/generate/assets/preact/frontend/src/style.css b/v2/pkg/templates/generate/assets/preact/frontend/src/style.css deleted file mode 100644 index 3940d6c63..000000000 --- a/v2/pkg/templates/generate/assets/preact/frontend/src/style.css +++ /dev/null @@ -1,26 +0,0 @@ -html { - background-color: rgba(27, 38, 54, 1); - text-align: center; - color: white; -} - -body { - margin: 0; - color: white; - font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", - "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", - sans-serif; -} - -@font-face { - font-family: "Nunito"; - font-style: normal; - font-weight: 400; - src: local(""), - url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2"); -} - -#app { - height: 100vh; - text-align: center; -} diff --git a/v2/pkg/templates/generate/assets/react-ts/frontend/index.tmpl.html b/v2/pkg/templates/generate/assets/react-ts/frontend/index.tmpl.html deleted file mode 100644 index a2023cac7..000000000 --- a/v2/pkg/templates/generate/assets/react-ts/frontend/index.tmpl.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - {{.ProjectName}} - - -
- - - - diff --git a/v2/pkg/templates/generate/assets/react-ts/frontend/src/App.css b/v2/pkg/templates/generate/assets/react-ts/frontend/src/App.css deleted file mode 100644 index f949d9c18..000000000 --- a/v2/pkg/templates/generate/assets/react-ts/frontend/src/App.css +++ /dev/null @@ -1,59 +0,0 @@ -#app { - height: 100vh; - text-align: center; -} - -#logo { - display: block; - width: 50%; - height: 50%; - margin: auto; - padding: 10% 0 0; - background-position: center; - background-repeat: no-repeat; - background-size: 100% 100%; - background-origin: content-box; -} - -.result { - height: 20px; - line-height: 20px; - margin: 1.5rem auto; -} - -.input-box .btn { - width: 60px; - height: 30px; - line-height: 30px; - border-radius: 3px; - border: none; - margin: 0 0 0 20px; - padding: 0 8px; - cursor: pointer; -} - -.input-box .btn:hover { - background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%); - color: #333333; -} - -.input-box .input { - border: none; - border-radius: 3px; - outline: none; - height: 30px; - line-height: 30px; - padding: 0 10px; - background-color: rgba(240, 240, 240, 1); - -webkit-font-smoothing: antialiased; -} - -.input-box .input:hover { - border: none; - background-color: rgba(255, 255, 255, 1); -} - -.input-box .input:focus { - border: none; - background-color: rgba(255, 255, 255, 1); -} \ No newline at end of file diff --git a/v2/pkg/templates/generate/assets/react-ts/frontend/src/App.tsx b/v2/pkg/templates/generate/assets/react-ts/frontend/src/App.tsx deleted file mode 100644 index a6e56f9f8..000000000 --- a/v2/pkg/templates/generate/assets/react-ts/frontend/src/App.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import {useState} from 'react'; -import logo from './assets/images/logo-universal.png'; -import './App.css'; -import {Greet} from "../wailsjs/go/main/App"; - -function App() { - const [resultText, setResultText] = useState("Please enter your name below 👇"); - const [name, setName] = useState(''); - const updateName = (e: any) => setName(e.target.value); - const updateResultText = (result: string) => setResultText(result); - - function greet() { - Greet(name).then(updateResultText); - } - - return ( -
- -
{resultText}
-
- - -
-
- ) -} - -export default App diff --git a/v2/pkg/templates/generate/assets/react-ts/frontend/src/main.tsx b/v2/pkg/templates/generate/assets/react-ts/frontend/src/main.tsx deleted file mode 100644 index 3626ff303..000000000 --- a/v2/pkg/templates/generate/assets/react-ts/frontend/src/main.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react' -import {createRoot} from 'react-dom/client' -import './style.css' -import App from './App' - -const container = document.getElementById('root') - -const root = createRoot(container!) - -root.render( - - - -) diff --git a/v2/pkg/templates/generate/assets/react/frontend/dist/gitkeep b/v2/pkg/templates/generate/assets/react/frontend/dist/gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/v2/pkg/templates/generate/assets/react/frontend/index.tmpl.html b/v2/pkg/templates/generate/assets/react/frontend/index.tmpl.html deleted file mode 100644 index 80aa30b89..000000000 --- a/v2/pkg/templates/generate/assets/react/frontend/index.tmpl.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - {{.ProjectName}} - - -
- - - - diff --git a/v2/pkg/templates/generate/assets/react/frontend/src/App.css b/v2/pkg/templates/generate/assets/react/frontend/src/App.css deleted file mode 100644 index f949d9c18..000000000 --- a/v2/pkg/templates/generate/assets/react/frontend/src/App.css +++ /dev/null @@ -1,59 +0,0 @@ -#app { - height: 100vh; - text-align: center; -} - -#logo { - display: block; - width: 50%; - height: 50%; - margin: auto; - padding: 10% 0 0; - background-position: center; - background-repeat: no-repeat; - background-size: 100% 100%; - background-origin: content-box; -} - -.result { - height: 20px; - line-height: 20px; - margin: 1.5rem auto; -} - -.input-box .btn { - width: 60px; - height: 30px; - line-height: 30px; - border-radius: 3px; - border: none; - margin: 0 0 0 20px; - padding: 0 8px; - cursor: pointer; -} - -.input-box .btn:hover { - background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%); - color: #333333; -} - -.input-box .input { - border: none; - border-radius: 3px; - outline: none; - height: 30px; - line-height: 30px; - padding: 0 10px; - background-color: rgba(240, 240, 240, 1); - -webkit-font-smoothing: antialiased; -} - -.input-box .input:hover { - border: none; - background-color: rgba(255, 255, 255, 1); -} - -.input-box .input:focus { - border: none; - background-color: rgba(255, 255, 255, 1); -} \ No newline at end of file diff --git a/v2/pkg/templates/generate/assets/react/frontend/src/App.jsx b/v2/pkg/templates/generate/assets/react/frontend/src/App.jsx deleted file mode 100644 index fd762291f..000000000 --- a/v2/pkg/templates/generate/assets/react/frontend/src/App.jsx +++ /dev/null @@ -1,28 +0,0 @@ -import {useState} from 'react'; -import logo from './assets/images/logo-universal.png'; -import './App.css'; -import {Greet} from "../wailsjs/go/main/App"; - -function App() { - const [resultText, setResultText] = useState("Please enter your name below 👇"); - const [name, setName] = useState(''); - const updateName = (e) => setName(e.target.value); - const updateResultText = (result) => setResultText(result); - - function greet() { - Greet(name).then(updateResultText); - } - - return ( -
- -
{resultText}
-
- - -
-
- ) -} - -export default App diff --git a/v2/pkg/templates/generate/assets/react/frontend/src/assets/fonts/OFL.txt b/v2/pkg/templates/generate/assets/react/frontend/src/assets/fonts/OFL.txt deleted file mode 100644 index 9cac04ce8..000000000 --- a/v2/pkg/templates/generate/assets/react/frontend/src/assets/fonts/OFL.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com), - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/v2/pkg/templates/generate/assets/react/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 b/v2/pkg/templates/generate/assets/react/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 deleted file mode 100644 index 2f9cc5964..000000000 Binary files a/v2/pkg/templates/generate/assets/react/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 and /dev/null differ diff --git a/v2/pkg/templates/generate/assets/react/frontend/src/assets/images/logo-universal.png b/v2/pkg/templates/generate/assets/react/frontend/src/assets/images/logo-universal.png deleted file mode 100644 index 01c74ee9b..000000000 Binary files a/v2/pkg/templates/generate/assets/react/frontend/src/assets/images/logo-universal.png and /dev/null differ diff --git a/v2/pkg/templates/generate/assets/react/frontend/src/main.jsx b/v2/pkg/templates/generate/assets/react/frontend/src/main.jsx deleted file mode 100644 index e50e105db..000000000 --- a/v2/pkg/templates/generate/assets/react/frontend/src/main.jsx +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react' -import {createRoot} from 'react-dom/client' -import './style.css' -import App from './App' - -const container = document.getElementById('root') - -const root = createRoot(container) - -root.render( - - - -) diff --git a/v2/pkg/templates/generate/assets/react/frontend/src/style.css b/v2/pkg/templates/generate/assets/react/frontend/src/style.css deleted file mode 100644 index 3940d6c63..000000000 --- a/v2/pkg/templates/generate/assets/react/frontend/src/style.css +++ /dev/null @@ -1,26 +0,0 @@ -html { - background-color: rgba(27, 38, 54, 1); - text-align: center; - color: white; -} - -body { - margin: 0; - color: white; - font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", - "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", - sans-serif; -} - -@font-face { - font-family: "Nunito"; - font-style: normal; - font-weight: 400; - src: local(""), - url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2"); -} - -#app { - height: 100vh; - text-align: center; -} diff --git a/v2/pkg/templates/generate/assets/svelte-ts/frontend/index.tmpl.html b/v2/pkg/templates/generate/assets/svelte-ts/frontend/index.tmpl.html deleted file mode 100644 index 3dd212f2d..000000000 --- a/v2/pkg/templates/generate/assets/svelte-ts/frontend/index.tmpl.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - {{.ProjectName}} - - -
- - - diff --git a/v2/pkg/templates/generate/assets/svelte-ts/frontend/src/App.svelte b/v2/pkg/templates/generate/assets/svelte-ts/frontend/src/App.svelte deleted file mode 100644 index 1987eb090..000000000 --- a/v2/pkg/templates/generate/assets/svelte-ts/frontend/src/App.svelte +++ /dev/null @@ -1,79 +0,0 @@ - - -
- -
{resultText}
-
- - -
-
- - diff --git a/v2/pkg/templates/generate/assets/svelte-ts/frontend/src/main.ts b/v2/pkg/templates/generate/assets/svelte-ts/frontend/src/main.ts deleted file mode 100644 index 95c41a51d..000000000 --- a/v2/pkg/templates/generate/assets/svelte-ts/frontend/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './style.css' -import App from './App.svelte' - -const app = new App({ - target: document.getElementById('app') -}) - -export default app diff --git a/v2/pkg/templates/generate/assets/svelte/frontend/index.tmpl.html b/v2/pkg/templates/generate/assets/svelte/frontend/index.tmpl.html deleted file mode 100644 index 859919153..000000000 --- a/v2/pkg/templates/generate/assets/svelte/frontend/index.tmpl.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - {{.ProjectName}} - - -
- - - diff --git a/v2/pkg/templates/generate/assets/svelte/frontend/src/App.svelte b/v2/pkg/templates/generate/assets/svelte/frontend/src/App.svelte deleted file mode 100644 index 2a2ce2282..000000000 --- a/v2/pkg/templates/generate/assets/svelte/frontend/src/App.svelte +++ /dev/null @@ -1,79 +0,0 @@ - - -
- -
{resultText}
-
- - -
-
- - diff --git a/v2/pkg/templates/generate/assets/svelte/frontend/src/main.js b/v2/pkg/templates/generate/assets/svelte/frontend/src/main.js deleted file mode 100644 index 95c41a51d..000000000 --- a/v2/pkg/templates/generate/assets/svelte/frontend/src/main.js +++ /dev/null @@ -1,8 +0,0 @@ -import './style.css' -import App from './App.svelte' - -const app = new App({ - target: document.getElementById('app') -}) - -export default app diff --git a/v2/pkg/templates/generate/assets/vanilla-ts/frontend/index.tmpl.html b/v2/pkg/templates/generate/assets/vanilla-ts/frontend/index.tmpl.html deleted file mode 100644 index 3dd212f2d..000000000 --- a/v2/pkg/templates/generate/assets/vanilla-ts/frontend/index.tmpl.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - {{.ProjectName}} - - -
- - - diff --git a/v2/pkg/templates/generate/assets/vanilla-ts/frontend/src/app.css b/v2/pkg/templates/generate/assets/vanilla-ts/frontend/src/app.css deleted file mode 100644 index 59d06f692..000000000 --- a/v2/pkg/templates/generate/assets/vanilla-ts/frontend/src/app.css +++ /dev/null @@ -1,54 +0,0 @@ -#logo { - display: block; - width: 50%; - height: 50%; - margin: auto; - padding: 10% 0 0; - background-position: center; - background-repeat: no-repeat; - background-size: 100% 100%; - background-origin: content-box; -} - -.result { - height: 20px; - line-height: 20px; - margin: 1.5rem auto; -} - -.input-box .btn { - width: 60px; - height: 30px; - line-height: 30px; - border-radius: 3px; - border: none; - margin: 0 0 0 20px; - padding: 0 8px; - cursor: pointer; -} - -.input-box .btn:hover { - background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%); - color: #333333; -} - -.input-box .input { - border: none; - border-radius: 3px; - outline: none; - height: 30px; - line-height: 30px; - padding: 0 10px; - background-color: rgba(240, 240, 240, 1); - -webkit-font-smoothing: antialiased; -} - -.input-box .input:hover { - border: none; - background-color: rgba(255, 255, 255, 1); -} - -.input-box .input:focus { - border: none; - background-color: rgba(255, 255, 255, 1); -} \ No newline at end of file diff --git a/v2/pkg/templates/generate/assets/vanilla-ts/frontend/src/main.ts b/v2/pkg/templates/generate/assets/vanilla-ts/frontend/src/main.ts deleted file mode 100644 index b68d7d961..000000000 --- a/v2/pkg/templates/generate/assets/vanilla-ts/frontend/src/main.ts +++ /dev/null @@ -1,49 +0,0 @@ -import './style.css'; -import './app.css'; - -import logo from './assets/images/logo-universal.png'; -import {Greet} from '../wailsjs/go/main/App'; - -// Setup the greet function -window.greet = function () { - // Get name - let name = nameElement!.value; - - // Check if the input is empty - if (name === "") return; - - // Call App.Greet(name) - try { - Greet(name) - .then((result) => { - // Update result with data back from App.Greet() - resultElement!.innerText = result; - }) - .catch((err) => { - console.error(err); - }); - } catch (err) { - console.error(err); - } -}; - -document.querySelector('#app')!.innerHTML = ` - -
Please enter your name below 👇
-
- - -
- -`; -(document.getElementById('logo') as HTMLImageElement).src = logo; - -let nameElement = (document.getElementById("name") as HTMLInputElement); -nameElement.focus(); -let resultElement = document.getElementById("result"); - -declare global { - interface Window { - greet: () => void; - } -} diff --git a/v2/pkg/templates/generate/assets/vanilla/frontend/index.tmpl.html b/v2/pkg/templates/generate/assets/vanilla/frontend/index.tmpl.html deleted file mode 100644 index 859919153..000000000 --- a/v2/pkg/templates/generate/assets/vanilla/frontend/index.tmpl.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - {{.ProjectName}} - - -
- - - diff --git a/v2/pkg/templates/generate/assets/vanilla/frontend/src/app.css b/v2/pkg/templates/generate/assets/vanilla/frontend/src/app.css deleted file mode 100644 index 59d06f692..000000000 --- a/v2/pkg/templates/generate/assets/vanilla/frontend/src/app.css +++ /dev/null @@ -1,54 +0,0 @@ -#logo { - display: block; - width: 50%; - height: 50%; - margin: auto; - padding: 10% 0 0; - background-position: center; - background-repeat: no-repeat; - background-size: 100% 100%; - background-origin: content-box; -} - -.result { - height: 20px; - line-height: 20px; - margin: 1.5rem auto; -} - -.input-box .btn { - width: 60px; - height: 30px; - line-height: 30px; - border-radius: 3px; - border: none; - margin: 0 0 0 20px; - padding: 0 8px; - cursor: pointer; -} - -.input-box .btn:hover { - background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%); - color: #333333; -} - -.input-box .input { - border: none; - border-radius: 3px; - outline: none; - height: 30px; - line-height: 30px; - padding: 0 10px; - background-color: rgba(240, 240, 240, 1); - -webkit-font-smoothing: antialiased; -} - -.input-box .input:hover { - border: none; - background-color: rgba(255, 255, 255, 1); -} - -.input-box .input:focus { - border: none; - background-color: rgba(255, 255, 255, 1); -} \ No newline at end of file diff --git a/v2/pkg/templates/generate/assets/vanilla/frontend/src/main.js b/v2/pkg/templates/generate/assets/vanilla/frontend/src/main.js deleted file mode 100644 index 4ad5a2cae..000000000 --- a/v2/pkg/templates/generate/assets/vanilla/frontend/src/main.js +++ /dev/null @@ -1,43 +0,0 @@ -import './style.css'; -import './app.css'; - -import logo from './assets/images/logo-universal.png'; -import {Greet} from '../wailsjs/go/main/App'; - -document.querySelector('#app').innerHTML = ` - -
Please enter your name below 👇
-
- - -
- -`; -document.getElementById('logo').src = logo; - -let nameElement = document.getElementById("name"); -nameElement.focus(); -let resultElement = document.getElementById("result"); - -// Setup the greet function -window.greet = function () { - // Get name - let name = nameElement.value; - - // Check if the input is empty - if (name === "") return; - - // Call App.Greet(name) - try { - Greet(name) - .then((result) => { - // Update result with data back from App.Greet() - resultElement.innerText = result; - }) - .catch((err) => { - console.error(err); - }); - } catch (err) { - console.error(err); - } -}; diff --git a/v2/pkg/templates/generate/assets/vue-ts/frontend/index.tmpl.html b/v2/pkg/templates/generate/assets/vue-ts/frontend/index.tmpl.html deleted file mode 100644 index cc259435b..000000000 --- a/v2/pkg/templates/generate/assets/vue-ts/frontend/index.tmpl.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - {{.ProjectName}} - - -
- - - - diff --git a/v2/pkg/templates/generate/assets/vue-ts/frontend/src/App.vue b/v2/pkg/templates/generate/assets/vue-ts/frontend/src/App.vue deleted file mode 100644 index b63d187c5..000000000 --- a/v2/pkg/templates/generate/assets/vue-ts/frontend/src/App.vue +++ /dev/null @@ -1,21 +0,0 @@ - - - - - diff --git a/v2/pkg/templates/generate/assets/vue-ts/frontend/src/components/HelloWorld.vue b/v2/pkg/templates/generate/assets/vue-ts/frontend/src/components/HelloWorld.vue deleted file mode 100644 index 3ab3df798..000000000 --- a/v2/pkg/templates/generate/assets/vue-ts/frontend/src/components/HelloWorld.vue +++ /dev/null @@ -1,71 +0,0 @@ - - - - - diff --git a/v2/pkg/templates/generate/assets/vue-ts/frontend/src/main.ts b/v2/pkg/templates/generate/assets/vue-ts/frontend/src/main.ts deleted file mode 100644 index e57db5948..000000000 --- a/v2/pkg/templates/generate/assets/vue-ts/frontend/src/main.ts +++ /dev/null @@ -1,4 +0,0 @@ -import {createApp} from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/v2/pkg/templates/generate/assets/vue-ts/frontend/tsconfig.json b/v2/pkg/templates/generate/assets/vue-ts/frontend/tsconfig.json deleted file mode 100644 index 3cc844d92..000000000 --- a/v2/pkg/templates/generate/assets/vue-ts/frontend/tsconfig.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "moduleResolution": "Node", - "strict": true, - "jsx": "preserve", - "sourceMap": true, - "resolveJsonModule": true, - "isolatedModules": true, - "esModuleInterop": true, - "lib": [ - "ESNext", - "DOM" - ], - "skipLibCheck": true - }, - "include": [ - "src/**/*.ts", - "src/**/*.d.ts", - "src/**/*.tsx", - "src/**/*.vue" - ], - "references": [ - { - "path": "./tsconfig.node.json" - } - ] -} diff --git a/v2/pkg/templates/generate/assets/vue/frontend/index.tmpl.html b/v2/pkg/templates/generate/assets/vue/frontend/index.tmpl.html deleted file mode 100644 index d45b7a8c4..000000000 --- a/v2/pkg/templates/generate/assets/vue/frontend/index.tmpl.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - {{.ProjectName}} - - -
- - - - diff --git a/v2/pkg/templates/generate/assets/vue/frontend/src/App.vue b/v2/pkg/templates/generate/assets/vue/frontend/src/App.vue deleted file mode 100644 index 15d2f1215..000000000 --- a/v2/pkg/templates/generate/assets/vue/frontend/src/App.vue +++ /dev/null @@ -1,21 +0,0 @@ - - - - - diff --git a/v2/pkg/templates/generate/assets/vue/frontend/src/assets/fonts/OFL.txt b/v2/pkg/templates/generate/assets/vue/frontend/src/assets/fonts/OFL.txt deleted file mode 100644 index 9cac04ce8..000000000 --- a/v2/pkg/templates/generate/assets/vue/frontend/src/assets/fonts/OFL.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com), - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/v2/pkg/templates/generate/assets/vue/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 b/v2/pkg/templates/generate/assets/vue/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 deleted file mode 100644 index 2f9cc5964..000000000 Binary files a/v2/pkg/templates/generate/assets/vue/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 and /dev/null differ diff --git a/v2/pkg/templates/generate/assets/vue/frontend/src/assets/images/logo-universal.png b/v2/pkg/templates/generate/assets/vue/frontend/src/assets/images/logo-universal.png deleted file mode 100644 index b1224ec79..000000000 Binary files a/v2/pkg/templates/generate/assets/vue/frontend/src/assets/images/logo-universal.png and /dev/null differ diff --git a/v2/pkg/templates/generate/assets/vue/frontend/src/components/HelloWorld.vue b/v2/pkg/templates/generate/assets/vue/frontend/src/components/HelloWorld.vue deleted file mode 100644 index 29c023fbe..000000000 --- a/v2/pkg/templates/generate/assets/vue/frontend/src/components/HelloWorld.vue +++ /dev/null @@ -1,71 +0,0 @@ - - - - - diff --git a/v2/pkg/templates/generate/assets/vue/frontend/src/main.js b/v2/pkg/templates/generate/assets/vue/frontend/src/main.js deleted file mode 100644 index e57db5948..000000000 --- a/v2/pkg/templates/generate/assets/vue/frontend/src/main.js +++ /dev/null @@ -1,4 +0,0 @@ -import {createApp} from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/v2/pkg/templates/generate/assets/vue/frontend/src/style.css b/v2/pkg/templates/generate/assets/vue/frontend/src/style.css deleted file mode 100644 index 3940d6c63..000000000 --- a/v2/pkg/templates/generate/assets/vue/frontend/src/style.css +++ /dev/null @@ -1,26 +0,0 @@ -html { - background-color: rgba(27, 38, 54, 1); - text-align: center; - color: white; -} - -body { - margin: 0; - color: white; - font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", - "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", - sans-serif; -} - -@font-face { - font-family: "Nunito"; - font-style: normal; - font-weight: 400; - src: local(""), - url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2"); -} - -#app { - height: 100vh; - text-align: center; -} diff --git a/v2/pkg/templates/generate/assets/vue/frontend/vite.config.js b/v2/pkg/templates/generate/assets/vue/frontend/vite.config.js deleted file mode 100644 index a30c338ed..000000000 --- a/v2/pkg/templates/generate/assets/vue/frontend/vite.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import {defineConfig} from 'vite' -import vue from '@vitejs/plugin-vue' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue()] -}) diff --git a/v2/pkg/templates/generate/generate.go b/v2/pkg/templates/generate/generate.go deleted file mode 100644 index 6842dc196..000000000 --- a/v2/pkg/templates/generate/generate.go +++ /dev/null @@ -1,232 +0,0 @@ -package main - -import ( - "embed" - "os" - "strings" - - "github.com/leaanthony/debme" - "github.com/leaanthony/gosod" - "github.com/wailsapp/wails/v2/internal/s" -) - -//go:embed assets/common/* -var common embed.FS - -//go:embed assets/svelte/* -var svelte embed.FS - -//go:embed assets/svelte-ts/* -var sveltets embed.FS - -//go:embed assets/lit/* -var lit embed.FS - -//go:embed assets/lit-ts/* -var litts embed.FS - -//go:embed assets/vue/* -var vue embed.FS - -//go:embed assets/vue-ts/* -var vuets embed.FS - -//go:embed assets/react/* -var react embed.FS - -//go:embed assets/react-ts/* -var reactts embed.FS - -//go:embed assets/preact/* -var preact embed.FS - -//go:embed assets/preact-ts/* -var preactts embed.FS - -//go:embed assets/vanilla/* -var vanilla embed.FS - -//go:embed assets/vanilla-ts/* -var vanillats embed.FS - -func checkError(err error) { - if err != nil { - println("\nERROR:", err.Error()) - os.Exit(1) - } -} - -type template struct { - Name string - ShortName string - Description string - Assets embed.FS - FilesToDelete []string - DirsToDelete []string -} - -var templates = []*template{ - { - Name: "Svelte + Vite", - ShortName: "Svelte", - Description: "Svelte + Vite development server", - Assets: svelte, - FilesToDelete: []string{"frontend/index.html", "frontend/.gitignore", "frontend/src/app.css", "frontend/src/assets/svelte.svg"}, - DirsToDelete: []string{"frontend/public", "frontend/src/lib"}, - }, - { - Name: "Svelte + Vite (Typescript)", - ShortName: "Svelte-TS", - Description: "Svelte + TS + Vite development server", - Assets: sveltets, - FilesToDelete: []string{"frontend/index.html", "frontend/.gitignore", "frontend/src/app.css", "frontend/src/assets/svelte.svg"}, - DirsToDelete: []string{"frontend/public", "frontend/src/lib"}, - }, - { - Name: "Lit + Vite", - ShortName: "Lit", - Description: "Lit + Vite development server", - Assets: lit, - FilesToDelete: []string{"frontend/index.html", "frontend/vite.config.js"}, - }, - { - Name: "Lit + Vite (Typescript)", - ShortName: "Lit-TS", - Description: "Lit + TS + Vite development server", - Assets: litts, - FilesToDelete: []string{"frontend/index.html", "frontend/src/favicon.svg"}, - }, - { - Name: "Vue + Vite", - ShortName: "Vue", - Description: "Vue + Vite development server", - Assets: vue, - FilesToDelete: []string{"frontend/index.html", "frontend/.gitignore"}, - DirsToDelete: []string{"frontend/src/assets", "frontend/src/components", "frontend/public"}, - }, - { - Name: "Vue + Vite (Typescript)", - ShortName: "Vue-TS", - Description: "Vue + Vite development server", - Assets: vuets, - FilesToDelete: []string{"frontend/index.html", "frontend/.gitignore"}, - DirsToDelete: []string{"frontend/src/assets", "frontend/src/components", "frontend/public"}, - }, - { - Name: "React + Vite", - ShortName: "React", - Description: "React + Vite development server", - Assets: react, - FilesToDelete: []string{"frontend/src/index.css", "frontend/src/favicon.svg", "frontend/src/logo.svg", "frontend/.gitignore", "frontend/index.html"}, - }, - { - Name: "React + Vite (Typescript)", - ShortName: "React-TS", - Description: "React + Vite development server", - Assets: reactts, - FilesToDelete: []string{"frontend/src/index.css", "frontend/src/favicon.svg", "frontend/src/logo.svg", "frontend/.gitignore", "frontend/index.html"}, - }, - { - Name: "Preact + Vite", - ShortName: "Preact", - Description: "Preact + Vite development server", - Assets: preact, - FilesToDelete: []string{"frontend/src/index.css", "frontend/src/favicon.svg", "frontend/src/logo.jsx", "frontend/.gitignore", "frontend/index.html"}, - DirsToDelete: []string{"frontend/public"}, - }, - { - Name: "Preact + Vite (Typescript)", - ShortName: "Preact-TS", - Description: "Preact + Vite development server", - Assets: preactts, - FilesToDelete: []string{"frontend/src/index.css", "frontend/src/favicon.svg", "frontend/src/assets/preact.svg", "frontend/src/logo.tsx", "frontend/.gitignore", "frontend/index.html"}, - DirsToDelete: []string{"frontend/public"}, - }, - { - Name: "Vanilla + Vite", - ShortName: "Vanilla", - Description: "Vanilla + Vite development server", - Assets: vanilla, - FilesToDelete: []string{"frontend/.gitignore", "frontend/index.html", "frontend/favicon.svg", "frontend/main.js", "frontend/style.css"}, - }, - { - Name: "Vanilla + Vite (Typescript)", - ShortName: "Vanilla-TS", - Description: "Vanilla + Vite development server", - Assets: vanillats, - FilesToDelete: []string{"frontend/.gitignore", "frontend/index.html", "frontend/favicon.svg", "frontend/src/main.ts", "frontend/src/style.css"}, - }, -} - -func main() { - rebuildRuntime() - - for _, t := range templates { - createTemplate(t) - } - - // copy plain template - s.ECHO("Copying plain template") - s.RMDIR("../templates/plain") - s.COPYDIR("plain", "../templates/plain") - - s.ECHO(`Until an auto fix is done, add "@babel/types": "^7.17.10" to vue-ts/frontend/package.json`) -} - -func rebuildRuntime() { - s.ECHO("Generating Runtime") - cwd := s.CWD() - const runtimeDir = "../../../internal/frontend/runtime/" - const commonDir = "./assets/common/frontend/wailsjs/runtime/" - s.CD(runtimeDir) - s.EXEC("npm run build") - s.ECHO("Copying new files") - s.CD("wrapper") - s.COPY("package.json", commonDir+"package.json") - s.COPY("runtime.js", commonDir+"runtime.js") - s.COPY("runtime.d.ts", commonDir+"runtime.d.ts") - s.CD(cwd) -} - -func createTemplate(template *template) { - cwd := s.CWD() - name := template.Name - shortName := strings.ToLower(template.ShortName) - assets, err := debme.FS(template.Assets, "assets/"+shortName) - checkError(err) - commonAssets, err := debme.FS(common, "assets/common") - checkError(err) - - s.CD("..") - s.ENDIR("templates") - s.CD("templates") - s.RMDIR(shortName) - s.COPYDIR("../base", shortName) - s.CD(shortName) - s.ECHO("Generating vite template: " + shortName) - s.EXEC("npm create vite@latest frontend --template " + shortName) - - // Clean up template - for _, fileToDelete := range template.FilesToDelete { - s.DELETE(fileToDelete) - } - for _, dirToDelete := range template.DirsToDelete { - s.RMDIR(dirToDelete) - } - s.REPLACEALL("README.md", s.Sub{"$NAME": template.ShortName}) - s.REPLACEALL("template.json", s.Sub{"$NAME": name, "$SHORTNAME": shortName, "$DESCRIPTION": template.Description}) - - // Add common files - g := gosod.New(commonAssets) - g.SetTemplateFilters([]string{}) - err = g.Extract(".", nil) - checkError(err) - - // Add custom files - g = gosod.New(assets) - g.SetTemplateFilters([]string{}) - err = g.Extract(".", nil) - checkError(err) - - s.CD(cwd) -} diff --git a/v2/pkg/templates/generate/go.sum b/v2/pkg/templates/generate/go.sum deleted file mode 100644 index 69c3ba18a..000000000 --- a/v2/pkg/templates/generate/go.sum +++ /dev/null @@ -1,4 +0,0 @@ -github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc= -github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA= -github.com/leaanthony/gosod v1.0.3 h1:Fnt+/B6NjQOVuCWOKYRREZnjGyvg+mEhd1nkkA04aTQ= -github.com/leaanthony/gosod v1.0.3/go.mod h1:BJ2J+oHsQIyIQpnLPjnqFGTMnOZXDbvWtRCSG7jGxs4= diff --git a/v2/pkg/templates/generate/plain/.gitignore.tmpl b/v2/pkg/templates/generate/plain/.gitignore.tmpl deleted file mode 100644 index b92a6f8bf..000000000 --- a/v2/pkg/templates/generate/plain/.gitignore.tmpl +++ /dev/null @@ -1,12 +0,0 @@ -# Wails bin directory -build/bin -# Wails Windows NSIS support files -build/windows/installer/wails_tools.nsh -build/windows/installer/tmp/ - -# IDEs -.idea -.vscode - -# The black hole that is... -node_modules diff --git a/v2/pkg/templates/generate/plain/README.md b/v2/pkg/templates/generate/plain/README.md deleted file mode 100644 index 9fcd85bdd..000000000 --- a/v2/pkg/templates/generate/plain/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# README - -## About - -This template uses plain JS / HTML and CSS. - -You can configure the project by editing `wails.json`. More information about the project settings can be found -here: https://wails.io/docs/reference/project-config - -## Live Development - -To run in live development mode, run `wails dev` in the project directory. The frontend dev server will run -on http://localhost:34115. Open this in your browser to connect to your application. - -## Building - -For a production build, use `wails build`. - diff --git a/v2/pkg/templates/generate/plain/app.go b/v2/pkg/templates/generate/plain/app.go deleted file mode 100644 index 224be7156..000000000 --- a/v2/pkg/templates/generate/plain/app.go +++ /dev/null @@ -1,44 +0,0 @@ -package main - -import ( - "context" - "fmt" -) - -// App struct -type App struct { - ctx context.Context -} - -// NewApp creates a new App application struct -func NewApp() *App { - return &App{} -} - -// startup is called at application startup -func (a *App) startup(ctx context.Context) { - // Perform your setup here - a.ctx = ctx -} - -// domReady is called after front-end resources have been loaded -func (a App) domReady(ctx context.Context) { - // Add your action here -} - -// beforeClose is called when the application is about to quit, -// either by clicking the window close button or calling runtime.Quit. -// Returning true will cause the application to continue, false will continue shutdown as normal. -func (a *App) beforeClose(ctx context.Context) (prevent bool) { - return false -} - -// shutdown is called at application termination -func (a *App) shutdown(ctx context.Context) { - // Perform your teardown here -} - -// Greet returns a greeting for the given name -func (a *App) Greet(name string) string { - return fmt.Sprintf("Hello %s, It's show time!", name) -} diff --git a/v2/pkg/templates/generate/plain/frontend/src/assets/fonts/OFL.txt b/v2/pkg/templates/generate/plain/frontend/src/assets/fonts/OFL.txt deleted file mode 100644 index 9cac04ce8..000000000 --- a/v2/pkg/templates/generate/plain/frontend/src/assets/fonts/OFL.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com), - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/v2/pkg/templates/generate/plain/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 b/v2/pkg/templates/generate/plain/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 deleted file mode 100644 index 2f9cc5964..000000000 Binary files a/v2/pkg/templates/generate/plain/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 and /dev/null differ diff --git a/v2/pkg/templates/generate/plain/frontend/src/assets/images/logo-universal.png b/v2/pkg/templates/generate/plain/frontend/src/assets/images/logo-universal.png deleted file mode 100644 index b1224ec79..000000000 Binary files a/v2/pkg/templates/generate/plain/frontend/src/assets/images/logo-universal.png and /dev/null differ diff --git a/v2/pkg/templates/generate/plain/frontend/src/index.tmpl.html b/v2/pkg/templates/generate/plain/frontend/src/index.tmpl.html deleted file mode 100644 index a8a434a37..000000000 --- a/v2/pkg/templates/generate/plain/frontend/src/index.tmpl.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - {{.ProjectName}} - - - - -
- -
Please enter your name below 👇
-
- - -
-
- - - diff --git a/v2/pkg/templates/generate/plain/frontend/src/main.css b/v2/pkg/templates/generate/plain/frontend/src/main.css deleted file mode 100644 index dab87d09a..000000000 --- a/v2/pkg/templates/generate/plain/frontend/src/main.css +++ /dev/null @@ -1,82 +0,0 @@ -html { - background-color: rgba(27, 38, 54, 1); - text-align: center; - color: white; -} - -body { - margin: 0; - color: white; - font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", - "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", - sans-serif; -} - -@font-face { - font-family: "Nunito"; - font-style: normal; - font-weight: 400; - src: local(""), - url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2"); -} - -#app { - height: 100vh; - text-align: center; -} - -.logo { - display: block; - width: 50%; - height: 50%; - margin: auto; - padding: 10% 0 0; - background-position: center; - background-repeat: no-repeat; - background-image: url("./assets/images/logo-universal.png"); - background-size: 100% 100%; - background-origin: content-box; -} - -.result { - height: 20px; - line-height: 20px; - margin: 1.5rem auto; -} - -.input-box .btn { - width: 60px; - height: 30px; - line-height: 30px; - border-radius: 3px; - border: none; - margin: 0 0 0 20px; - padding: 0 8px; - cursor: pointer; -} - -.input-box .btn:hover { - background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%); - color: #333333; -} - -.input-box .input { - border: none; - border-radius: 3px; - outline: none; - height: 30px; - line-height: 30px; - padding: 0 10px; - background-color: rgba(240, 240, 240, 1); - -webkit-font-smoothing: antialiased; -} - -.input-box .input:hover { - border: none; - background-color: rgba(255, 255, 255, 1); -} - -.input-box .input:focus { - border: none; - background-color: rgba(255, 255, 255, 1); -} diff --git a/v2/pkg/templates/generate/plain/frontend/src/main.js b/v2/pkg/templates/generate/plain/frontend/src/main.js deleted file mode 100644 index 3346d59ff..000000000 --- a/v2/pkg/templates/generate/plain/frontend/src/main.js +++ /dev/null @@ -1,32 +0,0 @@ -// Get input + focus -let nameElement = document.getElementById("name"); -nameElement.focus(); - -// Setup the greet function -window.greet = function () { - // Get name - let name = nameElement.value; - - // Check if the input is empty - if (name === "") return; - - // Call App.Greet(name) - try { - window.go.main.App.Greet(name) - .then((result) => { - // Update result with data back from App.Greet() - document.getElementById("result").innerText = result; - }) - .catch((err) => { - console.error(err); - }); - } catch (err) { - console.error(err); - } -}; - -nameElement.onkeydown = function (e) { - if (e.keyCode == 13) { - window.greet(); - } -}; diff --git a/v2/pkg/templates/generate/plain/go.mod.tmpl b/v2/pkg/templates/generate/plain/go.mod.tmpl deleted file mode 100644 index f6d0daec4..000000000 --- a/v2/pkg/templates/generate/plain/go.mod.tmpl +++ /dev/null @@ -1,34 +0,0 @@ -module changeme - -go 1.23.0 - -require github.com/wailsapp/wails/v2 {{.WailsVersion}} - -require ( -github.com/andybalholm/brotli v1.0.2 // indirect -github.com/davecgh/go-spew v1.1.1 // indirect -github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect -github.com/wailsapp/mimetype v1.4.1-beta.1 -github.com/go-ole/go-ole v1.2.5 // indirect -github.com/gofiber/fiber/v2 v2.17.0 // indirect -github.com/gofiber/websocket/v2 v2.0.8 // indirect -github.com/google/uuid v1.1.2 // indirect -github.com/imdario/mergo v0.3.12 // indirect -github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5 // indirect -github.com/klauspost/compress v1.12.2 // indirect -github.com/leaanthony/debme v1.2.1 // indirect -github.com/leaanthony/go-ansi-parser v1.0.1 // indirect -github.com/leaanthony/slicer v1.5.0 // indirect -github.com/leaanthony/typescriptify-golang-structs v0.1.7 // indirect -github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect -github.com/pkg/errors v0.9.1 // indirect -github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect -github.com/tkrajina/go-reflector v0.5.5 // indirect -github.com/valyala/bytebufferpool v1.0.0 // indirect -github.com/valyala/fasthttp v1.28.0 // indirect -github.com/valyala/tcplisten v1.0.0 // indirect -golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf // indirect -) - -// replace github.com/wailsapp/wails/v2 {{.WailsVersion}} => {{.WailsDirectory}} diff --git a/v2/pkg/templates/generate/plain/go.sum b/v2/pkg/templates/generate/plain/go.sum deleted file mode 100644 index 3e14e745f..000000000 --- a/v2/pkg/templates/generate/plain/go.sum +++ /dev/null @@ -1,220 +0,0 @@ -github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= -github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= -github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= -github.com/andybalholm/brotli v1.0.2 h1:JKnhI/XQ75uFBTiuzXpzFrUriDPiZjlOSzh6wXogP0E= -github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= -github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab h1:9e2joQGp642wHGFP5m86SDptAavrdGBe8/x9DGEEAaI= -github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab/go.mod h1:smsv/h4PBEBaU0XDTY5UwJTpZv69fQ0FfcLJr21mA6Y= -github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= -github.com/flytam/filenamify v1.0.0/go.mod h1:Dzf9kVycwcsBlr2ATg6uxjqiFgKGH+5SKFuhdeP5zu8= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/wailsapp/mimetype v1.4.1-beta.1 h1:gSnKX7WH+7aA0EEjOGUmpWXTb0Nt5B7/8Dm9wHLrnnY= -github.com/wailsapp/mimetype v1.4.1-beta.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= -github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= -github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= -github.com/go-git/go-billy/v5 v5.1.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= -github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= -github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= -github.com/go-git/go-git/v5 v5.3.0/go.mod h1:xdX4bWJ48aOrdhnl2XqHYstHbbp6+LFS4r4X+lNVprw= -github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= -github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY= -github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= -github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= -github.com/gofiber/fiber/v2 v2.17.0 h1:qP3PkGUbBB0i9iQh5E057XI1yO5CZigUxZhyUFYAFoM= -github.com/gofiber/fiber/v2 v2.17.0/go.mod h1:iftruuHGkRYGEXVISmdD7HTYWyfS2Bh+Dkfq4n/1Owg= -github.com/gofiber/websocket/v2 v2.0.8 h1:Hb4y6IxYZVMO0segROODXJiXVgVD3a6i7wnfot8kM6k= -github.com/gofiber/websocket/v2 v2.0.8/go.mod h1:fv8HSGQX09sauNv9g5Xq8GeGAaahLFYQKKb4ZdT0x2w= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= -github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/jackmordaunt/icns v1.0.0/go.mod h1:7TTQVEuGzVVfOPPlLNHJIkzA6CoV7aH1Dv9dW351oOo= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs= -github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck= -github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs= -github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= -github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.12.2 h1:2KCfW3I9M7nSc5wOqXAlW2v2U6v+w6cbjvbfp+OykW8= -github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/leaanthony/clir v1.0.4/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0= -github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc= -github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA= -github.com/leaanthony/go-ansi-parser v1.0.1 h1:97v6c5kYppVsbScf4r/VZdXyQ21KQIfeQOk2DgKxGG4= -github.com/leaanthony/go-ansi-parser v1.0.1/go.mod h1:7arTzgVI47srICYhvgUV4CGd063sGEeoSlych5yeSPM= -github.com/leaanthony/gosod v1.0.3/go.mod h1:BJ2J+oHsQIyIQpnLPjnqFGTMnOZXDbvWtRCSG7jGxs4= -github.com/leaanthony/idgen v1.0.0/go.mod h1:4nBZnt8ml/f/ic/EVQuLxuj817RccT2fyrUaZFxrcVA= -github.com/leaanthony/slicer v1.5.0 h1:aHYTN8xbCCLxJmkNKiLB6tgcMARl4eWmH9/F+S/0HtY= -github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY= -github.com/leaanthony/typescriptify-golang-structs v0.1.7 h1:yoznzWzyxkO/iWdlpq+aPcuJ5Y/hpjq/lmgMFmpjwl0= -github.com/leaanthony/typescriptify-golang-structs v0.1.7/go.mod h1:cWtOkiVhMF77e6phAXUcfNwYmMwCJ67Sij24lfvi9Js= -github.com/leaanthony/winicon v1.0.0/go.mod h1:en5xhijl92aphrJdmRPlh4NI1L6wq3gEm0LpXAPghjU= -github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= -github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= -github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= -github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= -github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 h1:acNfDZXmm28D2Yg/c3ALnZStzNaZMSagpbr96vY6Zjc= -github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f h1:PgA+Olipyj258EIEYnpFFONrrCcAIWNUNoFhUfMqAGY= -github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f/go.mod h1:lHhJedqxCoHN+zMtwGNTXWmF0u9Jt363FYRhV6g0CdY= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/tc-hib/winres v0.1.5/go.mod h1:pe6dOR40VOrGz8PkzreVKNvEKnlE8t4yR8A8naL+t7A= -github.com/tdewolff/minify v2.3.6+incompatible/go.mod h1:9Ov578KJUmAWpS6NeZwRZyT56Uf6o3Mcz9CEsg8USYs= -github.com/tdewolff/parse v2.3.4+incompatible/go.mod h1:8oBwCsVmUkgHO8M5iCzSIDtpzXOT0WXX9cWhz+bIzJQ= -github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= -github.com/tidwall/gjson v1.8.0/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk= -github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/tidwall/sjson v1.1.7/go.mod h1:w/yG+ezBeTdUxiKs5NcPicO9diP38nk96QBAbIIGeFs= -github.com/tkrajina/go-reflector v0.5.5 h1:gwoQFNye30Kk7NrExj8zm3zFtrGPqOkzFMLuQZg1DtQ= -github.com/tkrajina/go-reflector v0.5.5/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4= -github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.9.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= -github.com/valyala/fasthttp v1.26.0/go.mod h1:cmWIqlu99AO/RKcp1HWaViTqc57FswJOfYYdPJBl8BA= -github.com/valyala/fasthttp v1.28.0 h1:ruVmTmZaBR5i67NqnjvvH5gEv0zwHfWtbjoyW98iho4= -github.com/valyala/fasthttp v1.28.0/go.mod h1:cmWIqlu99AO/RKcp1HWaViTqc57FswJOfYYdPJBl8BA= -github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= -github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= -github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= -github.com/wailsapp/wails/v2 v2.0.0-beta.3 h1:8vhBbnjpYDF6cCUwKadon7J/98UjcP1nrnptUl70Tfg= -github.com/wailsapp/wails/v2 v2.0.0-beta.3/go.mod h1:aku28riyHF2G5jmx/qtxjLWi7VwpTjhhX/HVLCptWFA= -github.com/wzshiming/ctc v1.2.3/go.mod h1:2tVAtIY7SUyraSk0JxvwmONNPFL4ARavPuEsg5+KA28= -github.com/wzshiming/winseq v0.0.0-20200112104235-db357dc107ae/go.mod h1:VTAq37rkGeV+WOybvZwjXiJOicICdpLCN8ifpISjK20= -github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= -github.com/xyproto/xpm v1.2.1/go.mod h1:cMnesLsD0PBXLgjDfTDEaKr8XyTFsnP1QycSqRw7BiY= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/ztrue/tracerr v0.3.0/go.mod h1:qEalzze4VN9O8tnhBXScfCrmoJo10o8TN5ciKjm6Mww= -golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= -golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210510120150-4163338589ed h1:p9UgmWI9wKpfYmgaV/IZKGdXc5qEK45tDwwwDyjS26I= -golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210611083646-a4fc73990273/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 h1:foEbQz/B0Oz6YIqu/69kfXPYeFQAuuMYFkjaqXzl5Wo= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= diff --git a/v2/pkg/templates/generate/plain/main.go.tmpl b/v2/pkg/templates/generate/plain/main.go.tmpl deleted file mode 100644 index 9f3e2fffe..000000000 --- a/v2/pkg/templates/generate/plain/main.go.tmpl +++ /dev/null @@ -1,86 +0,0 @@ -package main - -import ( -"embed" -"log" - -"github.com/wailsapp/wails/v2/pkg/options/mac" - -"github.com/wailsapp/wails/v2" -"github.com/wailsapp/wails/v2/pkg/logger" -"github.com/wailsapp/wails/v2/pkg/options" -"github.com/wailsapp/wails/v2/pkg/options/assetserver" -"github.com/wailsapp/wails/v2/pkg/options/windows" -) - -//go:embed frontend/src -var assets embed.FS - -//go:embed build/appicon.png -var icon []byte - -func main() { -// Create an instance of the app structure -app := NewApp() - -// Create application with options -err := wails.Run(&options.App{ -Title: "{{.ProjectName}}", -Width: 1024, -Height: 768, -MinWidth: 1024, -MinHeight: 768, -MaxWidth: 1280, -MaxHeight: 800, -DisableResize: false, -Fullscreen: false, -Frameless: false, -StartHidden: false, -HideWindowOnClose: false, -BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, -AssetServer: &assetserver.Options{ - Assets: assets, -}, -Menu: nil, -Logger: nil, -LogLevel: logger.DEBUG, -OnStartup: app.startup, -OnDomReady: app.domReady, -OnBeforeClose: app.beforeClose, -OnShutdown: app.shutdown, -WindowStartState: options.Normal, -Bind: []interface{}{ -app, -}, -// Windows platform specific options -Windows: &windows.Options{ -WebviewIsTransparent: false, -WindowIsTranslucent: false, -DisableWindowIcon: false, -// DisableFramelessWindowDecorations: false, -WebviewUserDataPath: "", -}, -Mac: &mac.Options{ -TitleBar: &mac.TitleBar{ -TitlebarAppearsTransparent: true, -HideTitle: false, -HideTitleBar: false, -FullSizeContent: false, -UseToolbar: false, -HideToolbarSeparator: true, -}, -Appearance: mac.NSAppearanceNameDarkAqua, -WebviewIsTransparent: true, -WindowIsTranslucent: true, -About: &mac.AboutInfo{ -Title: "Plain Template", -Message: "Part of the Wails projects", -Icon: icon, -}, -}, -}) - -if err != nil { -log.Fatal(err) -} -} diff --git a/v2/pkg/templates/generate/plain/template.json b/v2/pkg/templates/generate/plain/template.json deleted file mode 100644 index fc919bc3b..000000000 --- a/v2/pkg/templates/generate/plain/template.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "Plain HTML/JS/CSS", - "shortname": "plain", - "author": "Lea Anthony ", - "description": "A simple template using only HTML/CSS/JS", - "helpurl": "https://github.com/wailsapp/wails" -} diff --git a/v2/pkg/templates/generate/plain/wails.tmpl.json b/v2/pkg/templates/generate/plain/wails.tmpl.json deleted file mode 100644 index 0168826bd..000000000 --- a/v2/pkg/templates/generate/plain/wails.tmpl.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "$schema": "https://wails.io/schemas/config.v2.json", - "name": "{{.ProjectName}}", - "outputfilename": "{{.BinaryName}}", - "wailsjsdir": "./frontend", - "author": { - "name": "{{.AuthorName}}", - "email": "{{.AuthorEmail}}" - } -} diff --git a/v2/pkg/templates/ides/vscode/launch.tmpl.json b/v2/pkg/templates/ides/vscode/launch.tmpl.json deleted file mode 100644 index 0a5437c9e..000000000 --- a/v2/pkg/templates/ides/vscode/launch.tmpl.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "name": "Wails: Production {{.ProjectName}}", - "type": "go", - "request": "launch", - "mode": "exec", - "program": "${workspaceFolder}/{{.PathToDesktopBinary}}", - "preLaunchTask": "build", - "cwd": "${workspaceFolder}" - }, - { - "name": "Wails: Debug {{.ProjectName}}", - "type": "go", - "request": "launch", - "mode": "exec", - "program": "${workspaceFolder}/{{.PathToDesktopBinary}}", - "preLaunchTask": "build debug", - "cwd": "${workspaceFolder}" - }, - { - "name": "Wails: Dev {{.ProjectName}}", - "type": "go", - "request": "launch", - "mode": "exec", - "program": "${workspaceFolder}/{{.PathToDesktopBinary}}", - "preLaunchTask": "build dev", - "cwd": "${workspaceFolder}" - } - ] -} \ No newline at end of file diff --git a/v2/pkg/templates/ides/vscode/tasks.tmpl.json b/v2/pkg/templates/ides/vscode/tasks.tmpl.json deleted file mode 100644 index fdf1d48dd..000000000 --- a/v2/pkg/templates/ides/vscode/tasks.tmpl.json +++ /dev/null @@ -1,111 +0,0 @@ -{ - "version": "2.0.0", - "tasks": [ - { - "label": "build", - "type": "shell", - "options": { - "cwd": "${workspaceFolder}", - "env": { - "CGO_ENABLED": "1" - } - }, - "osx": { - "options": { - "env": { - "CGO_CFLAGS": "-mmacosx-version-min=10.13", - "CGO_LDFLAGS": "-framework UniformTypeIdentifiers -mmacosx-version-min=10.13" - } - } - }, - "windows": { - "options": { - "env": { - "CGO_ENABLED": "0" - } - } - }, - "command": "go", - "args": [ - "build", - "-tags", - "production,desktop", - "-gcflags", - "all=-N -l", - "-o", - "{{.PathToDesktopBinary}}" - ] - }, - { - "label": "build debug", - "type": "shell", - "options": { - "cwd": "${workspaceFolder}", - "env": { - "CGO_ENABLED": "1" - } - }, - "osx": { - "options": { - "env": { - "CGO_CFLAGS": "-mmacosx-version-min=10.13", - "CGO_LDFLAGS": "-framework UniformTypeIdentifiers -mmacosx-version-min=10.13" - } - } - }, - "windows": { - "options": { - "env": { - "CGO_ENABLED": "0" - } - } - }, - "command": "go", - "args": [ - "build", - "-tags", - "production,desktop,debug", - "-gcflags", - "all=-N -l", - "-o", - "{{.PathToDesktopBinary}}" - ] - }, - { - "label": "build dev", - "type": "shell", - "options": { - "cwd": "${workspaceFolder}", - "env": { - "CGO_ENABLED": "1" - } - }, - "osx": { - "options": { - "env": { - "CGO_CFLAGS": "-mmacosx-version-min=10.13", - "CGO_LDFLAGS": "-framework UniformTypeIdentifiers -mmacosx-version-min=10.13" - } - } - }, - "windows": { - "options": { - "env": { - "CGO_ENABLED": "0" - } - } - }, - "command": "go", - "args": [ - "build", - "-tags", - "dev", - "-gcflags", - "all=-N -l", - "-o", - "{{.PathToDesktopBinary}}" - ] - } - ] -} - \ No newline at end of file diff --git a/v2/pkg/templates/templates.go b/v2/pkg/templates/templates.go deleted file mode 100644 index e18185520..000000000 --- a/v2/pkg/templates/templates.go +++ /dev/null @@ -1,407 +0,0 @@ -package templates - -import ( - "embed" - "encoding/json" - "fmt" - gofs "io/fs" - "log" - "os" - "path/filepath" - "runtime" - "strings" - - "github.com/go-git/go-git/v5" - "github.com/go-git/go-git/v5/plumbing" - "github.com/pkg/errors" - - "github.com/leaanthony/debme" - "github.com/leaanthony/gosod" - "github.com/wailsapp/wails/v2/internal/fs" - "github.com/wailsapp/wails/v2/pkg/clilogger" -) - -//go:embed all:templates -var templates embed.FS - -//go:embed all:ides/* -var ides embed.FS - -// Cahce for the templates -// We use this because we need different views of the same data -var templateCache []Template = nil - -// Data contains the data we wish to embed during template installation -type Data struct { - ProjectName string - BinaryName string - WailsVersion string - NPMProjectName string - AuthorName string - AuthorEmail string - AuthorNameAndEmail string - WailsDirectory string - GoSDKPath string - WindowsFlags string - CGOEnabled string - OutputFile string -} - -// Options for installing a template -type Options struct { - ProjectName string - TemplateName string - BinaryName string - TargetDir string - Logger *clilogger.CLILogger - PathToDesktopBinary string - PathToServerBinary string - InitGit bool - AuthorName string - AuthorEmail string - IDE string - ProjectNameFilename string // The project name but as a valid filename - WailsVersion string - GoSDKPath string - WindowsFlags string - CGOEnabled string - CGOLDFlags string - OutputFile string -} - -// Template holds data relating to a template -// including the metadata stored in template.json -type Template struct { - // Template details - Name string `json:"name"` - ShortName string `json:"shortname"` - Author string `json:"author"` - Description string `json:"description"` - HelpURL string `json:"helpurl"` - - // Other data - FS gofs.FS `json:"-"` -} - -func parseTemplate(template gofs.FS) (Template, error) { - var result Template - data, err := gofs.ReadFile(template, "template.json") - if err != nil { - return result, errors.Wrap(err, "Error parsing template") - } - err = json.Unmarshal(data, &result) - if err != nil { - return result, err - } - result.FS = template - return result, nil -} - -// List returns the list of available templates -func List() ([]Template, error) { - // If the cache isn't loaded, load it - if templateCache == nil { - err := loadTemplateCache() - if err != nil { - return nil, err - } - } - - return templateCache, nil -} - -// getTemplateByShortname returns the template with the given short name -func getTemplateByShortname(shortname string) (Template, error) { - var result Template - - // If the cache isn't loaded, load it - if templateCache == nil { - err := loadTemplateCache() - if err != nil { - return result, err - } - } - - for _, template := range templateCache { - if template.ShortName == shortname { - return template, nil - } - } - - return result, fmt.Errorf("shortname '%s' is not a valid template shortname", shortname) -} - -// Loads the template cache -func loadTemplateCache() error { - templatesFS, err := debme.FS(templates, "templates") - if err != nil { - return err - } - - // Get directories - files, err := templatesFS.ReadDir(".") - if err != nil { - return err - } - - // Reset cache - templateCache = []Template{} - - for _, file := range files { - if file.IsDir() { - templateFS, err := templatesFS.FS(file.Name()) - if err != nil { - return err - } - template, err := parseTemplate(templateFS) - if err != nil { - // Cannot parse this template, continue - continue - } - templateCache = append(templateCache, template) - } - } - - return nil -} - -// Install the given template. Returns true if the template is remote. -func Install(options *Options) (bool, *Template, error) { - // Get cwd - cwd, err := os.Getwd() - if err != nil { - return false, nil, err - } - - // Did the user want to install in current directory? - if options.TargetDir == "" { - options.TargetDir = filepath.Join(cwd, options.ProjectName) - if fs.DirExists(options.TargetDir) { - return false, nil, fmt.Errorf("cannot create project directory. Dir exists: %s", options.TargetDir) - } - } else { - // Get the absolute path of the given directory - targetDir, err := filepath.Abs(options.TargetDir) - if err != nil { - return false, nil, err - } - options.TargetDir = targetDir - if fs.DirExists(options.TargetDir) { - // Check if directory is non-empty - entries, err := os.ReadDir(options.TargetDir) - if err != nil { - return false, nil, err - } - if len(entries) > 0 { - return false, nil, fmt.Errorf("cannot initialise project in non-empty directory: %s", options.TargetDir) - } - } else { - err := fs.Mkdir(options.TargetDir) - if err != nil { - return false, nil, err - } - } - } - - // Flag to indicate remote template - remoteTemplate := false - - // Is this a shortname? - template, err := getTemplateByShortname(options.TemplateName) - if err != nil { - // Is this a filepath? - templatePath, err := filepath.Abs(options.TemplateName) - if fs.DirExists(templatePath) { - templateFS := os.DirFS(templatePath) - template, err = parseTemplate(templateFS) - if err != nil { - return false, nil, errors.Wrap(err, "Error installing template") - } - } else { - // git clone to temporary dir - tempdir, err := gitclone(options) - defer func(path string) { - err := os.RemoveAll(path) - if err != nil { - log.Fatal(err) - } - }(tempdir) - if err != nil { - return false, nil, err - } - // Remove the .git directory - err = os.RemoveAll(filepath.Join(tempdir, ".git")) - if err != nil { - return false, nil, err - } - - templateFS := os.DirFS(tempdir) - template, err = parseTemplate(templateFS) - if err != nil { - return false, nil, err - } - remoteTemplate = true - } - } - - // Use Gosod to install the template - installer := gosod.New(template.FS) - - // Ignore template.json files - installer.IgnoreFile("template.json") - - // Setup the data. - // We use the directory name for the binary name, like Go - BinaryName := filepath.Base(options.TargetDir) - NPMProjectName := strings.ToLower(strings.ReplaceAll(BinaryName, " ", "")) - localWailsDirectory := fs.RelativePath("../../../../../..") - - templateData := &Data{ - ProjectName: options.ProjectName, - BinaryName: filepath.Base(options.TargetDir), - NPMProjectName: NPMProjectName, - WailsDirectory: localWailsDirectory, - AuthorEmail: options.AuthorEmail, - AuthorName: options.AuthorName, - WailsVersion: options.WailsVersion, - GoSDKPath: options.GoSDKPath, - } - - // Create a formatted name and email combo. - if options.AuthorName != "" { - templateData.AuthorNameAndEmail = options.AuthorName + " " - } - if options.AuthorEmail != "" { - templateData.AuthorNameAndEmail += "<" + options.AuthorEmail + ">" - } - templateData.AuthorNameAndEmail = strings.TrimSpace(templateData.AuthorNameAndEmail) - - installer.RenameFiles(map[string]string{ - "gitignore.txt": ".gitignore", - }) - - // Extract the template - err = installer.Extract(options.TargetDir, templateData) - if err != nil { - return false, nil, err - } - - err = generateIDEFiles(options) - if err != nil { - return false, nil, err - } - - return remoteTemplate, &template, nil -} - -// Clones the given uri and returns the temporary cloned directory -func gitclone(options *Options) (string, error) { - // Create temporary directory - dirname, err := os.MkdirTemp("", "wails-template-*") - if err != nil { - return "", err - } - - // Parse remote template url and version number - templateInfo := strings.Split(options.TemplateName, "@") - cloneOption := &git.CloneOptions{ - URL: templateInfo[0], - } - if len(templateInfo) > 1 { - cloneOption.ReferenceName = plumbing.NewTagReferenceName(templateInfo[1]) - } - - _, err = git.PlainClone(dirname, false, cloneOption) - - return dirname, err -} - -func generateIDEFiles(options *Options) error { - switch options.IDE { - case "vscode": - return generateVSCodeFiles(options) - case "goland": - return generateGolandFiles(options) - } - - return nil -} - -type ideOptions struct { - name string - targetDir string - options *Options - renameFiles map[string]string - ignoredFiles []string -} - -func generateGolandFiles(options *Options) error { - ideoptions := ideOptions{ - name: "goland", - targetDir: filepath.Join(options.TargetDir, ".idea"), - options: options, - renameFiles: map[string]string{ - "projectname.iml": options.ProjectNameFilename + ".iml", - "gitignore.txt": ".gitignore", - "name": ".name", - }, - } - if !options.InitGit { - ideoptions.ignoredFiles = []string{"vcs.xml"} - } - err := installIDEFiles(ideoptions) - if err != nil { - return errors.Wrap(err, "generating Goland IDE files") - } - - return nil -} - -func generateVSCodeFiles(options *Options) error { - ideoptions := ideOptions{ - name: "vscode", - targetDir: filepath.Join(options.TargetDir, ".vscode"), - options: options, - } - return installIDEFiles(ideoptions) -} - -func installIDEFiles(o ideOptions) error { - source, err := debme.FS(ides, "ides/"+o.name) - if err != nil { - return err - } - - // Use gosod to install the template - installer := gosod.New(source) - - if o.renameFiles != nil { - installer.RenameFiles(o.renameFiles) - } - - for _, ignoreFile := range o.ignoredFiles { - installer.IgnoreFile(ignoreFile) - } - - binaryName := filepath.Base(o.options.TargetDir) - o.options.WindowsFlags = "" - o.options.CGOEnabled = "1" - - switch runtime.GOOS { - case "windows": - binaryName += ".exe" - o.options.WindowsFlags = " -H windowsgui" - o.options.CGOEnabled = "0" - case "darwin": - o.options.CGOLDFlags = "-framework UniformTypeIdentifiers" - } - - o.options.PathToDesktopBinary = filepath.ToSlash(filepath.Join("build", "bin", binaryName)) - - err = installer.Extract(o.targetDir, o.options) - if err != nil { - return err - } - - return nil -} diff --git a/v2/pkg/templates/templates/lit-ts/.gitignore.tmpl b/v2/pkg/templates/templates/lit-ts/.gitignore.tmpl deleted file mode 100644 index 129d52294..000000000 --- a/v2/pkg/templates/templates/lit-ts/.gitignore.tmpl +++ /dev/null @@ -1,3 +0,0 @@ -build/bin -node_modules -frontend/dist diff --git a/v2/pkg/templates/templates/lit-ts/README.md b/v2/pkg/templates/templates/lit-ts/README.md deleted file mode 100644 index 98d4d0447..000000000 --- a/v2/pkg/templates/templates/lit-ts/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# README - -## About - -This is the official Wails Lit-TS template. - -You can configure the project by editing `wails.json`. More information about the project settings can be found -here: https://wails.io/docs/reference/project-config - -## Live Development - -To run in live development mode, run `wails dev` in the project directory. This will run a Vite development -server that will provide very fast hot reload of your frontend changes. If you want to develop in a browser -and have access to your Go methods, there is also a dev server that runs on http://localhost:34115. Connect -to this in your browser, and you can call your Go code from devtools. - -## Building - -To build a redistributable, production mode package, use `wails build`. diff --git a/v2/pkg/templates/templates/lit-ts/app.tmpl.go b/v2/pkg/templates/templates/lit-ts/app.tmpl.go deleted file mode 100644 index af53038a1..000000000 --- a/v2/pkg/templates/templates/lit-ts/app.tmpl.go +++ /dev/null @@ -1,27 +0,0 @@ -package main - -import ( - "context" - "fmt" -) - -// App struct -type App struct { - ctx context.Context -} - -// NewApp creates a new App application struct -func NewApp() *App { - return &App{} -} - -// startup is called when the app starts. The context is saved -// so we can call the runtime methods -func (a *App) startup(ctx context.Context) { - a.ctx = ctx -} - -// Greet returns a greeting for the given name -func (a *App) Greet(name string) string { - return fmt.Sprintf("Hello %s, It's show time!", name) -} diff --git a/v2/pkg/templates/templates/lit-ts/frontend/.gitignore.tmpl b/v2/pkg/templates/templates/lit-ts/frontend/.gitignore.tmpl deleted file mode 100644 index a547bf36d..000000000 --- a/v2/pkg/templates/templates/lit-ts/frontend/.gitignore.tmpl +++ /dev/null @@ -1,24 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -dist-ssr -*.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? diff --git a/v2/pkg/templates/templates/lit-ts/frontend/dist/gitkeep b/v2/pkg/templates/templates/lit-ts/frontend/dist/gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/v2/pkg/templates/templates/lit-ts/frontend/index.tmpl.html b/v2/pkg/templates/templates/lit-ts/frontend/index.tmpl.html deleted file mode 100644 index febcb76cb..000000000 --- a/v2/pkg/templates/templates/lit-ts/frontend/index.tmpl.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - {{.ProjectName}} - - - - - - - diff --git a/v2/pkg/templates/templates/lit-ts/frontend/package.json b/v2/pkg/templates/templates/lit-ts/frontend/package.json deleted file mode 100644 index 01aa1512c..000000000 --- a/v2/pkg/templates/templates/lit-ts/frontend/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "frontend", - "private": true, - "version": "0.0.0", - "type": "module", - "main": "dist/my-element.es.js", - "exports": { - ".": "./dist/my-element.es.js" - }, - "types": "types/my-element.d.ts", - "files": [ - "dist", - "types" - ], - "scripts": { - "dev": "vite", - "build": "tsc && vite build" - }, - "dependencies": { - "lit": "^2.2.8" - }, - "devDependencies": { - "typescript": "^4.6.4", - "vite": "^3.0.7" - } -} \ No newline at end of file diff --git a/v2/pkg/templates/templates/lit-ts/frontend/src/assets/fonts/OFL.txt b/v2/pkg/templates/templates/lit-ts/frontend/src/assets/fonts/OFL.txt deleted file mode 100644 index 9cac04ce8..000000000 --- a/v2/pkg/templates/templates/lit-ts/frontend/src/assets/fonts/OFL.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com), - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/v2/pkg/templates/templates/lit-ts/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 b/v2/pkg/templates/templates/lit-ts/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 deleted file mode 100644 index 2f9cc5964..000000000 Binary files a/v2/pkg/templates/templates/lit-ts/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 and /dev/null differ diff --git a/v2/pkg/templates/templates/lit-ts/frontend/src/assets/images/logo-universal.png b/v2/pkg/templates/templates/lit-ts/frontend/src/assets/images/logo-universal.png deleted file mode 100644 index b1224ec79..000000000 Binary files a/v2/pkg/templates/templates/lit-ts/frontend/src/assets/images/logo-universal.png and /dev/null differ diff --git a/v2/pkg/templates/templates/lit-ts/frontend/src/my-element.ts b/v2/pkg/templates/templates/lit-ts/frontend/src/my-element.ts deleted file mode 100644 index af4e9ce20..000000000 --- a/v2/pkg/templates/templates/lit-ts/frontend/src/my-element.ts +++ /dev/null @@ -1,103 +0,0 @@ -import {css, html, LitElement} from 'lit' -import logo from './assets/images/logo-universal.png' -import {Greet} from "../wailsjs/go/main/App"; -import {customElement, property} from 'lit/decorators.js' -import './style.css'; - -/** - * An example element. - * - * @slot - This element has a slot - * @csspart button - The button - */ -@customElement('my-element') -export class MyElement extends LitElement { - static styles = css` - #logo { - display: block; - width: 50%; - height: 50%; - margin: auto; - padding: 10% 0 0; - background-position: center; - background-repeat: no-repeat; - background-size: 100% 100%; - background-origin: content-box; - } - - .result { - height: 20px; - line-height: 20px; - margin: 1.5rem auto; - } - - .input-box .btn { - width: 60px; - height: 30px; - line-height: 30px; - border-radius: 3px; - border: none; - margin: 0 0 0 20px; - padding: 0 8px; - cursor: pointer; - } - - .input-box .btn:hover { - background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%); - color: #333333; - } - - .input-box .input { - border: none; - border-radius: 3px; - outline: none; - height: 30px; - line-height: 30px; - padding: 0 10px; - background-color: rgba(240, 240, 240, 1); - -webkit-font-smoothing: antialiased; - } - - .input-box .input:hover { - border: none; - background-color: rgba(255, 255, 255, 1); - } - - .input-box .input:focus { - border: none; - background-color: rgba(255, 255, 255, 1); - } - - ` - - @property() - resultText = "Please enter your name below 👇" - - greet() { - let thisName = (this.shadowRoot?.getElementById('name') as HTMLInputElement)?.value; - if (thisName) { - Greet(thisName).then(result => { - this.resultText = result - }); - } - } - - render() { - return html` -
- -
${this.resultText}
-
- - -
-
- ` - } -} - -declare global { - interface HTMLElementTagNameMap { - 'my-element': MyElement - } -} \ No newline at end of file diff --git a/v2/pkg/templates/templates/lit-ts/frontend/src/style.css b/v2/pkg/templates/templates/lit-ts/frontend/src/style.css deleted file mode 100644 index 3940d6c63..000000000 --- a/v2/pkg/templates/templates/lit-ts/frontend/src/style.css +++ /dev/null @@ -1,26 +0,0 @@ -html { - background-color: rgba(27, 38, 54, 1); - text-align: center; - color: white; -} - -body { - margin: 0; - color: white; - font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", - "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", - sans-serif; -} - -@font-face { - font-family: "Nunito"; - font-style: normal; - font-weight: 400; - src: local(""), - url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2"); -} - -#app { - height: 100vh; - text-align: center; -} diff --git a/v2/pkg/templates/templates/lit-ts/frontend/src/vite-env.d.ts b/v2/pkg/templates/templates/lit-ts/frontend/src/vite-env.d.ts deleted file mode 100644 index 11f02fe2a..000000000 --- a/v2/pkg/templates/templates/lit-ts/frontend/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/v2/pkg/templates/templates/lit-ts/frontend/tsconfig.json b/v2/pkg/templates/templates/lit-ts/frontend/tsconfig.json deleted file mode 100644 index a28678589..000000000 --- a/v2/pkg/templates/templates/lit-ts/frontend/tsconfig.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "module": "ESNext", - "lib": [ - "ES2020", - "DOM", - "DOM.Iterable" - ], - "declaration": true, - "emitDeclarationOnly": true, - "outDir": "./types", - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "moduleResolution": "Node", - "isolatedModules": true, - "allowSyntheticDefaultImports": true, - "experimentalDecorators": true, - "forceConsistentCasingInFileNames": true, - "useDefineForClassFields": false, - "skipLibCheck": true - }, - "include": [ - "src/**/*.ts" - ], - "references": [ - { - "path": "./tsconfig.node.json" - } - ] -} diff --git a/v2/pkg/templates/templates/lit-ts/frontend/tsconfig.node.json b/v2/pkg/templates/templates/lit-ts/frontend/tsconfig.node.json deleted file mode 100644 index b8afcc8fa..000000000 --- a/v2/pkg/templates/templates/lit-ts/frontend/tsconfig.node.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "module": "ESNext", - "moduleResolution": "Node", - "allowSyntheticDefaultImports": true - }, - "include": [ - "vite.config.ts" - ] -} diff --git a/v2/pkg/templates/templates/lit-ts/frontend/vite.config.ts b/v2/pkg/templates/templates/lit-ts/frontend/vite.config.ts deleted file mode 100644 index bbb7f5889..000000000 --- a/v2/pkg/templates/templates/lit-ts/frontend/vite.config.ts +++ /dev/null @@ -1,4 +0,0 @@ -import {defineConfig} from 'vite' - -// https://vitejs.dev/config/ -export default defineConfig({}) diff --git a/v2/pkg/templates/templates/lit-ts/frontend/wailsjs/go/main/App.d.ts b/v2/pkg/templates/templates/lit-ts/frontend/wailsjs/go/main/App.d.ts deleted file mode 100644 index 43173cfce..000000000 --- a/v2/pkg/templates/templates/lit-ts/frontend/wailsjs/go/main/App.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Greet(arg1: string): Promise; diff --git a/v2/pkg/templates/templates/lit-ts/frontend/wailsjs/go/main/App.js b/v2/pkg/templates/templates/lit-ts/frontend/wailsjs/go/main/App.js deleted file mode 100644 index 0ee085c95..000000000 --- a/v2/pkg/templates/templates/lit-ts/frontend/wailsjs/go/main/App.js +++ /dev/null @@ -1,7 +0,0 @@ -// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Greet(arg1) { - return window['go']['main']['App']['Greet'](arg1); -} diff --git a/v2/pkg/templates/templates/lit-ts/frontend/wailsjs/runtime/package.json b/v2/pkg/templates/templates/lit-ts/frontend/wailsjs/runtime/package.json deleted file mode 100644 index 1e7c8a5d7..000000000 --- a/v2/pkg/templates/templates/lit-ts/frontend/wailsjs/runtime/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "@wailsapp/runtime", - "version": "2.0.0", - "description": "Wails Javascript runtime library", - "main": "runtime.js", - "types": "runtime.d.ts", - "scripts": { - }, - "repository": { - "type": "git", - "url": "git+https://github.com/wailsapp/wails.git" - }, - "keywords": [ - "Wails", - "Javascript", - "Go" - ], - "author": "Lea Anthony ", - "license": "MIT", - "bugs": { - "url": "https://github.com/wailsapp/wails/issues" - }, - "homepage": "https://github.com/wailsapp/wails#readme" -} diff --git a/v2/pkg/templates/templates/lit-ts/frontend/wailsjs/runtime/runtime.d.ts b/v2/pkg/templates/templates/lit-ts/frontend/wailsjs/runtime/runtime.d.ts deleted file mode 100644 index 336fb07aa..000000000 --- a/v2/pkg/templates/templates/lit-ts/frontend/wailsjs/runtime/runtime.d.ts +++ /dev/null @@ -1,211 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export interface Position { - x: number; - y: number; -} - -export interface Size { - w: number; - h: number; -} - -export interface Screen { - isCurrent: boolean; - isPrimary: boolean; - width: number - height: number -} - -// Environment information such as platform, buildtype, ... -export interface EnvironmentInfo { - buildType: string; - platform: string; - arch: string; -} - -// [EventsEmit](https://wails.io/docs/reference/runtime/events#eventsemit) -// emits the given event. Optional data may be passed with the event. -// This will trigger any event listeners. -export function EventsEmit(eventName: string, ...data: any): void; - -// [EventsOn](https://wails.io/docs/reference/runtime/events#eventson) sets up a listener for the given event name. -export function EventsOn(eventName: string, callback: (...data: any) => void): void; - -// [EventsOnMultiple](https://wails.io/docs/reference/runtime/events#eventsonmultiple) -// sets up a listener for the given event name, but will only trigger a given number times. -export function EventsOnMultiple(eventName: string, callback: (...data: any) => void, maxCallbacks: number): void; - -// [EventsOnce](https://wails.io/docs/reference/runtime/events#eventsonce) -// sets up a listener for the given event name, but will only trigger once. -export function EventsOnce(eventName: string, callback: (...data: any) => void): void; - -// [EventsOff](https://wails.io/docs/reference/runtime/events#eventsff) -// unregisters the listener for the given event name. -export function EventsOff(eventName: string): void; - -// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) -// unregisters all event listeners. -export function EventsOffAll(): void; - -// [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) -// logs the given message as a raw message -export function LogPrint(message: string): void; - -// [LogTrace](https://wails.io/docs/reference/runtime/log#logtrace) -// logs the given message at the `trace` log level. -export function LogTrace(message: string): void; - -// [LogDebug](https://wails.io/docs/reference/runtime/log#logdebug) -// logs the given message at the `debug` log level. -export function LogDebug(message: string): void; - -// [LogError](https://wails.io/docs/reference/runtime/log#logerror) -// logs the given message at the `error` log level. -export function LogError(message: string): void; - -// [LogFatal](https://wails.io/docs/reference/runtime/log#logfatal) -// logs the given message at the `fatal` log level. -// The application will quit after calling this method. -export function LogFatal(message: string): void; - -// [LogInfo](https://wails.io/docs/reference/runtime/log#loginfo) -// logs the given message at the `info` log level. -export function LogInfo(message: string): void; - -// [LogWarning](https://wails.io/docs/reference/runtime/log#logwarning) -// logs the given message at the `warning` log level. -export function LogWarning(message: string): void; - -// [WindowReload](https://wails.io/docs/reference/runtime/window#windowreload) -// Forces a reload by the main application as well as connected browsers. -export function WindowReload(): void; - -// [WindowReloadApp](https://wails.io/docs/reference/runtime/window#windowreloadapp) -// Reloads the application frontend. -export function WindowReloadApp(): void; - -// [WindowSetAlwaysOnTop](https://wails.io/docs/reference/runtime/window#windowsetalwaysontop) -// Sets the window AlwaysOnTop or not on top. -export function WindowSetAlwaysOnTop(b: boolean): void; - -// [WindowSetSystemDefaultTheme](https://wails.io/docs/next/reference/runtime/window#windowsetsystemdefaulttheme) -// *Windows only* -// Sets window theme to system default (dark/light). -export function WindowSetSystemDefaultTheme(): void; - -// [WindowSetLightTheme](https://wails.io/docs/next/reference/runtime/window#windowsetlighttheme) -// *Windows only* -// Sets window to light theme. -export function WindowSetLightTheme(): void; - -// [WindowSetDarkTheme](https://wails.io/docs/next/reference/runtime/window#windowsetdarktheme) -// *Windows only* -// Sets window to dark theme. -export function WindowSetDarkTheme(): void; - -// [WindowCenter](https://wails.io/docs/reference/runtime/window#windowcenter) -// Centers the window on the monitor the window is currently on. -export function WindowCenter(): void; - -// [WindowSetTitle](https://wails.io/docs/reference/runtime/window#windowsettitle) -// Sets the text in the window title bar. -export function WindowSetTitle(title: string): void; - -// [WindowFullscreen](https://wails.io/docs/reference/runtime/window#windowfullscreen) -// Makes the window full screen. -export function WindowFullscreen(): void; - -// [WindowUnfullscreen](https://wails.io/docs/reference/runtime/window#windowunfullscreen) -// Restores the previous window dimensions and position prior to full screen. -export function WindowUnfullscreen(): void; - -// [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize) -// Sets the width and height of the window. -export function WindowSetSize(width: number, height: number): void; - -// [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize) -// Gets the width and height of the window. -export function WindowGetSize(): Promise; - -// [WindowSetMaxSize](https://wails.io/docs/reference/runtime/window#windowsetmaxsize) -// Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMaxSize(width: number, height: number): void; - -// [WindowSetMinSize](https://wails.io/docs/reference/runtime/window#windowsetminsize) -// Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMinSize(width: number, height: number): void; - -// [WindowSetPosition](https://wails.io/docs/reference/runtime/window#windowsetposition) -// Sets the window position relative to the monitor the window is currently on. -export function WindowSetPosition(x: number, y: number): void; - -// [WindowGetPosition](https://wails.io/docs/reference/runtime/window#windowgetposition) -// Gets the window position relative to the monitor the window is currently on. -export function WindowGetPosition(): Promise; - -// [WindowHide](https://wails.io/docs/reference/runtime/window#windowhide) -// Hides the window. -export function WindowHide(): void; - -// [WindowShow](https://wails.io/docs/reference/runtime/window#windowshow) -// Shows the window, if it is currently hidden. -export function WindowShow(): void; - -// [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise) -// Maximises the window to fill the screen. -export function WindowMaximise(): void; - -// [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise) -// Toggles between Maximised and UnMaximised. -export function WindowToggleMaximise(): void; - -// [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise) -// Restores the window to the dimensions and position prior to maximising. -export function WindowUnmaximise(): void; - -// [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise) -// Minimises the window. -export function WindowMinimise(): void; - -// [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise) -// Restores the window to the dimensions and position prior to minimising. -export function WindowUnminimise(): void; - -// [WindowSetBackgroundColour](https://wails.io/docs/reference/runtime/window#windowsetbackgroundcolour) -// Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels. -export function WindowSetBackgroundColour(R: number, G: number, B: number, A: number): void; - -// [ScreenGetAll](https://wails.io/docs/reference/runtime/window#screengetall) -// Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system. -export function ScreenGetAll(): Promise; - -// [BrowserOpenURL](https://wails.io/docs/reference/runtime/browser#browseropenurl) -// Opens the given URL in the system browser. -export function BrowserOpenURL(url: string): void; - -// [Environment](https://wails.io/docs/reference/runtime/intro#environment) -// Returns information about the environment -export function Environment(): Promise; - -// [Quit](https://wails.io/docs/reference/runtime/intro#quit) -// Quits the application. -export function Quit(): void; - -// [Hide](https://wails.io/docs/reference/runtime/intro#hide) -// Hides the application. -export function Hide(): void; - -// [Show](https://wails.io/docs/reference/runtime/intro#show) -// Shows the application. -export function Show(): void; diff --git a/v2/pkg/templates/templates/lit-ts/frontend/wailsjs/runtime/runtime.js b/v2/pkg/templates/templates/lit-ts/frontend/wailsjs/runtime/runtime.js deleted file mode 100644 index b5ae16d56..000000000 --- a/v2/pkg/templates/templates/lit-ts/frontend/wailsjs/runtime/runtime.js +++ /dev/null @@ -1,182 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export function LogPrint(message) { - window.runtime.LogPrint(message); -} - -export function LogTrace(message) { - window.runtime.LogTrace(message); -} - -export function LogDebug(message) { - window.runtime.LogDebug(message); -} - -export function LogInfo(message) { - window.runtime.LogInfo(message); -} - -export function LogWarning(message) { - window.runtime.LogWarning(message); -} - -export function LogError(message) { - window.runtime.LogError(message); -} - -export function LogFatal(message) { - window.runtime.LogFatal(message); -} - -export function EventsOnMultiple(eventName, callback, maxCallbacks) { - window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks); -} - -export function EventsOn(eventName, callback) { - EventsOnMultiple(eventName, callback, -1); -} - -export function EventsOff(eventName) { - return window.runtime.EventsOff(eventName); -} - -export function EventsOffAll() { - return window.runtime.EventsOffAll(); -} - -export function EventsOnce(eventName, callback) { - EventsOnMultiple(eventName, callback, 1); -} - -export function EventsEmit(eventName) { - let args = [eventName].slice.call(arguments); - return window.runtime.EventsEmit.apply(null, args); -} - -export function WindowReload() { - window.runtime.WindowReload(); -} - -export function WindowReloadApp() { - window.runtime.WindowReloadApp(); -} - -export function WindowSetAlwaysOnTop(b) { - window.runtime.WindowSetAlwaysOnTop(b); -} - -export function WindowSetSystemDefaultTheme() { - window.runtime.WindowSetSystemDefaultTheme(); -} - -export function WindowSetLightTheme() { - window.runtime.WindowSetLightTheme(); -} - -export function WindowSetDarkTheme() { - window.runtime.WindowSetDarkTheme(); -} - -export function WindowCenter() { - window.runtime.WindowCenter(); -} - -export function WindowSetTitle(title) { - window.runtime.WindowSetTitle(title); -} - -export function WindowFullscreen() { - window.runtime.WindowFullscreen(); -} - -export function WindowUnfullscreen() { - window.runtime.WindowUnfullscreen(); -} - -export function WindowGetSize() { - return window.runtime.WindowGetSize(); -} - -export function WindowSetSize(width, height) { - window.runtime.WindowSetSize(width, height); -} - -export function WindowSetMaxSize(width, height) { - window.runtime.WindowSetMaxSize(width, height); -} - -export function WindowSetMinSize(width, height) { - window.runtime.WindowSetMinSize(width, height); -} - -export function WindowSetPosition(x, y) { - window.runtime.WindowSetPosition(x, y); -} - -export function WindowGetPosition() { - return window.runtime.WindowGetPosition(); -} - -export function WindowHide() { - window.runtime.WindowHide(); -} - -export function WindowShow() { - window.runtime.WindowShow(); -} - -export function WindowMaximise() { - window.runtime.WindowMaximise(); -} - -export function WindowToggleMaximise() { - window.runtime.WindowToggleMaximise(); -} - -export function WindowUnmaximise() { - window.runtime.WindowUnmaximise(); -} - -export function WindowMinimise() { - window.runtime.WindowMinimise(); -} - -export function WindowUnminimise() { - window.runtime.WindowUnminimise(); -} - -export function WindowSetBackgroundColour(R, G, B, A) { - window.runtime.WindowSetBackgroundColour(R, G, B, A); -} - -export function ScreenGetAll() { - return window.runtime.ScreenGetAll(); -} - -export function BrowserOpenURL(url) { - window.runtime.BrowserOpenURL(url); -} - -export function Environment() { - return window.runtime.Environment(); -} - -export function Quit() { - window.runtime.Quit(); -} - -export function Hide() { - window.runtime.Hide(); -} - -export function Show() { - window.runtime.Show(); -} diff --git a/v2/pkg/templates/templates/lit-ts/go.mod.tmpl b/v2/pkg/templates/templates/lit-ts/go.mod.tmpl deleted file mode 100644 index 4b34d1668..000000000 --- a/v2/pkg/templates/templates/lit-ts/go.mod.tmpl +++ /dev/null @@ -1,7 +0,0 @@ -module changeme - -go 1.23.0 - -require github.com/wailsapp/wails/v2 {{.WailsVersion}} - -// replace github.com/wailsapp/wails/v2 {{.WailsVersion}} => {{.WailsDirectory}} \ No newline at end of file diff --git a/v2/pkg/templates/templates/lit-ts/main.go.tmpl b/v2/pkg/templates/templates/lit-ts/main.go.tmpl deleted file mode 100644 index e24782be3..000000000 --- a/v2/pkg/templates/templates/lit-ts/main.go.tmpl +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import ( - "embed" - - "github.com/wailsapp/wails/v2" - "github.com/wailsapp/wails/v2/pkg/options" - "github.com/wailsapp/wails/v2/pkg/options/assetserver" -) - -//go:embed all:frontend/dist -var assets embed.FS - -func main() { - // Create an instance of the app structure - app := NewApp() - - // Create application with options - err := wails.Run(&options.App{ - Title: "{{.ProjectName}}", - Width: 1024, - Height: 768, - AssetServer: &assetserver.Options{ - Assets: assets, - }, - BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, - OnStartup: app.startup, - Bind: []interface{}{ - app, - }, - }) - - if err != nil { - println("Error:", err.Error()) - } -} diff --git a/v2/pkg/templates/templates/lit-ts/template.json b/v2/pkg/templates/templates/lit-ts/template.json deleted file mode 100644 index 7e9beabb7..000000000 --- a/v2/pkg/templates/templates/lit-ts/template.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "Lit + Vite (Typescript)", - "shortname": "lit-ts", - "author": "Lea Anthony", - "description": "Lit + TS + Vite development server", - "helpurl": "https://wails.io" -} \ No newline at end of file diff --git a/v2/pkg/templates/templates/lit-ts/wails.tmpl.json b/v2/pkg/templates/templates/lit-ts/wails.tmpl.json deleted file mode 100644 index c39b2cb7d..000000000 --- a/v2/pkg/templates/templates/lit-ts/wails.tmpl.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "$schema": "https://wails.io/schemas/config.v2.json", - "name": "{{.ProjectName}}", - "outputfilename": "{{.BinaryName}}", - "frontend:install": "npm install", - "frontend:build": "npm run build", - "frontend:dev:watcher": "npm run dev", - "frontend:dev:serverUrl": "auto", - "author": { - "name": "{{.AuthorName}}", - "email": "{{.AuthorEmail}}" - } -} diff --git a/v2/pkg/templates/templates/lit/.gitignore.tmpl b/v2/pkg/templates/templates/lit/.gitignore.tmpl deleted file mode 100644 index 129d52294..000000000 --- a/v2/pkg/templates/templates/lit/.gitignore.tmpl +++ /dev/null @@ -1,3 +0,0 @@ -build/bin -node_modules -frontend/dist diff --git a/v2/pkg/templates/templates/lit/README.md b/v2/pkg/templates/templates/lit/README.md deleted file mode 100644 index dc8efed65..000000000 --- a/v2/pkg/templates/templates/lit/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# README - -## About - -This is the official Wails Lit template. - -You can configure the project by editing `wails.json`. More information about the project settings can be found -here: https://wails.io/docs/reference/project-config - -## Live Development - -To run in live development mode, run `wails dev` in the project directory. This will run a Vite development -server that will provide very fast hot reload of your frontend changes. If you want to develop in a browser -and have access to your Go methods, there is also a dev server that runs on http://localhost:34115. Connect -to this in your browser, and you can call your Go code from devtools. - -## Building - -To build a redistributable, production mode package, use `wails build`. diff --git a/v2/pkg/templates/templates/lit/app.tmpl.go b/v2/pkg/templates/templates/lit/app.tmpl.go deleted file mode 100644 index af53038a1..000000000 --- a/v2/pkg/templates/templates/lit/app.tmpl.go +++ /dev/null @@ -1,27 +0,0 @@ -package main - -import ( - "context" - "fmt" -) - -// App struct -type App struct { - ctx context.Context -} - -// NewApp creates a new App application struct -func NewApp() *App { - return &App{} -} - -// startup is called when the app starts. The context is saved -// so we can call the runtime methods -func (a *App) startup(ctx context.Context) { - a.ctx = ctx -} - -// Greet returns a greeting for the given name -func (a *App) Greet(name string) string { - return fmt.Sprintf("Hello %s, It's show time!", name) -} diff --git a/v2/pkg/templates/templates/lit/frontend/.gitignore.tmpl b/v2/pkg/templates/templates/lit/frontend/.gitignore.tmpl deleted file mode 100644 index a547bf36d..000000000 --- a/v2/pkg/templates/templates/lit/frontend/.gitignore.tmpl +++ /dev/null @@ -1,24 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -dist-ssr -*.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? diff --git a/v2/pkg/templates/templates/lit/frontend/dist/gitkeep b/v2/pkg/templates/templates/lit/frontend/dist/gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/v2/pkg/templates/templates/lit/frontend/index.tmpl.html b/v2/pkg/templates/templates/lit/frontend/index.tmpl.html deleted file mode 100644 index fbe3eb240..000000000 --- a/v2/pkg/templates/templates/lit/frontend/index.tmpl.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - {{.ProjectName}} - - - - - - - diff --git a/v2/pkg/templates/templates/lit/frontend/package.json b/v2/pkg/templates/templates/lit/frontend/package.json deleted file mode 100644 index 10c9a760e..000000000 --- a/v2/pkg/templates/templates/lit/frontend/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "frontend", - "private": true, - "version": "0.0.0", - "type": "module", - "main": "dist/my-element.es.js", - "exports": { - ".": "./dist/my-element.es.js" - }, - "files": [ - "dist" - ], - "scripts": { - "dev": "vite", - "build": "vite build" - }, - "dependencies": { - "lit": "^2.2.8" - }, - "devDependencies": { - "vite": "^3.0.7" - } -} \ No newline at end of file diff --git a/v2/pkg/templates/templates/lit/frontend/src/assets/fonts/OFL.txt b/v2/pkg/templates/templates/lit/frontend/src/assets/fonts/OFL.txt deleted file mode 100644 index 9cac04ce8..000000000 --- a/v2/pkg/templates/templates/lit/frontend/src/assets/fonts/OFL.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com), - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/v2/pkg/templates/templates/lit/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 b/v2/pkg/templates/templates/lit/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 deleted file mode 100644 index 2f9cc5964..000000000 Binary files a/v2/pkg/templates/templates/lit/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 and /dev/null differ diff --git a/v2/pkg/templates/templates/lit/frontend/src/assets/images/logo-universal.png b/v2/pkg/templates/templates/lit/frontend/src/assets/images/logo-universal.png deleted file mode 100644 index 99ac71f5a..000000000 Binary files a/v2/pkg/templates/templates/lit/frontend/src/assets/images/logo-universal.png and /dev/null differ diff --git a/v2/pkg/templates/templates/lit/frontend/src/my-element.js b/v2/pkg/templates/templates/lit/frontend/src/my-element.js deleted file mode 100644 index 017632c09..000000000 --- a/v2/pkg/templates/templates/lit/frontend/src/my-element.js +++ /dev/null @@ -1,106 +0,0 @@ -import {css, html, LitElement} from 'lit' -import logo from './assets/images/logo-universal.png' -import {Greet} from "../wailsjs/go/main/App"; -import './style.css'; - -/** - * An example element. - * - * @slot - This element has a slot - * @csspart button - The button - */ -export class MyElement extends LitElement { - constructor() { - super() - this.resultText = "Please enter your name below 👇" - } - - static get styles() { - return css` - #logo { - display: block; - width: 50%; - height: 50%; - margin: auto; - padding: 10% 0 0; - background-position: center; - background-repeat: no-repeat; - background-size: 100% 100%; - background-origin: content-box; - } - - .result { - height: 20px; - line-height: 20px; - margin: 1.5rem auto; - } - - .input-box .btn { - width: 60px; - height: 30px; - line-height: 30px; - border-radius: 3px; - border: none; - margin: 0 0 0 20px; - padding: 0 8px; - cursor: pointer; - } - - .input-box .btn:hover { - background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%); - color: #333333; - } - - .input-box .input { - border: none; - border-radius: 3px; - outline: none; - height: 30px; - line-height: 30px; - padding: 0 10px; - background-color: rgba(240, 240, 240, 1); - -webkit-font-smoothing: antialiased; - } - - .input-box .input:hover { - border: none; - background-color: rgba(255, 255, 255, 1); - } - - .input-box .input:focus { - border: none; - background-color: rgba(255, 255, 255, 1); - } - - ` - } - - static get properties() { - return { - resultText: {type: String}, - } - } - - greet() { - let thisName = this.shadowRoot.getElementById('name').value - Greet(thisName).then(result => { - this.resultText = result - }); - } - - render() { - return html` -
- -
${this.resultText}
-
- - -
-
- ` - } - -} - -window.customElements.define('my-element', MyElement) diff --git a/v2/pkg/templates/templates/lit/frontend/src/style.css b/v2/pkg/templates/templates/lit/frontend/src/style.css deleted file mode 100644 index 3940d6c63..000000000 --- a/v2/pkg/templates/templates/lit/frontend/src/style.css +++ /dev/null @@ -1,26 +0,0 @@ -html { - background-color: rgba(27, 38, 54, 1); - text-align: center; - color: white; -} - -body { - margin: 0; - color: white; - font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", - "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", - sans-serif; -} - -@font-face { - font-family: "Nunito"; - font-style: normal; - font-weight: 400; - src: local(""), - url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2"); -} - -#app { - height: 100vh; - text-align: center; -} diff --git a/v2/pkg/templates/templates/lit/frontend/vite.config.js b/v2/pkg/templates/templates/lit/frontend/vite.config.js deleted file mode 100644 index bbb7f5889..000000000 --- a/v2/pkg/templates/templates/lit/frontend/vite.config.js +++ /dev/null @@ -1,4 +0,0 @@ -import {defineConfig} from 'vite' - -// https://vitejs.dev/config/ -export default defineConfig({}) diff --git a/v2/pkg/templates/templates/lit/frontend/wailsjs/go/main/App.d.ts b/v2/pkg/templates/templates/lit/frontend/wailsjs/go/main/App.d.ts deleted file mode 100644 index 43173cfce..000000000 --- a/v2/pkg/templates/templates/lit/frontend/wailsjs/go/main/App.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Greet(arg1: string): Promise; diff --git a/v2/pkg/templates/templates/lit/frontend/wailsjs/go/main/App.js b/v2/pkg/templates/templates/lit/frontend/wailsjs/go/main/App.js deleted file mode 100644 index 0ee085c95..000000000 --- a/v2/pkg/templates/templates/lit/frontend/wailsjs/go/main/App.js +++ /dev/null @@ -1,7 +0,0 @@ -// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Greet(arg1) { - return window['go']['main']['App']['Greet'](arg1); -} diff --git a/v2/pkg/templates/templates/lit/frontend/wailsjs/runtime/package.json b/v2/pkg/templates/templates/lit/frontend/wailsjs/runtime/package.json deleted file mode 100644 index 1e7c8a5d7..000000000 --- a/v2/pkg/templates/templates/lit/frontend/wailsjs/runtime/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "@wailsapp/runtime", - "version": "2.0.0", - "description": "Wails Javascript runtime library", - "main": "runtime.js", - "types": "runtime.d.ts", - "scripts": { - }, - "repository": { - "type": "git", - "url": "git+https://github.com/wailsapp/wails.git" - }, - "keywords": [ - "Wails", - "Javascript", - "Go" - ], - "author": "Lea Anthony ", - "license": "MIT", - "bugs": { - "url": "https://github.com/wailsapp/wails/issues" - }, - "homepage": "https://github.com/wailsapp/wails#readme" -} diff --git a/v2/pkg/templates/templates/lit/frontend/wailsjs/runtime/runtime.d.ts b/v2/pkg/templates/templates/lit/frontend/wailsjs/runtime/runtime.d.ts deleted file mode 100644 index 336fb07aa..000000000 --- a/v2/pkg/templates/templates/lit/frontend/wailsjs/runtime/runtime.d.ts +++ /dev/null @@ -1,211 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export interface Position { - x: number; - y: number; -} - -export interface Size { - w: number; - h: number; -} - -export interface Screen { - isCurrent: boolean; - isPrimary: boolean; - width: number - height: number -} - -// Environment information such as platform, buildtype, ... -export interface EnvironmentInfo { - buildType: string; - platform: string; - arch: string; -} - -// [EventsEmit](https://wails.io/docs/reference/runtime/events#eventsemit) -// emits the given event. Optional data may be passed with the event. -// This will trigger any event listeners. -export function EventsEmit(eventName: string, ...data: any): void; - -// [EventsOn](https://wails.io/docs/reference/runtime/events#eventson) sets up a listener for the given event name. -export function EventsOn(eventName: string, callback: (...data: any) => void): void; - -// [EventsOnMultiple](https://wails.io/docs/reference/runtime/events#eventsonmultiple) -// sets up a listener for the given event name, but will only trigger a given number times. -export function EventsOnMultiple(eventName: string, callback: (...data: any) => void, maxCallbacks: number): void; - -// [EventsOnce](https://wails.io/docs/reference/runtime/events#eventsonce) -// sets up a listener for the given event name, but will only trigger once. -export function EventsOnce(eventName: string, callback: (...data: any) => void): void; - -// [EventsOff](https://wails.io/docs/reference/runtime/events#eventsff) -// unregisters the listener for the given event name. -export function EventsOff(eventName: string): void; - -// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) -// unregisters all event listeners. -export function EventsOffAll(): void; - -// [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) -// logs the given message as a raw message -export function LogPrint(message: string): void; - -// [LogTrace](https://wails.io/docs/reference/runtime/log#logtrace) -// logs the given message at the `trace` log level. -export function LogTrace(message: string): void; - -// [LogDebug](https://wails.io/docs/reference/runtime/log#logdebug) -// logs the given message at the `debug` log level. -export function LogDebug(message: string): void; - -// [LogError](https://wails.io/docs/reference/runtime/log#logerror) -// logs the given message at the `error` log level. -export function LogError(message: string): void; - -// [LogFatal](https://wails.io/docs/reference/runtime/log#logfatal) -// logs the given message at the `fatal` log level. -// The application will quit after calling this method. -export function LogFatal(message: string): void; - -// [LogInfo](https://wails.io/docs/reference/runtime/log#loginfo) -// logs the given message at the `info` log level. -export function LogInfo(message: string): void; - -// [LogWarning](https://wails.io/docs/reference/runtime/log#logwarning) -// logs the given message at the `warning` log level. -export function LogWarning(message: string): void; - -// [WindowReload](https://wails.io/docs/reference/runtime/window#windowreload) -// Forces a reload by the main application as well as connected browsers. -export function WindowReload(): void; - -// [WindowReloadApp](https://wails.io/docs/reference/runtime/window#windowreloadapp) -// Reloads the application frontend. -export function WindowReloadApp(): void; - -// [WindowSetAlwaysOnTop](https://wails.io/docs/reference/runtime/window#windowsetalwaysontop) -// Sets the window AlwaysOnTop or not on top. -export function WindowSetAlwaysOnTop(b: boolean): void; - -// [WindowSetSystemDefaultTheme](https://wails.io/docs/next/reference/runtime/window#windowsetsystemdefaulttheme) -// *Windows only* -// Sets window theme to system default (dark/light). -export function WindowSetSystemDefaultTheme(): void; - -// [WindowSetLightTheme](https://wails.io/docs/next/reference/runtime/window#windowsetlighttheme) -// *Windows only* -// Sets window to light theme. -export function WindowSetLightTheme(): void; - -// [WindowSetDarkTheme](https://wails.io/docs/next/reference/runtime/window#windowsetdarktheme) -// *Windows only* -// Sets window to dark theme. -export function WindowSetDarkTheme(): void; - -// [WindowCenter](https://wails.io/docs/reference/runtime/window#windowcenter) -// Centers the window on the monitor the window is currently on. -export function WindowCenter(): void; - -// [WindowSetTitle](https://wails.io/docs/reference/runtime/window#windowsettitle) -// Sets the text in the window title bar. -export function WindowSetTitle(title: string): void; - -// [WindowFullscreen](https://wails.io/docs/reference/runtime/window#windowfullscreen) -// Makes the window full screen. -export function WindowFullscreen(): void; - -// [WindowUnfullscreen](https://wails.io/docs/reference/runtime/window#windowunfullscreen) -// Restores the previous window dimensions and position prior to full screen. -export function WindowUnfullscreen(): void; - -// [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize) -// Sets the width and height of the window. -export function WindowSetSize(width: number, height: number): void; - -// [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize) -// Gets the width and height of the window. -export function WindowGetSize(): Promise; - -// [WindowSetMaxSize](https://wails.io/docs/reference/runtime/window#windowsetmaxsize) -// Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMaxSize(width: number, height: number): void; - -// [WindowSetMinSize](https://wails.io/docs/reference/runtime/window#windowsetminsize) -// Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMinSize(width: number, height: number): void; - -// [WindowSetPosition](https://wails.io/docs/reference/runtime/window#windowsetposition) -// Sets the window position relative to the monitor the window is currently on. -export function WindowSetPosition(x: number, y: number): void; - -// [WindowGetPosition](https://wails.io/docs/reference/runtime/window#windowgetposition) -// Gets the window position relative to the monitor the window is currently on. -export function WindowGetPosition(): Promise; - -// [WindowHide](https://wails.io/docs/reference/runtime/window#windowhide) -// Hides the window. -export function WindowHide(): void; - -// [WindowShow](https://wails.io/docs/reference/runtime/window#windowshow) -// Shows the window, if it is currently hidden. -export function WindowShow(): void; - -// [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise) -// Maximises the window to fill the screen. -export function WindowMaximise(): void; - -// [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise) -// Toggles between Maximised and UnMaximised. -export function WindowToggleMaximise(): void; - -// [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise) -// Restores the window to the dimensions and position prior to maximising. -export function WindowUnmaximise(): void; - -// [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise) -// Minimises the window. -export function WindowMinimise(): void; - -// [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise) -// Restores the window to the dimensions and position prior to minimising. -export function WindowUnminimise(): void; - -// [WindowSetBackgroundColour](https://wails.io/docs/reference/runtime/window#windowsetbackgroundcolour) -// Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels. -export function WindowSetBackgroundColour(R: number, G: number, B: number, A: number): void; - -// [ScreenGetAll](https://wails.io/docs/reference/runtime/window#screengetall) -// Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system. -export function ScreenGetAll(): Promise; - -// [BrowserOpenURL](https://wails.io/docs/reference/runtime/browser#browseropenurl) -// Opens the given URL in the system browser. -export function BrowserOpenURL(url: string): void; - -// [Environment](https://wails.io/docs/reference/runtime/intro#environment) -// Returns information about the environment -export function Environment(): Promise; - -// [Quit](https://wails.io/docs/reference/runtime/intro#quit) -// Quits the application. -export function Quit(): void; - -// [Hide](https://wails.io/docs/reference/runtime/intro#hide) -// Hides the application. -export function Hide(): void; - -// [Show](https://wails.io/docs/reference/runtime/intro#show) -// Shows the application. -export function Show(): void; diff --git a/v2/pkg/templates/templates/lit/frontend/wailsjs/runtime/runtime.js b/v2/pkg/templates/templates/lit/frontend/wailsjs/runtime/runtime.js deleted file mode 100644 index b5ae16d56..000000000 --- a/v2/pkg/templates/templates/lit/frontend/wailsjs/runtime/runtime.js +++ /dev/null @@ -1,182 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export function LogPrint(message) { - window.runtime.LogPrint(message); -} - -export function LogTrace(message) { - window.runtime.LogTrace(message); -} - -export function LogDebug(message) { - window.runtime.LogDebug(message); -} - -export function LogInfo(message) { - window.runtime.LogInfo(message); -} - -export function LogWarning(message) { - window.runtime.LogWarning(message); -} - -export function LogError(message) { - window.runtime.LogError(message); -} - -export function LogFatal(message) { - window.runtime.LogFatal(message); -} - -export function EventsOnMultiple(eventName, callback, maxCallbacks) { - window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks); -} - -export function EventsOn(eventName, callback) { - EventsOnMultiple(eventName, callback, -1); -} - -export function EventsOff(eventName) { - return window.runtime.EventsOff(eventName); -} - -export function EventsOffAll() { - return window.runtime.EventsOffAll(); -} - -export function EventsOnce(eventName, callback) { - EventsOnMultiple(eventName, callback, 1); -} - -export function EventsEmit(eventName) { - let args = [eventName].slice.call(arguments); - return window.runtime.EventsEmit.apply(null, args); -} - -export function WindowReload() { - window.runtime.WindowReload(); -} - -export function WindowReloadApp() { - window.runtime.WindowReloadApp(); -} - -export function WindowSetAlwaysOnTop(b) { - window.runtime.WindowSetAlwaysOnTop(b); -} - -export function WindowSetSystemDefaultTheme() { - window.runtime.WindowSetSystemDefaultTheme(); -} - -export function WindowSetLightTheme() { - window.runtime.WindowSetLightTheme(); -} - -export function WindowSetDarkTheme() { - window.runtime.WindowSetDarkTheme(); -} - -export function WindowCenter() { - window.runtime.WindowCenter(); -} - -export function WindowSetTitle(title) { - window.runtime.WindowSetTitle(title); -} - -export function WindowFullscreen() { - window.runtime.WindowFullscreen(); -} - -export function WindowUnfullscreen() { - window.runtime.WindowUnfullscreen(); -} - -export function WindowGetSize() { - return window.runtime.WindowGetSize(); -} - -export function WindowSetSize(width, height) { - window.runtime.WindowSetSize(width, height); -} - -export function WindowSetMaxSize(width, height) { - window.runtime.WindowSetMaxSize(width, height); -} - -export function WindowSetMinSize(width, height) { - window.runtime.WindowSetMinSize(width, height); -} - -export function WindowSetPosition(x, y) { - window.runtime.WindowSetPosition(x, y); -} - -export function WindowGetPosition() { - return window.runtime.WindowGetPosition(); -} - -export function WindowHide() { - window.runtime.WindowHide(); -} - -export function WindowShow() { - window.runtime.WindowShow(); -} - -export function WindowMaximise() { - window.runtime.WindowMaximise(); -} - -export function WindowToggleMaximise() { - window.runtime.WindowToggleMaximise(); -} - -export function WindowUnmaximise() { - window.runtime.WindowUnmaximise(); -} - -export function WindowMinimise() { - window.runtime.WindowMinimise(); -} - -export function WindowUnminimise() { - window.runtime.WindowUnminimise(); -} - -export function WindowSetBackgroundColour(R, G, B, A) { - window.runtime.WindowSetBackgroundColour(R, G, B, A); -} - -export function ScreenGetAll() { - return window.runtime.ScreenGetAll(); -} - -export function BrowserOpenURL(url) { - window.runtime.BrowserOpenURL(url); -} - -export function Environment() { - return window.runtime.Environment(); -} - -export function Quit() { - window.runtime.Quit(); -} - -export function Hide() { - window.runtime.Hide(); -} - -export function Show() { - window.runtime.Show(); -} diff --git a/v2/pkg/templates/templates/lit/go.mod.tmpl b/v2/pkg/templates/templates/lit/go.mod.tmpl deleted file mode 100644 index 4b34d1668..000000000 --- a/v2/pkg/templates/templates/lit/go.mod.tmpl +++ /dev/null @@ -1,7 +0,0 @@ -module changeme - -go 1.23.0 - -require github.com/wailsapp/wails/v2 {{.WailsVersion}} - -// replace github.com/wailsapp/wails/v2 {{.WailsVersion}} => {{.WailsDirectory}} \ No newline at end of file diff --git a/v2/pkg/templates/templates/lit/main.go.tmpl b/v2/pkg/templates/templates/lit/main.go.tmpl deleted file mode 100644 index e24782be3..000000000 --- a/v2/pkg/templates/templates/lit/main.go.tmpl +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import ( - "embed" - - "github.com/wailsapp/wails/v2" - "github.com/wailsapp/wails/v2/pkg/options" - "github.com/wailsapp/wails/v2/pkg/options/assetserver" -) - -//go:embed all:frontend/dist -var assets embed.FS - -func main() { - // Create an instance of the app structure - app := NewApp() - - // Create application with options - err := wails.Run(&options.App{ - Title: "{{.ProjectName}}", - Width: 1024, - Height: 768, - AssetServer: &assetserver.Options{ - Assets: assets, - }, - BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, - OnStartup: app.startup, - Bind: []interface{}{ - app, - }, - }) - - if err != nil { - println("Error:", err.Error()) - } -} diff --git a/v2/pkg/templates/templates/lit/template.json b/v2/pkg/templates/templates/lit/template.json deleted file mode 100644 index 168769e37..000000000 --- a/v2/pkg/templates/templates/lit/template.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "Lit + Vite", - "shortname": "lit", - "author": "Lea Anthony", - "description": "Lit + Vite development server", - "helpurl": "https://wails.io" -} \ No newline at end of file diff --git a/v2/pkg/templates/templates/lit/wails.tmpl.json b/v2/pkg/templates/templates/lit/wails.tmpl.json deleted file mode 100644 index c39b2cb7d..000000000 --- a/v2/pkg/templates/templates/lit/wails.tmpl.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "$schema": "https://wails.io/schemas/config.v2.json", - "name": "{{.ProjectName}}", - "outputfilename": "{{.BinaryName}}", - "frontend:install": "npm install", - "frontend:build": "npm run build", - "frontend:dev:watcher": "npm run dev", - "frontend:dev:serverUrl": "auto", - "author": { - "name": "{{.AuthorName}}", - "email": "{{.AuthorEmail}}" - } -} diff --git a/v2/pkg/templates/templates/plain/.gitignore.tmpl b/v2/pkg/templates/templates/plain/.gitignore.tmpl deleted file mode 100644 index b92a6f8bf..000000000 --- a/v2/pkg/templates/templates/plain/.gitignore.tmpl +++ /dev/null @@ -1,12 +0,0 @@ -# Wails bin directory -build/bin -# Wails Windows NSIS support files -build/windows/installer/wails_tools.nsh -build/windows/installer/tmp/ - -# IDEs -.idea -.vscode - -# The black hole that is... -node_modules diff --git a/v2/pkg/templates/templates/plain/README.md b/v2/pkg/templates/templates/plain/README.md deleted file mode 100644 index 3a71c4e9b..000000000 --- a/v2/pkg/templates/templates/plain/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# README - -## About - -This template uses plain JS / HTML and CSS. - -You can configure the project by editing `wails.json`. More information about the project settings can be found -here: https://wails.io/docs/reference/project-config - -## Live Development - -To run in live development mode, run `wails dev` in the project directory. This will run a Vite development -server that will provide very fast hot reload of your frontend changes. If you want to develop in a browser -and have access to your Go methods, there is also a dev server that runs on http://localhost:34115. Connect -to this in your browser, and you can call your Go code from devtools. - -## Building - -To build a redistributable, production mode package, use `wails build`. diff --git a/v2/pkg/templates/templates/plain/app.go b/v2/pkg/templates/templates/plain/app.go deleted file mode 100644 index 224be7156..000000000 --- a/v2/pkg/templates/templates/plain/app.go +++ /dev/null @@ -1,44 +0,0 @@ -package main - -import ( - "context" - "fmt" -) - -// App struct -type App struct { - ctx context.Context -} - -// NewApp creates a new App application struct -func NewApp() *App { - return &App{} -} - -// startup is called at application startup -func (a *App) startup(ctx context.Context) { - // Perform your setup here - a.ctx = ctx -} - -// domReady is called after front-end resources have been loaded -func (a App) domReady(ctx context.Context) { - // Add your action here -} - -// beforeClose is called when the application is about to quit, -// either by clicking the window close button or calling runtime.Quit. -// Returning true will cause the application to continue, false will continue shutdown as normal. -func (a *App) beforeClose(ctx context.Context) (prevent bool) { - return false -} - -// shutdown is called at application termination -func (a *App) shutdown(ctx context.Context) { - // Perform your teardown here -} - -// Greet returns a greeting for the given name -func (a *App) Greet(name string) string { - return fmt.Sprintf("Hello %s, It's show time!", name) -} diff --git a/v2/pkg/templates/templates/plain/frontend/src/assets/fonts/OFL.txt b/v2/pkg/templates/templates/plain/frontend/src/assets/fonts/OFL.txt deleted file mode 100644 index 9cac04ce8..000000000 --- a/v2/pkg/templates/templates/plain/frontend/src/assets/fonts/OFL.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com), - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/v2/pkg/templates/templates/plain/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 b/v2/pkg/templates/templates/plain/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 deleted file mode 100644 index 2f9cc5964..000000000 Binary files a/v2/pkg/templates/templates/plain/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 and /dev/null differ diff --git a/v2/pkg/templates/templates/plain/frontend/src/assets/images/logo-universal.png b/v2/pkg/templates/templates/plain/frontend/src/assets/images/logo-universal.png deleted file mode 100644 index 99ac71f5a..000000000 Binary files a/v2/pkg/templates/templates/plain/frontend/src/assets/images/logo-universal.png and /dev/null differ diff --git a/v2/pkg/templates/templates/plain/frontend/src/index.tmpl.html b/v2/pkg/templates/templates/plain/frontend/src/index.tmpl.html deleted file mode 100644 index a8a434a37..000000000 --- a/v2/pkg/templates/templates/plain/frontend/src/index.tmpl.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - {{.ProjectName}} - - - - -
- -
Please enter your name below 👇
-
- - -
-
- - - diff --git a/v2/pkg/templates/templates/plain/frontend/src/main.css b/v2/pkg/templates/templates/plain/frontend/src/main.css deleted file mode 100644 index dab87d09a..000000000 --- a/v2/pkg/templates/templates/plain/frontend/src/main.css +++ /dev/null @@ -1,82 +0,0 @@ -html { - background-color: rgba(27, 38, 54, 1); - text-align: center; - color: white; -} - -body { - margin: 0; - color: white; - font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", - "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", - sans-serif; -} - -@font-face { - font-family: "Nunito"; - font-style: normal; - font-weight: 400; - src: local(""), - url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2"); -} - -#app { - height: 100vh; - text-align: center; -} - -.logo { - display: block; - width: 50%; - height: 50%; - margin: auto; - padding: 10% 0 0; - background-position: center; - background-repeat: no-repeat; - background-image: url("./assets/images/logo-universal.png"); - background-size: 100% 100%; - background-origin: content-box; -} - -.result { - height: 20px; - line-height: 20px; - margin: 1.5rem auto; -} - -.input-box .btn { - width: 60px; - height: 30px; - line-height: 30px; - border-radius: 3px; - border: none; - margin: 0 0 0 20px; - padding: 0 8px; - cursor: pointer; -} - -.input-box .btn:hover { - background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%); - color: #333333; -} - -.input-box .input { - border: none; - border-radius: 3px; - outline: none; - height: 30px; - line-height: 30px; - padding: 0 10px; - background-color: rgba(240, 240, 240, 1); - -webkit-font-smoothing: antialiased; -} - -.input-box .input:hover { - border: none; - background-color: rgba(255, 255, 255, 1); -} - -.input-box .input:focus { - border: none; - background-color: rgba(255, 255, 255, 1); -} diff --git a/v2/pkg/templates/templates/plain/frontend/src/main.js b/v2/pkg/templates/templates/plain/frontend/src/main.js deleted file mode 100644 index e4945441d..000000000 --- a/v2/pkg/templates/templates/plain/frontend/src/main.js +++ /dev/null @@ -1,33 +0,0 @@ -// Get input + focus -let nameElement = document.getElementById("name"); -nameElement.focus(); -import './main.css'; - -// Setup the greet function -window.greet = function () { - // Get name - let name = nameElement.value; - - // Check if the input is empty - if (name === "") return; - - // Call App.Greet(name) - try { - window.go.main.App.Greet(name) - .then((result) => { - // Update result with data back from App.Greet() - document.getElementById("result").innerText = result; - }) - .catch((err) => { - console.error(err); - }); - } catch (err) { - console.error(err); - } -}; - -nameElement.onkeydown = function (e) { - if (e.keyCode == 13) { - window.greet(); - } -}; diff --git a/v2/pkg/templates/templates/plain/go.mod.tmpl b/v2/pkg/templates/templates/plain/go.mod.tmpl deleted file mode 100644 index 4b34d1668..000000000 --- a/v2/pkg/templates/templates/plain/go.mod.tmpl +++ /dev/null @@ -1,7 +0,0 @@ -module changeme - -go 1.23.0 - -require github.com/wailsapp/wails/v2 {{.WailsVersion}} - -// replace github.com/wailsapp/wails/v2 {{.WailsVersion}} => {{.WailsDirectory}} \ No newline at end of file diff --git a/v2/pkg/templates/templates/plain/main.go.tmpl b/v2/pkg/templates/templates/plain/main.go.tmpl deleted file mode 100644 index 847803db6..000000000 --- a/v2/pkg/templates/templates/plain/main.go.tmpl +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import ( - "embed" - - "github.com/wailsapp/wails/v2" - "github.com/wailsapp/wails/v2/pkg/options" - "github.com/wailsapp/wails/v2/pkg/options/assetserver" -) - -//go:embed all:frontend/src -var assets embed.FS - -func main() { - // Create an instance of the app structure - app := NewApp() - - // Create application with options - err := wails.Run(&options.App{ - Title: "{{.ProjectName}}", - Width: 1024, - Height: 768, - AssetServer: &assetserver.Options{ - Assets: assets, - }, - BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, - OnStartup: app.startup, - Bind: []interface{}{ - app, - }, - }) - - if err != nil { - println("Error:", err.Error()) - } -} diff --git a/v2/pkg/templates/templates/plain/template.json b/v2/pkg/templates/templates/plain/template.json deleted file mode 100644 index fc919bc3b..000000000 --- a/v2/pkg/templates/templates/plain/template.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "Plain HTML/JS/CSS", - "shortname": "plain", - "author": "Lea Anthony ", - "description": "A simple template using only HTML/CSS/JS", - "helpurl": "https://github.com/wailsapp/wails" -} diff --git a/v2/pkg/templates/templates/plain/wails.tmpl.json b/v2/pkg/templates/templates/plain/wails.tmpl.json deleted file mode 100644 index 0168826bd..000000000 --- a/v2/pkg/templates/templates/plain/wails.tmpl.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "$schema": "https://wails.io/schemas/config.v2.json", - "name": "{{.ProjectName}}", - "outputfilename": "{{.BinaryName}}", - "wailsjsdir": "./frontend", - "author": { - "name": "{{.AuthorName}}", - "email": "{{.AuthorEmail}}" - } -} diff --git a/v2/pkg/templates/templates/preact-ts/.gitignore.tmpl b/v2/pkg/templates/templates/preact-ts/.gitignore.tmpl deleted file mode 100644 index 129d52294..000000000 --- a/v2/pkg/templates/templates/preact-ts/.gitignore.tmpl +++ /dev/null @@ -1,3 +0,0 @@ -build/bin -node_modules -frontend/dist diff --git a/v2/pkg/templates/templates/preact-ts/README.md b/v2/pkg/templates/templates/preact-ts/README.md deleted file mode 100644 index 923ecb002..000000000 --- a/v2/pkg/templates/templates/preact-ts/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# README - -## About - -This is the official Wails Preact-TS template. - -You can configure the project by editing `wails.json`. More information about the project settings can be found -here: https://wails.io/docs/reference/project-config - -## Live Development - -To run in live development mode, run `wails dev` in the project directory. This will run a Vite development -server that will provide very fast hot reload of your frontend changes. If you want to develop in a browser -and have access to your Go methods, there is also a dev server that runs on http://localhost:34115. Connect -to this in your browser, and you can call your Go code from devtools. - -## Building - -To build a redistributable, production mode package, use `wails build`. diff --git a/v2/pkg/templates/templates/preact-ts/app.tmpl.go b/v2/pkg/templates/templates/preact-ts/app.tmpl.go deleted file mode 100644 index af53038a1..000000000 --- a/v2/pkg/templates/templates/preact-ts/app.tmpl.go +++ /dev/null @@ -1,27 +0,0 @@ -package main - -import ( - "context" - "fmt" -) - -// App struct -type App struct { - ctx context.Context -} - -// NewApp creates a new App application struct -func NewApp() *App { - return &App{} -} - -// startup is called when the app starts. The context is saved -// so we can call the runtime methods -func (a *App) startup(ctx context.Context) { - a.ctx = ctx -} - -// Greet returns a greeting for the given name -func (a *App) Greet(name string) string { - return fmt.Sprintf("Hello %s, It's show time!", name) -} diff --git a/v2/pkg/templates/templates/preact-ts/frontend/dist/gitkeep b/v2/pkg/templates/templates/preact-ts/frontend/dist/gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/v2/pkg/templates/templates/preact-ts/frontend/index.tmpl.html b/v2/pkg/templates/templates/preact-ts/frontend/index.tmpl.html deleted file mode 100644 index 0fb692c96..000000000 --- a/v2/pkg/templates/templates/preact-ts/frontend/index.tmpl.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - {{.ProjectName}} - - -
- - - - diff --git a/v2/pkg/templates/templates/preact-ts/frontend/package.json b/v2/pkg/templates/templates/preact-ts/frontend/package.json deleted file mode 100644 index 014e8df79..000000000 --- a/v2/pkg/templates/templates/preact-ts/frontend/package.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "frontend", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.10.1" - }, - "devDependencies": { - "@preact/preset-vite": "^2.3.0", - "typescript": "^4.6.4", - "vite": "^3.0.7" - } -} \ No newline at end of file diff --git a/v2/pkg/templates/templates/preact-ts/frontend/src/App.css b/v2/pkg/templates/templates/preact-ts/frontend/src/App.css deleted file mode 100644 index f949d9c18..000000000 --- a/v2/pkg/templates/templates/preact-ts/frontend/src/App.css +++ /dev/null @@ -1,59 +0,0 @@ -#app { - height: 100vh; - text-align: center; -} - -#logo { - display: block; - width: 50%; - height: 50%; - margin: auto; - padding: 10% 0 0; - background-position: center; - background-repeat: no-repeat; - background-size: 100% 100%; - background-origin: content-box; -} - -.result { - height: 20px; - line-height: 20px; - margin: 1.5rem auto; -} - -.input-box .btn { - width: 60px; - height: 30px; - line-height: 30px; - border-radius: 3px; - border: none; - margin: 0 0 0 20px; - padding: 0 8px; - cursor: pointer; -} - -.input-box .btn:hover { - background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%); - color: #333333; -} - -.input-box .input { - border: none; - border-radius: 3px; - outline: none; - height: 30px; - line-height: 30px; - padding: 0 10px; - background-color: rgba(240, 240, 240, 1); - -webkit-font-smoothing: antialiased; -} - -.input-box .input:hover { - border: none; - background-color: rgba(255, 255, 255, 1); -} - -.input-box .input:focus { - border: none; - background-color: rgba(255, 255, 255, 1); -} \ No newline at end of file diff --git a/v2/pkg/templates/templates/preact-ts/frontend/src/app.tsx b/v2/pkg/templates/templates/preact-ts/frontend/src/app.tsx deleted file mode 100644 index 9875320f9..000000000 --- a/v2/pkg/templates/templates/preact-ts/frontend/src/app.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import './App.css' -import logo from "./assets/images/logo-universal.png" -import {Greet} from "../wailsjs/go/main/App"; -import {useState} from "preact/hooks"; -import {h} from 'preact'; - -export function App(props: any) { - const [resultText, setResultText] = useState("Please enter your name below 👇"); - const [name, setName] = useState(''); - const updateName = (e: any) => setName(e.target.value); - const updateResultText = (result: string) => setResultText(result); - - function greet() { - Greet(name).then(updateResultText); - } - - return ( - <> -
- -
{resultText}
-
- - -
-
- - ) -} diff --git a/v2/pkg/templates/templates/preact-ts/frontend/src/assets/fonts/OFL.txt b/v2/pkg/templates/templates/preact-ts/frontend/src/assets/fonts/OFL.txt deleted file mode 100644 index 9cac04ce8..000000000 --- a/v2/pkg/templates/templates/preact-ts/frontend/src/assets/fonts/OFL.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com), - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/v2/pkg/templates/templates/preact-ts/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 b/v2/pkg/templates/templates/preact-ts/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 deleted file mode 100644 index 2f9cc5964..000000000 Binary files a/v2/pkg/templates/templates/preact-ts/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 and /dev/null differ diff --git a/v2/pkg/templates/templates/preact-ts/frontend/src/assets/images/logo-universal.png b/v2/pkg/templates/templates/preact-ts/frontend/src/assets/images/logo-universal.png deleted file mode 100644 index 99ac71f5a..000000000 Binary files a/v2/pkg/templates/templates/preact-ts/frontend/src/assets/images/logo-universal.png and /dev/null differ diff --git a/v2/pkg/templates/templates/preact-ts/frontend/src/main.tsx b/v2/pkg/templates/templates/preact-ts/frontend/src/main.tsx deleted file mode 100644 index 05b147282..000000000 --- a/v2/pkg/templates/templates/preact-ts/frontend/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import {render} from 'preact'; -import {App} from './app'; -import './style.css'; - -render(, document.getElementById('app')!); diff --git a/v2/pkg/templates/templates/preact-ts/frontend/src/preact.d.ts b/v2/pkg/templates/templates/preact-ts/frontend/src/preact.d.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/v2/pkg/templates/templates/preact-ts/frontend/src/style.css b/v2/pkg/templates/templates/preact-ts/frontend/src/style.css deleted file mode 100644 index 3940d6c63..000000000 --- a/v2/pkg/templates/templates/preact-ts/frontend/src/style.css +++ /dev/null @@ -1,26 +0,0 @@ -html { - background-color: rgba(27, 38, 54, 1); - text-align: center; - color: white; -} - -body { - margin: 0; - color: white; - font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", - "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", - sans-serif; -} - -@font-face { - font-family: "Nunito"; - font-style: normal; - font-weight: 400; - src: local(""), - url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2"); -} - -#app { - height: 100vh; - text-align: center; -} diff --git a/v2/pkg/templates/templates/preact-ts/frontend/src/vite-env.d.ts b/v2/pkg/templates/templates/preact-ts/frontend/src/vite-env.d.ts deleted file mode 100644 index 11f02fe2a..000000000 --- a/v2/pkg/templates/templates/preact-ts/frontend/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/v2/pkg/templates/templates/preact-ts/frontend/tsconfig.json b/v2/pkg/templates/templates/preact-ts/frontend/tsconfig.json deleted file mode 100644 index d6f1807ef..000000000 --- a/v2/pkg/templates/templates/preact-ts/frontend/tsconfig.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "lib": [ - "DOM", - "DOM.Iterable", - "ESNext" - ], - "allowJs": false, - "skipLibCheck": true, - "esModuleInterop": false, - "allowSyntheticDefaultImports": true, - "strict": true, - "forceConsistentCasingInFileNames": true, - "module": "ESNext", - "moduleResolution": "Node", - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "preserve", - "jsxFactory": "h", - "jsxFragmentFactory": "Fragment" - }, - "include": [ - "src" - ], - "references": [ - { - "path": "./tsconfig.node.json" - } - ] -} diff --git a/v2/pkg/templates/templates/preact-ts/frontend/tsconfig.node.json b/v2/pkg/templates/templates/preact-ts/frontend/tsconfig.node.json deleted file mode 100644 index b8afcc8fa..000000000 --- a/v2/pkg/templates/templates/preact-ts/frontend/tsconfig.node.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "module": "ESNext", - "moduleResolution": "Node", - "allowSyntheticDefaultImports": true - }, - "include": [ - "vite.config.ts" - ] -} diff --git a/v2/pkg/templates/templates/preact-ts/frontend/vite.config.ts b/v2/pkg/templates/templates/preact-ts/frontend/vite.config.ts deleted file mode 100644 index 25845ba4b..000000000 --- a/v2/pkg/templates/templates/preact-ts/frontend/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import {defineConfig} from 'vite' -import preact from '@preact/preset-vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact()] -}) diff --git a/v2/pkg/templates/templates/preact-ts/frontend/wailsjs/go/main/App.d.ts b/v2/pkg/templates/templates/preact-ts/frontend/wailsjs/go/main/App.d.ts deleted file mode 100644 index 43173cfce..000000000 --- a/v2/pkg/templates/templates/preact-ts/frontend/wailsjs/go/main/App.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Greet(arg1: string): Promise; diff --git a/v2/pkg/templates/templates/preact-ts/frontend/wailsjs/go/main/App.js b/v2/pkg/templates/templates/preact-ts/frontend/wailsjs/go/main/App.js deleted file mode 100644 index 0ee085c95..000000000 --- a/v2/pkg/templates/templates/preact-ts/frontend/wailsjs/go/main/App.js +++ /dev/null @@ -1,7 +0,0 @@ -// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Greet(arg1) { - return window['go']['main']['App']['Greet'](arg1); -} diff --git a/v2/pkg/templates/templates/preact-ts/frontend/wailsjs/runtime/package.json b/v2/pkg/templates/templates/preact-ts/frontend/wailsjs/runtime/package.json deleted file mode 100644 index 1e7c8a5d7..000000000 --- a/v2/pkg/templates/templates/preact-ts/frontend/wailsjs/runtime/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "@wailsapp/runtime", - "version": "2.0.0", - "description": "Wails Javascript runtime library", - "main": "runtime.js", - "types": "runtime.d.ts", - "scripts": { - }, - "repository": { - "type": "git", - "url": "git+https://github.com/wailsapp/wails.git" - }, - "keywords": [ - "Wails", - "Javascript", - "Go" - ], - "author": "Lea Anthony ", - "license": "MIT", - "bugs": { - "url": "https://github.com/wailsapp/wails/issues" - }, - "homepage": "https://github.com/wailsapp/wails#readme" -} diff --git a/v2/pkg/templates/templates/preact-ts/frontend/wailsjs/runtime/runtime.d.ts b/v2/pkg/templates/templates/preact-ts/frontend/wailsjs/runtime/runtime.d.ts deleted file mode 100644 index 336fb07aa..000000000 --- a/v2/pkg/templates/templates/preact-ts/frontend/wailsjs/runtime/runtime.d.ts +++ /dev/null @@ -1,211 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export interface Position { - x: number; - y: number; -} - -export interface Size { - w: number; - h: number; -} - -export interface Screen { - isCurrent: boolean; - isPrimary: boolean; - width: number - height: number -} - -// Environment information such as platform, buildtype, ... -export interface EnvironmentInfo { - buildType: string; - platform: string; - arch: string; -} - -// [EventsEmit](https://wails.io/docs/reference/runtime/events#eventsemit) -// emits the given event. Optional data may be passed with the event. -// This will trigger any event listeners. -export function EventsEmit(eventName: string, ...data: any): void; - -// [EventsOn](https://wails.io/docs/reference/runtime/events#eventson) sets up a listener for the given event name. -export function EventsOn(eventName: string, callback: (...data: any) => void): void; - -// [EventsOnMultiple](https://wails.io/docs/reference/runtime/events#eventsonmultiple) -// sets up a listener for the given event name, but will only trigger a given number times. -export function EventsOnMultiple(eventName: string, callback: (...data: any) => void, maxCallbacks: number): void; - -// [EventsOnce](https://wails.io/docs/reference/runtime/events#eventsonce) -// sets up a listener for the given event name, but will only trigger once. -export function EventsOnce(eventName: string, callback: (...data: any) => void): void; - -// [EventsOff](https://wails.io/docs/reference/runtime/events#eventsff) -// unregisters the listener for the given event name. -export function EventsOff(eventName: string): void; - -// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) -// unregisters all event listeners. -export function EventsOffAll(): void; - -// [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) -// logs the given message as a raw message -export function LogPrint(message: string): void; - -// [LogTrace](https://wails.io/docs/reference/runtime/log#logtrace) -// logs the given message at the `trace` log level. -export function LogTrace(message: string): void; - -// [LogDebug](https://wails.io/docs/reference/runtime/log#logdebug) -// logs the given message at the `debug` log level. -export function LogDebug(message: string): void; - -// [LogError](https://wails.io/docs/reference/runtime/log#logerror) -// logs the given message at the `error` log level. -export function LogError(message: string): void; - -// [LogFatal](https://wails.io/docs/reference/runtime/log#logfatal) -// logs the given message at the `fatal` log level. -// The application will quit after calling this method. -export function LogFatal(message: string): void; - -// [LogInfo](https://wails.io/docs/reference/runtime/log#loginfo) -// logs the given message at the `info` log level. -export function LogInfo(message: string): void; - -// [LogWarning](https://wails.io/docs/reference/runtime/log#logwarning) -// logs the given message at the `warning` log level. -export function LogWarning(message: string): void; - -// [WindowReload](https://wails.io/docs/reference/runtime/window#windowreload) -// Forces a reload by the main application as well as connected browsers. -export function WindowReload(): void; - -// [WindowReloadApp](https://wails.io/docs/reference/runtime/window#windowreloadapp) -// Reloads the application frontend. -export function WindowReloadApp(): void; - -// [WindowSetAlwaysOnTop](https://wails.io/docs/reference/runtime/window#windowsetalwaysontop) -// Sets the window AlwaysOnTop or not on top. -export function WindowSetAlwaysOnTop(b: boolean): void; - -// [WindowSetSystemDefaultTheme](https://wails.io/docs/next/reference/runtime/window#windowsetsystemdefaulttheme) -// *Windows only* -// Sets window theme to system default (dark/light). -export function WindowSetSystemDefaultTheme(): void; - -// [WindowSetLightTheme](https://wails.io/docs/next/reference/runtime/window#windowsetlighttheme) -// *Windows only* -// Sets window to light theme. -export function WindowSetLightTheme(): void; - -// [WindowSetDarkTheme](https://wails.io/docs/next/reference/runtime/window#windowsetdarktheme) -// *Windows only* -// Sets window to dark theme. -export function WindowSetDarkTheme(): void; - -// [WindowCenter](https://wails.io/docs/reference/runtime/window#windowcenter) -// Centers the window on the monitor the window is currently on. -export function WindowCenter(): void; - -// [WindowSetTitle](https://wails.io/docs/reference/runtime/window#windowsettitle) -// Sets the text in the window title bar. -export function WindowSetTitle(title: string): void; - -// [WindowFullscreen](https://wails.io/docs/reference/runtime/window#windowfullscreen) -// Makes the window full screen. -export function WindowFullscreen(): void; - -// [WindowUnfullscreen](https://wails.io/docs/reference/runtime/window#windowunfullscreen) -// Restores the previous window dimensions and position prior to full screen. -export function WindowUnfullscreen(): void; - -// [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize) -// Sets the width and height of the window. -export function WindowSetSize(width: number, height: number): void; - -// [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize) -// Gets the width and height of the window. -export function WindowGetSize(): Promise; - -// [WindowSetMaxSize](https://wails.io/docs/reference/runtime/window#windowsetmaxsize) -// Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMaxSize(width: number, height: number): void; - -// [WindowSetMinSize](https://wails.io/docs/reference/runtime/window#windowsetminsize) -// Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMinSize(width: number, height: number): void; - -// [WindowSetPosition](https://wails.io/docs/reference/runtime/window#windowsetposition) -// Sets the window position relative to the monitor the window is currently on. -export function WindowSetPosition(x: number, y: number): void; - -// [WindowGetPosition](https://wails.io/docs/reference/runtime/window#windowgetposition) -// Gets the window position relative to the monitor the window is currently on. -export function WindowGetPosition(): Promise; - -// [WindowHide](https://wails.io/docs/reference/runtime/window#windowhide) -// Hides the window. -export function WindowHide(): void; - -// [WindowShow](https://wails.io/docs/reference/runtime/window#windowshow) -// Shows the window, if it is currently hidden. -export function WindowShow(): void; - -// [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise) -// Maximises the window to fill the screen. -export function WindowMaximise(): void; - -// [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise) -// Toggles between Maximised and UnMaximised. -export function WindowToggleMaximise(): void; - -// [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise) -// Restores the window to the dimensions and position prior to maximising. -export function WindowUnmaximise(): void; - -// [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise) -// Minimises the window. -export function WindowMinimise(): void; - -// [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise) -// Restores the window to the dimensions and position prior to minimising. -export function WindowUnminimise(): void; - -// [WindowSetBackgroundColour](https://wails.io/docs/reference/runtime/window#windowsetbackgroundcolour) -// Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels. -export function WindowSetBackgroundColour(R: number, G: number, B: number, A: number): void; - -// [ScreenGetAll](https://wails.io/docs/reference/runtime/window#screengetall) -// Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system. -export function ScreenGetAll(): Promise; - -// [BrowserOpenURL](https://wails.io/docs/reference/runtime/browser#browseropenurl) -// Opens the given URL in the system browser. -export function BrowserOpenURL(url: string): void; - -// [Environment](https://wails.io/docs/reference/runtime/intro#environment) -// Returns information about the environment -export function Environment(): Promise; - -// [Quit](https://wails.io/docs/reference/runtime/intro#quit) -// Quits the application. -export function Quit(): void; - -// [Hide](https://wails.io/docs/reference/runtime/intro#hide) -// Hides the application. -export function Hide(): void; - -// [Show](https://wails.io/docs/reference/runtime/intro#show) -// Shows the application. -export function Show(): void; diff --git a/v2/pkg/templates/templates/preact-ts/frontend/wailsjs/runtime/runtime.js b/v2/pkg/templates/templates/preact-ts/frontend/wailsjs/runtime/runtime.js deleted file mode 100644 index b5ae16d56..000000000 --- a/v2/pkg/templates/templates/preact-ts/frontend/wailsjs/runtime/runtime.js +++ /dev/null @@ -1,182 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export function LogPrint(message) { - window.runtime.LogPrint(message); -} - -export function LogTrace(message) { - window.runtime.LogTrace(message); -} - -export function LogDebug(message) { - window.runtime.LogDebug(message); -} - -export function LogInfo(message) { - window.runtime.LogInfo(message); -} - -export function LogWarning(message) { - window.runtime.LogWarning(message); -} - -export function LogError(message) { - window.runtime.LogError(message); -} - -export function LogFatal(message) { - window.runtime.LogFatal(message); -} - -export function EventsOnMultiple(eventName, callback, maxCallbacks) { - window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks); -} - -export function EventsOn(eventName, callback) { - EventsOnMultiple(eventName, callback, -1); -} - -export function EventsOff(eventName) { - return window.runtime.EventsOff(eventName); -} - -export function EventsOffAll() { - return window.runtime.EventsOffAll(); -} - -export function EventsOnce(eventName, callback) { - EventsOnMultiple(eventName, callback, 1); -} - -export function EventsEmit(eventName) { - let args = [eventName].slice.call(arguments); - return window.runtime.EventsEmit.apply(null, args); -} - -export function WindowReload() { - window.runtime.WindowReload(); -} - -export function WindowReloadApp() { - window.runtime.WindowReloadApp(); -} - -export function WindowSetAlwaysOnTop(b) { - window.runtime.WindowSetAlwaysOnTop(b); -} - -export function WindowSetSystemDefaultTheme() { - window.runtime.WindowSetSystemDefaultTheme(); -} - -export function WindowSetLightTheme() { - window.runtime.WindowSetLightTheme(); -} - -export function WindowSetDarkTheme() { - window.runtime.WindowSetDarkTheme(); -} - -export function WindowCenter() { - window.runtime.WindowCenter(); -} - -export function WindowSetTitle(title) { - window.runtime.WindowSetTitle(title); -} - -export function WindowFullscreen() { - window.runtime.WindowFullscreen(); -} - -export function WindowUnfullscreen() { - window.runtime.WindowUnfullscreen(); -} - -export function WindowGetSize() { - return window.runtime.WindowGetSize(); -} - -export function WindowSetSize(width, height) { - window.runtime.WindowSetSize(width, height); -} - -export function WindowSetMaxSize(width, height) { - window.runtime.WindowSetMaxSize(width, height); -} - -export function WindowSetMinSize(width, height) { - window.runtime.WindowSetMinSize(width, height); -} - -export function WindowSetPosition(x, y) { - window.runtime.WindowSetPosition(x, y); -} - -export function WindowGetPosition() { - return window.runtime.WindowGetPosition(); -} - -export function WindowHide() { - window.runtime.WindowHide(); -} - -export function WindowShow() { - window.runtime.WindowShow(); -} - -export function WindowMaximise() { - window.runtime.WindowMaximise(); -} - -export function WindowToggleMaximise() { - window.runtime.WindowToggleMaximise(); -} - -export function WindowUnmaximise() { - window.runtime.WindowUnmaximise(); -} - -export function WindowMinimise() { - window.runtime.WindowMinimise(); -} - -export function WindowUnminimise() { - window.runtime.WindowUnminimise(); -} - -export function WindowSetBackgroundColour(R, G, B, A) { - window.runtime.WindowSetBackgroundColour(R, G, B, A); -} - -export function ScreenGetAll() { - return window.runtime.ScreenGetAll(); -} - -export function BrowserOpenURL(url) { - window.runtime.BrowserOpenURL(url); -} - -export function Environment() { - return window.runtime.Environment(); -} - -export function Quit() { - window.runtime.Quit(); -} - -export function Hide() { - window.runtime.Hide(); -} - -export function Show() { - window.runtime.Show(); -} diff --git a/v2/pkg/templates/templates/preact-ts/go.mod.tmpl b/v2/pkg/templates/templates/preact-ts/go.mod.tmpl deleted file mode 100644 index 4b34d1668..000000000 --- a/v2/pkg/templates/templates/preact-ts/go.mod.tmpl +++ /dev/null @@ -1,7 +0,0 @@ -module changeme - -go 1.23.0 - -require github.com/wailsapp/wails/v2 {{.WailsVersion}} - -// replace github.com/wailsapp/wails/v2 {{.WailsVersion}} => {{.WailsDirectory}} \ No newline at end of file diff --git a/v2/pkg/templates/templates/preact-ts/main.go.tmpl b/v2/pkg/templates/templates/preact-ts/main.go.tmpl deleted file mode 100644 index e24782be3..000000000 --- a/v2/pkg/templates/templates/preact-ts/main.go.tmpl +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import ( - "embed" - - "github.com/wailsapp/wails/v2" - "github.com/wailsapp/wails/v2/pkg/options" - "github.com/wailsapp/wails/v2/pkg/options/assetserver" -) - -//go:embed all:frontend/dist -var assets embed.FS - -func main() { - // Create an instance of the app structure - app := NewApp() - - // Create application with options - err := wails.Run(&options.App{ - Title: "{{.ProjectName}}", - Width: 1024, - Height: 768, - AssetServer: &assetserver.Options{ - Assets: assets, - }, - BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, - OnStartup: app.startup, - Bind: []interface{}{ - app, - }, - }) - - if err != nil { - println("Error:", err.Error()) - } -} diff --git a/v2/pkg/templates/templates/preact-ts/template.json b/v2/pkg/templates/templates/preact-ts/template.json deleted file mode 100644 index b7b46a64c..000000000 --- a/v2/pkg/templates/templates/preact-ts/template.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "Preact + Vite (Typescript)", - "shortname": "preact-ts", - "author": "Lea Anthony", - "description": "Preact + Vite development server", - "helpurl": "https://wails.io" -} \ No newline at end of file diff --git a/v2/pkg/templates/templates/preact-ts/wails.tmpl.json b/v2/pkg/templates/templates/preact-ts/wails.tmpl.json deleted file mode 100644 index c39b2cb7d..000000000 --- a/v2/pkg/templates/templates/preact-ts/wails.tmpl.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "$schema": "https://wails.io/schemas/config.v2.json", - "name": "{{.ProjectName}}", - "outputfilename": "{{.BinaryName}}", - "frontend:install": "npm install", - "frontend:build": "npm run build", - "frontend:dev:watcher": "npm run dev", - "frontend:dev:serverUrl": "auto", - "author": { - "name": "{{.AuthorName}}", - "email": "{{.AuthorEmail}}" - } -} diff --git a/v2/pkg/templates/templates/preact/.gitignore.tmpl b/v2/pkg/templates/templates/preact/.gitignore.tmpl deleted file mode 100644 index 129d52294..000000000 --- a/v2/pkg/templates/templates/preact/.gitignore.tmpl +++ /dev/null @@ -1,3 +0,0 @@ -build/bin -node_modules -frontend/dist diff --git a/v2/pkg/templates/templates/preact/README.md b/v2/pkg/templates/templates/preact/README.md deleted file mode 100644 index 8a354d53b..000000000 --- a/v2/pkg/templates/templates/preact/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# README - -## About - -This is the official Wails Preact template. - -You can configure the project by editing `wails.json`. More information about the project settings can be found -here: https://wails.io/docs/reference/project-config - -## Live Development - -To run in live development mode, run `wails dev` in the project directory. This will run a Vite development -server that will provide very fast hot reload of your frontend changes. If you want to develop in a browser -and have access to your Go methods, there is also a dev server that runs on http://localhost:34115. Connect -to this in your browser, and you can call your Go code from devtools. - -## Building - -To build a redistributable, production mode package, use `wails build`. diff --git a/v2/pkg/templates/templates/preact/app.tmpl.go b/v2/pkg/templates/templates/preact/app.tmpl.go deleted file mode 100644 index af53038a1..000000000 --- a/v2/pkg/templates/templates/preact/app.tmpl.go +++ /dev/null @@ -1,27 +0,0 @@ -package main - -import ( - "context" - "fmt" -) - -// App struct -type App struct { - ctx context.Context -} - -// NewApp creates a new App application struct -func NewApp() *App { - return &App{} -} - -// startup is called when the app starts. The context is saved -// so we can call the runtime methods -func (a *App) startup(ctx context.Context) { - a.ctx = ctx -} - -// Greet returns a greeting for the given name -func (a *App) Greet(name string) string { - return fmt.Sprintf("Hello %s, It's show time!", name) -} diff --git a/v2/pkg/templates/templates/preact/frontend/dist/gitkeep b/v2/pkg/templates/templates/preact/frontend/dist/gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/v2/pkg/templates/templates/preact/frontend/index.tmpl.html b/v2/pkg/templates/templates/preact/frontend/index.tmpl.html deleted file mode 100644 index c8bfd4b76..000000000 --- a/v2/pkg/templates/templates/preact/frontend/index.tmpl.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - {{.ProjectName}} - - -
- - - - diff --git a/v2/pkg/templates/templates/preact/frontend/package.json b/v2/pkg/templates/templates/preact/frontend/package.json deleted file mode 100644 index f8d09a99d..000000000 --- a/v2/pkg/templates/templates/preact/frontend/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "frontend", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "vite build", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.10.1" - }, - "devDependencies": { - "@preact/preset-vite": "^2.3.0", - "vite": "^3.0.7" - } -} \ No newline at end of file diff --git a/v2/pkg/templates/templates/preact/frontend/src/app.css b/v2/pkg/templates/templates/preact/frontend/src/app.css deleted file mode 100644 index f949d9c18..000000000 --- a/v2/pkg/templates/templates/preact/frontend/src/app.css +++ /dev/null @@ -1,59 +0,0 @@ -#app { - height: 100vh; - text-align: center; -} - -#logo { - display: block; - width: 50%; - height: 50%; - margin: auto; - padding: 10% 0 0; - background-position: center; - background-repeat: no-repeat; - background-size: 100% 100%; - background-origin: content-box; -} - -.result { - height: 20px; - line-height: 20px; - margin: 1.5rem auto; -} - -.input-box .btn { - width: 60px; - height: 30px; - line-height: 30px; - border-radius: 3px; - border: none; - margin: 0 0 0 20px; - padding: 0 8px; - cursor: pointer; -} - -.input-box .btn:hover { - background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%); - color: #333333; -} - -.input-box .input { - border: none; - border-radius: 3px; - outline: none; - height: 30px; - line-height: 30px; - padding: 0 10px; - background-color: rgba(240, 240, 240, 1); - -webkit-font-smoothing: antialiased; -} - -.input-box .input:hover { - border: none; - background-color: rgba(255, 255, 255, 1); -} - -.input-box .input:focus { - border: none; - background-color: rgba(255, 255, 255, 1); -} \ No newline at end of file diff --git a/v2/pkg/templates/templates/preact/frontend/src/app.jsx b/v2/pkg/templates/templates/preact/frontend/src/app.jsx deleted file mode 100644 index d0543d081..000000000 --- a/v2/pkg/templates/templates/preact/frontend/src/app.jsx +++ /dev/null @@ -1,29 +0,0 @@ -import './app.css'; -import logo from "./assets/images/logo-universal.png"; -import {Greet} from "../wailsjs/go/main/App"; -import {useState} from "preact/hooks"; - -export function App(props) { - const [resultText, setResultText] = useState("Please enter your name below 👇"); - const [name, setName] = useState(''); - const updateName = (e) => setName(e.target.value); - const updateResultText = (result) => setResultText(result); - - function greet() { - Greet(name).then(updateResultText); - } - - return ( - <> -
- -
{resultText}
-
- - -
-
- - ) -} diff --git a/v2/pkg/templates/templates/preact/frontend/src/assets/fonts/OFL.txt b/v2/pkg/templates/templates/preact/frontend/src/assets/fonts/OFL.txt deleted file mode 100644 index 9cac04ce8..000000000 --- a/v2/pkg/templates/templates/preact/frontend/src/assets/fonts/OFL.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com), - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/v2/pkg/templates/templates/preact/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 b/v2/pkg/templates/templates/preact/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 deleted file mode 100644 index 2f9cc5964..000000000 Binary files a/v2/pkg/templates/templates/preact/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 and /dev/null differ diff --git a/v2/pkg/templates/templates/preact/frontend/src/assets/images/logo-universal.png b/v2/pkg/templates/templates/preact/frontend/src/assets/images/logo-universal.png deleted file mode 100644 index 99ac71f5a..000000000 Binary files a/v2/pkg/templates/templates/preact/frontend/src/assets/images/logo-universal.png and /dev/null differ diff --git a/v2/pkg/templates/templates/preact/frontend/src/assets/preact.svg b/v2/pkg/templates/templates/preact/frontend/src/assets/preact.svg deleted file mode 100644 index 23433fcf8..000000000 --- a/v2/pkg/templates/templates/preact/frontend/src/assets/preact.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/v2/pkg/templates/templates/preact/frontend/src/main.jsx b/v2/pkg/templates/templates/preact/frontend/src/main.jsx deleted file mode 100644 index 6c42a5949..000000000 --- a/v2/pkg/templates/templates/preact/frontend/src/main.jsx +++ /dev/null @@ -1,5 +0,0 @@ -import {render} from 'preact'; -import {App} from './app'; -import './style.css'; - -render(, document.getElementById('app')); \ No newline at end of file diff --git a/v2/pkg/templates/templates/preact/frontend/src/style.css b/v2/pkg/templates/templates/preact/frontend/src/style.css deleted file mode 100644 index 3940d6c63..000000000 --- a/v2/pkg/templates/templates/preact/frontend/src/style.css +++ /dev/null @@ -1,26 +0,0 @@ -html { - background-color: rgba(27, 38, 54, 1); - text-align: center; - color: white; -} - -body { - margin: 0; - color: white; - font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", - "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", - sans-serif; -} - -@font-face { - font-family: "Nunito"; - font-style: normal; - font-weight: 400; - src: local(""), - url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2"); -} - -#app { - height: 100vh; - text-align: center; -} diff --git a/v2/pkg/templates/templates/preact/frontend/vite.config.js b/v2/pkg/templates/templates/preact/frontend/vite.config.js deleted file mode 100644 index 25845ba4b..000000000 --- a/v2/pkg/templates/templates/preact/frontend/vite.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import {defineConfig} from 'vite' -import preact from '@preact/preset-vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact()] -}) diff --git a/v2/pkg/templates/templates/preact/frontend/wailsjs/go/main/App.d.ts b/v2/pkg/templates/templates/preact/frontend/wailsjs/go/main/App.d.ts deleted file mode 100644 index 43173cfce..000000000 --- a/v2/pkg/templates/templates/preact/frontend/wailsjs/go/main/App.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Greet(arg1: string): Promise; diff --git a/v2/pkg/templates/templates/preact/frontend/wailsjs/go/main/App.js b/v2/pkg/templates/templates/preact/frontend/wailsjs/go/main/App.js deleted file mode 100644 index 0ee085c95..000000000 --- a/v2/pkg/templates/templates/preact/frontend/wailsjs/go/main/App.js +++ /dev/null @@ -1,7 +0,0 @@ -// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Greet(arg1) { - return window['go']['main']['App']['Greet'](arg1); -} diff --git a/v2/pkg/templates/templates/preact/frontend/wailsjs/runtime/package.json b/v2/pkg/templates/templates/preact/frontend/wailsjs/runtime/package.json deleted file mode 100644 index 1e7c8a5d7..000000000 --- a/v2/pkg/templates/templates/preact/frontend/wailsjs/runtime/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "@wailsapp/runtime", - "version": "2.0.0", - "description": "Wails Javascript runtime library", - "main": "runtime.js", - "types": "runtime.d.ts", - "scripts": { - }, - "repository": { - "type": "git", - "url": "git+https://github.com/wailsapp/wails.git" - }, - "keywords": [ - "Wails", - "Javascript", - "Go" - ], - "author": "Lea Anthony ", - "license": "MIT", - "bugs": { - "url": "https://github.com/wailsapp/wails/issues" - }, - "homepage": "https://github.com/wailsapp/wails#readme" -} diff --git a/v2/pkg/templates/templates/preact/frontend/wailsjs/runtime/runtime.d.ts b/v2/pkg/templates/templates/preact/frontend/wailsjs/runtime/runtime.d.ts deleted file mode 100644 index 336fb07aa..000000000 --- a/v2/pkg/templates/templates/preact/frontend/wailsjs/runtime/runtime.d.ts +++ /dev/null @@ -1,211 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export interface Position { - x: number; - y: number; -} - -export interface Size { - w: number; - h: number; -} - -export interface Screen { - isCurrent: boolean; - isPrimary: boolean; - width: number - height: number -} - -// Environment information such as platform, buildtype, ... -export interface EnvironmentInfo { - buildType: string; - platform: string; - arch: string; -} - -// [EventsEmit](https://wails.io/docs/reference/runtime/events#eventsemit) -// emits the given event. Optional data may be passed with the event. -// This will trigger any event listeners. -export function EventsEmit(eventName: string, ...data: any): void; - -// [EventsOn](https://wails.io/docs/reference/runtime/events#eventson) sets up a listener for the given event name. -export function EventsOn(eventName: string, callback: (...data: any) => void): void; - -// [EventsOnMultiple](https://wails.io/docs/reference/runtime/events#eventsonmultiple) -// sets up a listener for the given event name, but will only trigger a given number times. -export function EventsOnMultiple(eventName: string, callback: (...data: any) => void, maxCallbacks: number): void; - -// [EventsOnce](https://wails.io/docs/reference/runtime/events#eventsonce) -// sets up a listener for the given event name, but will only trigger once. -export function EventsOnce(eventName: string, callback: (...data: any) => void): void; - -// [EventsOff](https://wails.io/docs/reference/runtime/events#eventsff) -// unregisters the listener for the given event name. -export function EventsOff(eventName: string): void; - -// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) -// unregisters all event listeners. -export function EventsOffAll(): void; - -// [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) -// logs the given message as a raw message -export function LogPrint(message: string): void; - -// [LogTrace](https://wails.io/docs/reference/runtime/log#logtrace) -// logs the given message at the `trace` log level. -export function LogTrace(message: string): void; - -// [LogDebug](https://wails.io/docs/reference/runtime/log#logdebug) -// logs the given message at the `debug` log level. -export function LogDebug(message: string): void; - -// [LogError](https://wails.io/docs/reference/runtime/log#logerror) -// logs the given message at the `error` log level. -export function LogError(message: string): void; - -// [LogFatal](https://wails.io/docs/reference/runtime/log#logfatal) -// logs the given message at the `fatal` log level. -// The application will quit after calling this method. -export function LogFatal(message: string): void; - -// [LogInfo](https://wails.io/docs/reference/runtime/log#loginfo) -// logs the given message at the `info` log level. -export function LogInfo(message: string): void; - -// [LogWarning](https://wails.io/docs/reference/runtime/log#logwarning) -// logs the given message at the `warning` log level. -export function LogWarning(message: string): void; - -// [WindowReload](https://wails.io/docs/reference/runtime/window#windowreload) -// Forces a reload by the main application as well as connected browsers. -export function WindowReload(): void; - -// [WindowReloadApp](https://wails.io/docs/reference/runtime/window#windowreloadapp) -// Reloads the application frontend. -export function WindowReloadApp(): void; - -// [WindowSetAlwaysOnTop](https://wails.io/docs/reference/runtime/window#windowsetalwaysontop) -// Sets the window AlwaysOnTop or not on top. -export function WindowSetAlwaysOnTop(b: boolean): void; - -// [WindowSetSystemDefaultTheme](https://wails.io/docs/next/reference/runtime/window#windowsetsystemdefaulttheme) -// *Windows only* -// Sets window theme to system default (dark/light). -export function WindowSetSystemDefaultTheme(): void; - -// [WindowSetLightTheme](https://wails.io/docs/next/reference/runtime/window#windowsetlighttheme) -// *Windows only* -// Sets window to light theme. -export function WindowSetLightTheme(): void; - -// [WindowSetDarkTheme](https://wails.io/docs/next/reference/runtime/window#windowsetdarktheme) -// *Windows only* -// Sets window to dark theme. -export function WindowSetDarkTheme(): void; - -// [WindowCenter](https://wails.io/docs/reference/runtime/window#windowcenter) -// Centers the window on the monitor the window is currently on. -export function WindowCenter(): void; - -// [WindowSetTitle](https://wails.io/docs/reference/runtime/window#windowsettitle) -// Sets the text in the window title bar. -export function WindowSetTitle(title: string): void; - -// [WindowFullscreen](https://wails.io/docs/reference/runtime/window#windowfullscreen) -// Makes the window full screen. -export function WindowFullscreen(): void; - -// [WindowUnfullscreen](https://wails.io/docs/reference/runtime/window#windowunfullscreen) -// Restores the previous window dimensions and position prior to full screen. -export function WindowUnfullscreen(): void; - -// [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize) -// Sets the width and height of the window. -export function WindowSetSize(width: number, height: number): void; - -// [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize) -// Gets the width and height of the window. -export function WindowGetSize(): Promise; - -// [WindowSetMaxSize](https://wails.io/docs/reference/runtime/window#windowsetmaxsize) -// Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMaxSize(width: number, height: number): void; - -// [WindowSetMinSize](https://wails.io/docs/reference/runtime/window#windowsetminsize) -// Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMinSize(width: number, height: number): void; - -// [WindowSetPosition](https://wails.io/docs/reference/runtime/window#windowsetposition) -// Sets the window position relative to the monitor the window is currently on. -export function WindowSetPosition(x: number, y: number): void; - -// [WindowGetPosition](https://wails.io/docs/reference/runtime/window#windowgetposition) -// Gets the window position relative to the monitor the window is currently on. -export function WindowGetPosition(): Promise; - -// [WindowHide](https://wails.io/docs/reference/runtime/window#windowhide) -// Hides the window. -export function WindowHide(): void; - -// [WindowShow](https://wails.io/docs/reference/runtime/window#windowshow) -// Shows the window, if it is currently hidden. -export function WindowShow(): void; - -// [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise) -// Maximises the window to fill the screen. -export function WindowMaximise(): void; - -// [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise) -// Toggles between Maximised and UnMaximised. -export function WindowToggleMaximise(): void; - -// [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise) -// Restores the window to the dimensions and position prior to maximising. -export function WindowUnmaximise(): void; - -// [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise) -// Minimises the window. -export function WindowMinimise(): void; - -// [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise) -// Restores the window to the dimensions and position prior to minimising. -export function WindowUnminimise(): void; - -// [WindowSetBackgroundColour](https://wails.io/docs/reference/runtime/window#windowsetbackgroundcolour) -// Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels. -export function WindowSetBackgroundColour(R: number, G: number, B: number, A: number): void; - -// [ScreenGetAll](https://wails.io/docs/reference/runtime/window#screengetall) -// Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system. -export function ScreenGetAll(): Promise; - -// [BrowserOpenURL](https://wails.io/docs/reference/runtime/browser#browseropenurl) -// Opens the given URL in the system browser. -export function BrowserOpenURL(url: string): void; - -// [Environment](https://wails.io/docs/reference/runtime/intro#environment) -// Returns information about the environment -export function Environment(): Promise; - -// [Quit](https://wails.io/docs/reference/runtime/intro#quit) -// Quits the application. -export function Quit(): void; - -// [Hide](https://wails.io/docs/reference/runtime/intro#hide) -// Hides the application. -export function Hide(): void; - -// [Show](https://wails.io/docs/reference/runtime/intro#show) -// Shows the application. -export function Show(): void; diff --git a/v2/pkg/templates/templates/preact/frontend/wailsjs/runtime/runtime.js b/v2/pkg/templates/templates/preact/frontend/wailsjs/runtime/runtime.js deleted file mode 100644 index b5ae16d56..000000000 --- a/v2/pkg/templates/templates/preact/frontend/wailsjs/runtime/runtime.js +++ /dev/null @@ -1,182 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export function LogPrint(message) { - window.runtime.LogPrint(message); -} - -export function LogTrace(message) { - window.runtime.LogTrace(message); -} - -export function LogDebug(message) { - window.runtime.LogDebug(message); -} - -export function LogInfo(message) { - window.runtime.LogInfo(message); -} - -export function LogWarning(message) { - window.runtime.LogWarning(message); -} - -export function LogError(message) { - window.runtime.LogError(message); -} - -export function LogFatal(message) { - window.runtime.LogFatal(message); -} - -export function EventsOnMultiple(eventName, callback, maxCallbacks) { - window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks); -} - -export function EventsOn(eventName, callback) { - EventsOnMultiple(eventName, callback, -1); -} - -export function EventsOff(eventName) { - return window.runtime.EventsOff(eventName); -} - -export function EventsOffAll() { - return window.runtime.EventsOffAll(); -} - -export function EventsOnce(eventName, callback) { - EventsOnMultiple(eventName, callback, 1); -} - -export function EventsEmit(eventName) { - let args = [eventName].slice.call(arguments); - return window.runtime.EventsEmit.apply(null, args); -} - -export function WindowReload() { - window.runtime.WindowReload(); -} - -export function WindowReloadApp() { - window.runtime.WindowReloadApp(); -} - -export function WindowSetAlwaysOnTop(b) { - window.runtime.WindowSetAlwaysOnTop(b); -} - -export function WindowSetSystemDefaultTheme() { - window.runtime.WindowSetSystemDefaultTheme(); -} - -export function WindowSetLightTheme() { - window.runtime.WindowSetLightTheme(); -} - -export function WindowSetDarkTheme() { - window.runtime.WindowSetDarkTheme(); -} - -export function WindowCenter() { - window.runtime.WindowCenter(); -} - -export function WindowSetTitle(title) { - window.runtime.WindowSetTitle(title); -} - -export function WindowFullscreen() { - window.runtime.WindowFullscreen(); -} - -export function WindowUnfullscreen() { - window.runtime.WindowUnfullscreen(); -} - -export function WindowGetSize() { - return window.runtime.WindowGetSize(); -} - -export function WindowSetSize(width, height) { - window.runtime.WindowSetSize(width, height); -} - -export function WindowSetMaxSize(width, height) { - window.runtime.WindowSetMaxSize(width, height); -} - -export function WindowSetMinSize(width, height) { - window.runtime.WindowSetMinSize(width, height); -} - -export function WindowSetPosition(x, y) { - window.runtime.WindowSetPosition(x, y); -} - -export function WindowGetPosition() { - return window.runtime.WindowGetPosition(); -} - -export function WindowHide() { - window.runtime.WindowHide(); -} - -export function WindowShow() { - window.runtime.WindowShow(); -} - -export function WindowMaximise() { - window.runtime.WindowMaximise(); -} - -export function WindowToggleMaximise() { - window.runtime.WindowToggleMaximise(); -} - -export function WindowUnmaximise() { - window.runtime.WindowUnmaximise(); -} - -export function WindowMinimise() { - window.runtime.WindowMinimise(); -} - -export function WindowUnminimise() { - window.runtime.WindowUnminimise(); -} - -export function WindowSetBackgroundColour(R, G, B, A) { - window.runtime.WindowSetBackgroundColour(R, G, B, A); -} - -export function ScreenGetAll() { - return window.runtime.ScreenGetAll(); -} - -export function BrowserOpenURL(url) { - window.runtime.BrowserOpenURL(url); -} - -export function Environment() { - return window.runtime.Environment(); -} - -export function Quit() { - window.runtime.Quit(); -} - -export function Hide() { - window.runtime.Hide(); -} - -export function Show() { - window.runtime.Show(); -} diff --git a/v2/pkg/templates/templates/preact/go.mod.tmpl b/v2/pkg/templates/templates/preact/go.mod.tmpl deleted file mode 100644 index 4b34d1668..000000000 --- a/v2/pkg/templates/templates/preact/go.mod.tmpl +++ /dev/null @@ -1,7 +0,0 @@ -module changeme - -go 1.23.0 - -require github.com/wailsapp/wails/v2 {{.WailsVersion}} - -// replace github.com/wailsapp/wails/v2 {{.WailsVersion}} => {{.WailsDirectory}} \ No newline at end of file diff --git a/v2/pkg/templates/templates/preact/main.go.tmpl b/v2/pkg/templates/templates/preact/main.go.tmpl deleted file mode 100644 index e24782be3..000000000 --- a/v2/pkg/templates/templates/preact/main.go.tmpl +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import ( - "embed" - - "github.com/wailsapp/wails/v2" - "github.com/wailsapp/wails/v2/pkg/options" - "github.com/wailsapp/wails/v2/pkg/options/assetserver" -) - -//go:embed all:frontend/dist -var assets embed.FS - -func main() { - // Create an instance of the app structure - app := NewApp() - - // Create application with options - err := wails.Run(&options.App{ - Title: "{{.ProjectName}}", - Width: 1024, - Height: 768, - AssetServer: &assetserver.Options{ - Assets: assets, - }, - BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, - OnStartup: app.startup, - Bind: []interface{}{ - app, - }, - }) - - if err != nil { - println("Error:", err.Error()) - } -} diff --git a/v2/pkg/templates/templates/preact/template.json b/v2/pkg/templates/templates/preact/template.json deleted file mode 100644 index 034c37478..000000000 --- a/v2/pkg/templates/templates/preact/template.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "Preact + Vite", - "shortname": "preact", - "author": "Lea Anthony", - "description": "Preact + Vite development server", - "helpurl": "https://wails.io" -} \ No newline at end of file diff --git a/v2/pkg/templates/templates/preact/wails.tmpl.json b/v2/pkg/templates/templates/preact/wails.tmpl.json deleted file mode 100644 index c39b2cb7d..000000000 --- a/v2/pkg/templates/templates/preact/wails.tmpl.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "$schema": "https://wails.io/schemas/config.v2.json", - "name": "{{.ProjectName}}", - "outputfilename": "{{.BinaryName}}", - "frontend:install": "npm install", - "frontend:build": "npm run build", - "frontend:dev:watcher": "npm run dev", - "frontend:dev:serverUrl": "auto", - "author": { - "name": "{{.AuthorName}}", - "email": "{{.AuthorEmail}}" - } -} diff --git a/v2/pkg/templates/templates/react-ts/.gitignore.tmpl b/v2/pkg/templates/templates/react-ts/.gitignore.tmpl deleted file mode 100644 index 129d52294..000000000 --- a/v2/pkg/templates/templates/react-ts/.gitignore.tmpl +++ /dev/null @@ -1,3 +0,0 @@ -build/bin -node_modules -frontend/dist diff --git a/v2/pkg/templates/templates/react-ts/README.md b/v2/pkg/templates/templates/react-ts/README.md deleted file mode 100644 index d2169cc44..000000000 --- a/v2/pkg/templates/templates/react-ts/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# README - -## About - -This is the official Wails React-TS template. - -You can configure the project by editing `wails.json`. More information about the project settings can be found -here: https://wails.io/docs/reference/project-config - -## Live Development - -To run in live development mode, run `wails dev` in the project directory. This will run a Vite development -server that will provide very fast hot reload of your frontend changes. If you want to develop in a browser -and have access to your Go methods, there is also a dev server that runs on http://localhost:34115. Connect -to this in your browser, and you can call your Go code from devtools. - -## Building - -To build a redistributable, production mode package, use `wails build`. diff --git a/v2/pkg/templates/templates/react-ts/app.tmpl.go b/v2/pkg/templates/templates/react-ts/app.tmpl.go deleted file mode 100644 index af53038a1..000000000 --- a/v2/pkg/templates/templates/react-ts/app.tmpl.go +++ /dev/null @@ -1,27 +0,0 @@ -package main - -import ( - "context" - "fmt" -) - -// App struct -type App struct { - ctx context.Context -} - -// NewApp creates a new App application struct -func NewApp() *App { - return &App{} -} - -// startup is called when the app starts. The context is saved -// so we can call the runtime methods -func (a *App) startup(ctx context.Context) { - a.ctx = ctx -} - -// Greet returns a greeting for the given name -func (a *App) Greet(name string) string { - return fmt.Sprintf("Hello %s, It's show time!", name) -} diff --git a/v2/pkg/templates/templates/react-ts/frontend/dist/gitkeep b/v2/pkg/templates/templates/react-ts/frontend/dist/gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/v2/pkg/templates/templates/react-ts/frontend/index.tmpl.html b/v2/pkg/templates/templates/react-ts/frontend/index.tmpl.html deleted file mode 100644 index a2023cac7..000000000 --- a/v2/pkg/templates/templates/react-ts/frontend/index.tmpl.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - {{.ProjectName}} - - -
- - - - diff --git a/v2/pkg/templates/templates/react-ts/frontend/package.json b/v2/pkg/templates/templates/react-ts/frontend/package.json deleted file mode 100644 index f0106ca9a..000000000 --- a/v2/pkg/templates/templates/react-ts/frontend/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "frontend", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "dependencies": { - "react": "^18.2.0", - "react-dom": "^18.2.0" - }, - "devDependencies": { - "@types/react": "^18.0.17", - "@types/react-dom": "^18.0.6", - "@vitejs/plugin-react": "^2.0.1", - "typescript": "^4.6.4", - "vite": "^3.0.7" - } -} \ No newline at end of file diff --git a/v2/pkg/templates/templates/react-ts/frontend/src/App.css b/v2/pkg/templates/templates/react-ts/frontend/src/App.css deleted file mode 100644 index f949d9c18..000000000 --- a/v2/pkg/templates/templates/react-ts/frontend/src/App.css +++ /dev/null @@ -1,59 +0,0 @@ -#app { - height: 100vh; - text-align: center; -} - -#logo { - display: block; - width: 50%; - height: 50%; - margin: auto; - padding: 10% 0 0; - background-position: center; - background-repeat: no-repeat; - background-size: 100% 100%; - background-origin: content-box; -} - -.result { - height: 20px; - line-height: 20px; - margin: 1.5rem auto; -} - -.input-box .btn { - width: 60px; - height: 30px; - line-height: 30px; - border-radius: 3px; - border: none; - margin: 0 0 0 20px; - padding: 0 8px; - cursor: pointer; -} - -.input-box .btn:hover { - background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%); - color: #333333; -} - -.input-box .input { - border: none; - border-radius: 3px; - outline: none; - height: 30px; - line-height: 30px; - padding: 0 10px; - background-color: rgba(240, 240, 240, 1); - -webkit-font-smoothing: antialiased; -} - -.input-box .input:hover { - border: none; - background-color: rgba(255, 255, 255, 1); -} - -.input-box .input:focus { - border: none; - background-color: rgba(255, 255, 255, 1); -} \ No newline at end of file diff --git a/v2/pkg/templates/templates/react-ts/frontend/src/App.tsx b/v2/pkg/templates/templates/react-ts/frontend/src/App.tsx deleted file mode 100644 index a6e56f9f8..000000000 --- a/v2/pkg/templates/templates/react-ts/frontend/src/App.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import {useState} from 'react'; -import logo from './assets/images/logo-universal.png'; -import './App.css'; -import {Greet} from "../wailsjs/go/main/App"; - -function App() { - const [resultText, setResultText] = useState("Please enter your name below 👇"); - const [name, setName] = useState(''); - const updateName = (e: any) => setName(e.target.value); - const updateResultText = (result: string) => setResultText(result); - - function greet() { - Greet(name).then(updateResultText); - } - - return ( -
- -
{resultText}
-
- - -
-
- ) -} - -export default App diff --git a/v2/pkg/templates/templates/react-ts/frontend/src/assets/fonts/OFL.txt b/v2/pkg/templates/templates/react-ts/frontend/src/assets/fonts/OFL.txt deleted file mode 100644 index 9cac04ce8..000000000 --- a/v2/pkg/templates/templates/react-ts/frontend/src/assets/fonts/OFL.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com), - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/v2/pkg/templates/templates/react-ts/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 b/v2/pkg/templates/templates/react-ts/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 deleted file mode 100644 index 2f9cc5964..000000000 Binary files a/v2/pkg/templates/templates/react-ts/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 and /dev/null differ diff --git a/v2/pkg/templates/templates/react-ts/frontend/src/assets/images/logo-universal.png b/v2/pkg/templates/templates/react-ts/frontend/src/assets/images/logo-universal.png deleted file mode 100644 index 99ac71f5a..000000000 Binary files a/v2/pkg/templates/templates/react-ts/frontend/src/assets/images/logo-universal.png and /dev/null differ diff --git a/v2/pkg/templates/templates/react-ts/frontend/src/main.tsx b/v2/pkg/templates/templates/react-ts/frontend/src/main.tsx deleted file mode 100644 index 3626ff303..000000000 --- a/v2/pkg/templates/templates/react-ts/frontend/src/main.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react' -import {createRoot} from 'react-dom/client' -import './style.css' -import App from './App' - -const container = document.getElementById('root') - -const root = createRoot(container!) - -root.render( - - - -) diff --git a/v2/pkg/templates/templates/react-ts/frontend/src/style.css b/v2/pkg/templates/templates/react-ts/frontend/src/style.css deleted file mode 100644 index 3940d6c63..000000000 --- a/v2/pkg/templates/templates/react-ts/frontend/src/style.css +++ /dev/null @@ -1,26 +0,0 @@ -html { - background-color: rgba(27, 38, 54, 1); - text-align: center; - color: white; -} - -body { - margin: 0; - color: white; - font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", - "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", - sans-serif; -} - -@font-face { - font-family: "Nunito"; - font-style: normal; - font-weight: 400; - src: local(""), - url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2"); -} - -#app { - height: 100vh; - text-align: center; -} diff --git a/v2/pkg/templates/templates/react-ts/frontend/src/vite-env.d.ts b/v2/pkg/templates/templates/react-ts/frontend/src/vite-env.d.ts deleted file mode 100644 index 11f02fe2a..000000000 --- a/v2/pkg/templates/templates/react-ts/frontend/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/v2/pkg/templates/templates/react-ts/frontend/tsconfig.json b/v2/pkg/templates/templates/react-ts/frontend/tsconfig.json deleted file mode 100644 index 823e83d11..000000000 --- a/v2/pkg/templates/templates/react-ts/frontend/tsconfig.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "lib": [ - "DOM", - "DOM.Iterable", - "ESNext" - ], - "allowJs": false, - "skipLibCheck": true, - "esModuleInterop": false, - "allowSyntheticDefaultImports": true, - "strict": true, - "forceConsistentCasingInFileNames": true, - "module": "ESNext", - "moduleResolution": "Node", - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "react-jsx" - }, - "include": [ - "src" - ], - "references": [ - { - "path": "./tsconfig.node.json" - } - ] -} diff --git a/v2/pkg/templates/templates/react-ts/frontend/tsconfig.node.json b/v2/pkg/templates/templates/react-ts/frontend/tsconfig.node.json deleted file mode 100644 index b8afcc8fa..000000000 --- a/v2/pkg/templates/templates/react-ts/frontend/tsconfig.node.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "module": "ESNext", - "moduleResolution": "Node", - "allowSyntheticDefaultImports": true - }, - "include": [ - "vite.config.ts" - ] -} diff --git a/v2/pkg/templates/templates/react-ts/frontend/vite.config.ts b/v2/pkg/templates/templates/react-ts/frontend/vite.config.ts deleted file mode 100644 index 49550655a..000000000 --- a/v2/pkg/templates/templates/react-ts/frontend/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import {defineConfig} from 'vite' -import react from '@vitejs/plugin-react' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react()] -}) diff --git a/v2/pkg/templates/templates/react-ts/frontend/wailsjs/go/main/App.d.ts b/v2/pkg/templates/templates/react-ts/frontend/wailsjs/go/main/App.d.ts deleted file mode 100644 index 43173cfce..000000000 --- a/v2/pkg/templates/templates/react-ts/frontend/wailsjs/go/main/App.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Greet(arg1: string): Promise; diff --git a/v2/pkg/templates/templates/react-ts/frontend/wailsjs/go/main/App.js b/v2/pkg/templates/templates/react-ts/frontend/wailsjs/go/main/App.js deleted file mode 100644 index 0ee085c95..000000000 --- a/v2/pkg/templates/templates/react-ts/frontend/wailsjs/go/main/App.js +++ /dev/null @@ -1,7 +0,0 @@ -// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Greet(arg1) { - return window['go']['main']['App']['Greet'](arg1); -} diff --git a/v2/pkg/templates/templates/react-ts/frontend/wailsjs/runtime/package.json b/v2/pkg/templates/templates/react-ts/frontend/wailsjs/runtime/package.json deleted file mode 100644 index 1e7c8a5d7..000000000 --- a/v2/pkg/templates/templates/react-ts/frontend/wailsjs/runtime/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "@wailsapp/runtime", - "version": "2.0.0", - "description": "Wails Javascript runtime library", - "main": "runtime.js", - "types": "runtime.d.ts", - "scripts": { - }, - "repository": { - "type": "git", - "url": "git+https://github.com/wailsapp/wails.git" - }, - "keywords": [ - "Wails", - "Javascript", - "Go" - ], - "author": "Lea Anthony ", - "license": "MIT", - "bugs": { - "url": "https://github.com/wailsapp/wails/issues" - }, - "homepage": "https://github.com/wailsapp/wails#readme" -} diff --git a/v2/pkg/templates/templates/react-ts/frontend/wailsjs/runtime/runtime.d.ts b/v2/pkg/templates/templates/react-ts/frontend/wailsjs/runtime/runtime.d.ts deleted file mode 100644 index 336fb07aa..000000000 --- a/v2/pkg/templates/templates/react-ts/frontend/wailsjs/runtime/runtime.d.ts +++ /dev/null @@ -1,211 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export interface Position { - x: number; - y: number; -} - -export interface Size { - w: number; - h: number; -} - -export interface Screen { - isCurrent: boolean; - isPrimary: boolean; - width: number - height: number -} - -// Environment information such as platform, buildtype, ... -export interface EnvironmentInfo { - buildType: string; - platform: string; - arch: string; -} - -// [EventsEmit](https://wails.io/docs/reference/runtime/events#eventsemit) -// emits the given event. Optional data may be passed with the event. -// This will trigger any event listeners. -export function EventsEmit(eventName: string, ...data: any): void; - -// [EventsOn](https://wails.io/docs/reference/runtime/events#eventson) sets up a listener for the given event name. -export function EventsOn(eventName: string, callback: (...data: any) => void): void; - -// [EventsOnMultiple](https://wails.io/docs/reference/runtime/events#eventsonmultiple) -// sets up a listener for the given event name, but will only trigger a given number times. -export function EventsOnMultiple(eventName: string, callback: (...data: any) => void, maxCallbacks: number): void; - -// [EventsOnce](https://wails.io/docs/reference/runtime/events#eventsonce) -// sets up a listener for the given event name, but will only trigger once. -export function EventsOnce(eventName: string, callback: (...data: any) => void): void; - -// [EventsOff](https://wails.io/docs/reference/runtime/events#eventsff) -// unregisters the listener for the given event name. -export function EventsOff(eventName: string): void; - -// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) -// unregisters all event listeners. -export function EventsOffAll(): void; - -// [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) -// logs the given message as a raw message -export function LogPrint(message: string): void; - -// [LogTrace](https://wails.io/docs/reference/runtime/log#logtrace) -// logs the given message at the `trace` log level. -export function LogTrace(message: string): void; - -// [LogDebug](https://wails.io/docs/reference/runtime/log#logdebug) -// logs the given message at the `debug` log level. -export function LogDebug(message: string): void; - -// [LogError](https://wails.io/docs/reference/runtime/log#logerror) -// logs the given message at the `error` log level. -export function LogError(message: string): void; - -// [LogFatal](https://wails.io/docs/reference/runtime/log#logfatal) -// logs the given message at the `fatal` log level. -// The application will quit after calling this method. -export function LogFatal(message: string): void; - -// [LogInfo](https://wails.io/docs/reference/runtime/log#loginfo) -// logs the given message at the `info` log level. -export function LogInfo(message: string): void; - -// [LogWarning](https://wails.io/docs/reference/runtime/log#logwarning) -// logs the given message at the `warning` log level. -export function LogWarning(message: string): void; - -// [WindowReload](https://wails.io/docs/reference/runtime/window#windowreload) -// Forces a reload by the main application as well as connected browsers. -export function WindowReload(): void; - -// [WindowReloadApp](https://wails.io/docs/reference/runtime/window#windowreloadapp) -// Reloads the application frontend. -export function WindowReloadApp(): void; - -// [WindowSetAlwaysOnTop](https://wails.io/docs/reference/runtime/window#windowsetalwaysontop) -// Sets the window AlwaysOnTop or not on top. -export function WindowSetAlwaysOnTop(b: boolean): void; - -// [WindowSetSystemDefaultTheme](https://wails.io/docs/next/reference/runtime/window#windowsetsystemdefaulttheme) -// *Windows only* -// Sets window theme to system default (dark/light). -export function WindowSetSystemDefaultTheme(): void; - -// [WindowSetLightTheme](https://wails.io/docs/next/reference/runtime/window#windowsetlighttheme) -// *Windows only* -// Sets window to light theme. -export function WindowSetLightTheme(): void; - -// [WindowSetDarkTheme](https://wails.io/docs/next/reference/runtime/window#windowsetdarktheme) -// *Windows only* -// Sets window to dark theme. -export function WindowSetDarkTheme(): void; - -// [WindowCenter](https://wails.io/docs/reference/runtime/window#windowcenter) -// Centers the window on the monitor the window is currently on. -export function WindowCenter(): void; - -// [WindowSetTitle](https://wails.io/docs/reference/runtime/window#windowsettitle) -// Sets the text in the window title bar. -export function WindowSetTitle(title: string): void; - -// [WindowFullscreen](https://wails.io/docs/reference/runtime/window#windowfullscreen) -// Makes the window full screen. -export function WindowFullscreen(): void; - -// [WindowUnfullscreen](https://wails.io/docs/reference/runtime/window#windowunfullscreen) -// Restores the previous window dimensions and position prior to full screen. -export function WindowUnfullscreen(): void; - -// [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize) -// Sets the width and height of the window. -export function WindowSetSize(width: number, height: number): void; - -// [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize) -// Gets the width and height of the window. -export function WindowGetSize(): Promise; - -// [WindowSetMaxSize](https://wails.io/docs/reference/runtime/window#windowsetmaxsize) -// Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMaxSize(width: number, height: number): void; - -// [WindowSetMinSize](https://wails.io/docs/reference/runtime/window#windowsetminsize) -// Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMinSize(width: number, height: number): void; - -// [WindowSetPosition](https://wails.io/docs/reference/runtime/window#windowsetposition) -// Sets the window position relative to the monitor the window is currently on. -export function WindowSetPosition(x: number, y: number): void; - -// [WindowGetPosition](https://wails.io/docs/reference/runtime/window#windowgetposition) -// Gets the window position relative to the monitor the window is currently on. -export function WindowGetPosition(): Promise; - -// [WindowHide](https://wails.io/docs/reference/runtime/window#windowhide) -// Hides the window. -export function WindowHide(): void; - -// [WindowShow](https://wails.io/docs/reference/runtime/window#windowshow) -// Shows the window, if it is currently hidden. -export function WindowShow(): void; - -// [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise) -// Maximises the window to fill the screen. -export function WindowMaximise(): void; - -// [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise) -// Toggles between Maximised and UnMaximised. -export function WindowToggleMaximise(): void; - -// [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise) -// Restores the window to the dimensions and position prior to maximising. -export function WindowUnmaximise(): void; - -// [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise) -// Minimises the window. -export function WindowMinimise(): void; - -// [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise) -// Restores the window to the dimensions and position prior to minimising. -export function WindowUnminimise(): void; - -// [WindowSetBackgroundColour](https://wails.io/docs/reference/runtime/window#windowsetbackgroundcolour) -// Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels. -export function WindowSetBackgroundColour(R: number, G: number, B: number, A: number): void; - -// [ScreenGetAll](https://wails.io/docs/reference/runtime/window#screengetall) -// Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system. -export function ScreenGetAll(): Promise; - -// [BrowserOpenURL](https://wails.io/docs/reference/runtime/browser#browseropenurl) -// Opens the given URL in the system browser. -export function BrowserOpenURL(url: string): void; - -// [Environment](https://wails.io/docs/reference/runtime/intro#environment) -// Returns information about the environment -export function Environment(): Promise; - -// [Quit](https://wails.io/docs/reference/runtime/intro#quit) -// Quits the application. -export function Quit(): void; - -// [Hide](https://wails.io/docs/reference/runtime/intro#hide) -// Hides the application. -export function Hide(): void; - -// [Show](https://wails.io/docs/reference/runtime/intro#show) -// Shows the application. -export function Show(): void; diff --git a/v2/pkg/templates/templates/react-ts/frontend/wailsjs/runtime/runtime.js b/v2/pkg/templates/templates/react-ts/frontend/wailsjs/runtime/runtime.js deleted file mode 100644 index b5ae16d56..000000000 --- a/v2/pkg/templates/templates/react-ts/frontend/wailsjs/runtime/runtime.js +++ /dev/null @@ -1,182 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export function LogPrint(message) { - window.runtime.LogPrint(message); -} - -export function LogTrace(message) { - window.runtime.LogTrace(message); -} - -export function LogDebug(message) { - window.runtime.LogDebug(message); -} - -export function LogInfo(message) { - window.runtime.LogInfo(message); -} - -export function LogWarning(message) { - window.runtime.LogWarning(message); -} - -export function LogError(message) { - window.runtime.LogError(message); -} - -export function LogFatal(message) { - window.runtime.LogFatal(message); -} - -export function EventsOnMultiple(eventName, callback, maxCallbacks) { - window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks); -} - -export function EventsOn(eventName, callback) { - EventsOnMultiple(eventName, callback, -1); -} - -export function EventsOff(eventName) { - return window.runtime.EventsOff(eventName); -} - -export function EventsOffAll() { - return window.runtime.EventsOffAll(); -} - -export function EventsOnce(eventName, callback) { - EventsOnMultiple(eventName, callback, 1); -} - -export function EventsEmit(eventName) { - let args = [eventName].slice.call(arguments); - return window.runtime.EventsEmit.apply(null, args); -} - -export function WindowReload() { - window.runtime.WindowReload(); -} - -export function WindowReloadApp() { - window.runtime.WindowReloadApp(); -} - -export function WindowSetAlwaysOnTop(b) { - window.runtime.WindowSetAlwaysOnTop(b); -} - -export function WindowSetSystemDefaultTheme() { - window.runtime.WindowSetSystemDefaultTheme(); -} - -export function WindowSetLightTheme() { - window.runtime.WindowSetLightTheme(); -} - -export function WindowSetDarkTheme() { - window.runtime.WindowSetDarkTheme(); -} - -export function WindowCenter() { - window.runtime.WindowCenter(); -} - -export function WindowSetTitle(title) { - window.runtime.WindowSetTitle(title); -} - -export function WindowFullscreen() { - window.runtime.WindowFullscreen(); -} - -export function WindowUnfullscreen() { - window.runtime.WindowUnfullscreen(); -} - -export function WindowGetSize() { - return window.runtime.WindowGetSize(); -} - -export function WindowSetSize(width, height) { - window.runtime.WindowSetSize(width, height); -} - -export function WindowSetMaxSize(width, height) { - window.runtime.WindowSetMaxSize(width, height); -} - -export function WindowSetMinSize(width, height) { - window.runtime.WindowSetMinSize(width, height); -} - -export function WindowSetPosition(x, y) { - window.runtime.WindowSetPosition(x, y); -} - -export function WindowGetPosition() { - return window.runtime.WindowGetPosition(); -} - -export function WindowHide() { - window.runtime.WindowHide(); -} - -export function WindowShow() { - window.runtime.WindowShow(); -} - -export function WindowMaximise() { - window.runtime.WindowMaximise(); -} - -export function WindowToggleMaximise() { - window.runtime.WindowToggleMaximise(); -} - -export function WindowUnmaximise() { - window.runtime.WindowUnmaximise(); -} - -export function WindowMinimise() { - window.runtime.WindowMinimise(); -} - -export function WindowUnminimise() { - window.runtime.WindowUnminimise(); -} - -export function WindowSetBackgroundColour(R, G, B, A) { - window.runtime.WindowSetBackgroundColour(R, G, B, A); -} - -export function ScreenGetAll() { - return window.runtime.ScreenGetAll(); -} - -export function BrowserOpenURL(url) { - window.runtime.BrowserOpenURL(url); -} - -export function Environment() { - return window.runtime.Environment(); -} - -export function Quit() { - window.runtime.Quit(); -} - -export function Hide() { - window.runtime.Hide(); -} - -export function Show() { - window.runtime.Show(); -} diff --git a/v2/pkg/templates/templates/react-ts/go.mod.tmpl b/v2/pkg/templates/templates/react-ts/go.mod.tmpl deleted file mode 100644 index 4b34d1668..000000000 --- a/v2/pkg/templates/templates/react-ts/go.mod.tmpl +++ /dev/null @@ -1,7 +0,0 @@ -module changeme - -go 1.23.0 - -require github.com/wailsapp/wails/v2 {{.WailsVersion}} - -// replace github.com/wailsapp/wails/v2 {{.WailsVersion}} => {{.WailsDirectory}} \ No newline at end of file diff --git a/v2/pkg/templates/templates/react-ts/main.go.tmpl b/v2/pkg/templates/templates/react-ts/main.go.tmpl deleted file mode 100644 index e24782be3..000000000 --- a/v2/pkg/templates/templates/react-ts/main.go.tmpl +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import ( - "embed" - - "github.com/wailsapp/wails/v2" - "github.com/wailsapp/wails/v2/pkg/options" - "github.com/wailsapp/wails/v2/pkg/options/assetserver" -) - -//go:embed all:frontend/dist -var assets embed.FS - -func main() { - // Create an instance of the app structure - app := NewApp() - - // Create application with options - err := wails.Run(&options.App{ - Title: "{{.ProjectName}}", - Width: 1024, - Height: 768, - AssetServer: &assetserver.Options{ - Assets: assets, - }, - BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, - OnStartup: app.startup, - Bind: []interface{}{ - app, - }, - }) - - if err != nil { - println("Error:", err.Error()) - } -} diff --git a/v2/pkg/templates/templates/react-ts/template.json b/v2/pkg/templates/templates/react-ts/template.json deleted file mode 100644 index 7e9753770..000000000 --- a/v2/pkg/templates/templates/react-ts/template.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "React + Vite (Typescript)", - "shortname": "react-ts", - "author": "Lea Anthony", - "description": "React + Vite development server", - "helpurl": "https://wails.io" -} \ No newline at end of file diff --git a/v2/pkg/templates/templates/react-ts/wails.tmpl.json b/v2/pkg/templates/templates/react-ts/wails.tmpl.json deleted file mode 100644 index c39b2cb7d..000000000 --- a/v2/pkg/templates/templates/react-ts/wails.tmpl.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "$schema": "https://wails.io/schemas/config.v2.json", - "name": "{{.ProjectName}}", - "outputfilename": "{{.BinaryName}}", - "frontend:install": "npm install", - "frontend:build": "npm run build", - "frontend:dev:watcher": "npm run dev", - "frontend:dev:serverUrl": "auto", - "author": { - "name": "{{.AuthorName}}", - "email": "{{.AuthorEmail}}" - } -} diff --git a/v2/pkg/templates/templates/react/.gitignore.tmpl b/v2/pkg/templates/templates/react/.gitignore.tmpl deleted file mode 100644 index 129d52294..000000000 --- a/v2/pkg/templates/templates/react/.gitignore.tmpl +++ /dev/null @@ -1,3 +0,0 @@ -build/bin -node_modules -frontend/dist diff --git a/v2/pkg/templates/templates/react/README.md b/v2/pkg/templates/templates/react/README.md deleted file mode 100644 index 4db88f690..000000000 --- a/v2/pkg/templates/templates/react/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# README - -## About - -This is the official Wails React template. - -You can configure the project by editing `wails.json`. More information about the project settings can be found -here: https://wails.io/docs/reference/project-config - -## Live Development - -To run in live development mode, run `wails dev` in the project directory. This will run a Vite development -server that will provide very fast hot reload of your frontend changes. If you want to develop in a browser -and have access to your Go methods, there is also a dev server that runs on http://localhost:34115. Connect -to this in your browser, and you can call your Go code from devtools. - -## Building - -To build a redistributable, production mode package, use `wails build`. diff --git a/v2/pkg/templates/templates/react/app.tmpl.go b/v2/pkg/templates/templates/react/app.tmpl.go deleted file mode 100644 index af53038a1..000000000 --- a/v2/pkg/templates/templates/react/app.tmpl.go +++ /dev/null @@ -1,27 +0,0 @@ -package main - -import ( - "context" - "fmt" -) - -// App struct -type App struct { - ctx context.Context -} - -// NewApp creates a new App application struct -func NewApp() *App { - return &App{} -} - -// startup is called when the app starts. The context is saved -// so we can call the runtime methods -func (a *App) startup(ctx context.Context) { - a.ctx = ctx -} - -// Greet returns a greeting for the given name -func (a *App) Greet(name string) string { - return fmt.Sprintf("Hello %s, It's show time!", name) -} diff --git a/v2/pkg/templates/templates/react/frontend/dist/gitkeep b/v2/pkg/templates/templates/react/frontend/dist/gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/v2/pkg/templates/templates/react/frontend/index.tmpl.html b/v2/pkg/templates/templates/react/frontend/index.tmpl.html deleted file mode 100644 index 80aa30b89..000000000 --- a/v2/pkg/templates/templates/react/frontend/index.tmpl.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - {{.ProjectName}} - - -
- - - - diff --git a/v2/pkg/templates/templates/react/frontend/package.json b/v2/pkg/templates/templates/react/frontend/package.json deleted file mode 100644 index 3b34e1f8f..000000000 --- a/v2/pkg/templates/templates/react/frontend/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "frontend", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "vite build", - "preview": "vite preview" - }, - "dependencies": { - "react": "^18.2.0", - "react-dom": "^18.2.0" - }, - "devDependencies": { - "@types/react": "^18.0.17", - "@types/react-dom": "^18.0.6", - "@vitejs/plugin-react": "^2.0.1", - "vite": "^3.0.7" - } -} \ No newline at end of file diff --git a/v2/pkg/templates/templates/react/frontend/src/App.css b/v2/pkg/templates/templates/react/frontend/src/App.css deleted file mode 100644 index f949d9c18..000000000 --- a/v2/pkg/templates/templates/react/frontend/src/App.css +++ /dev/null @@ -1,59 +0,0 @@ -#app { - height: 100vh; - text-align: center; -} - -#logo { - display: block; - width: 50%; - height: 50%; - margin: auto; - padding: 10% 0 0; - background-position: center; - background-repeat: no-repeat; - background-size: 100% 100%; - background-origin: content-box; -} - -.result { - height: 20px; - line-height: 20px; - margin: 1.5rem auto; -} - -.input-box .btn { - width: 60px; - height: 30px; - line-height: 30px; - border-radius: 3px; - border: none; - margin: 0 0 0 20px; - padding: 0 8px; - cursor: pointer; -} - -.input-box .btn:hover { - background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%); - color: #333333; -} - -.input-box .input { - border: none; - border-radius: 3px; - outline: none; - height: 30px; - line-height: 30px; - padding: 0 10px; - background-color: rgba(240, 240, 240, 1); - -webkit-font-smoothing: antialiased; -} - -.input-box .input:hover { - border: none; - background-color: rgba(255, 255, 255, 1); -} - -.input-box .input:focus { - border: none; - background-color: rgba(255, 255, 255, 1); -} \ No newline at end of file diff --git a/v2/pkg/templates/templates/react/frontend/src/App.jsx b/v2/pkg/templates/templates/react/frontend/src/App.jsx deleted file mode 100644 index fd762291f..000000000 --- a/v2/pkg/templates/templates/react/frontend/src/App.jsx +++ /dev/null @@ -1,28 +0,0 @@ -import {useState} from 'react'; -import logo from './assets/images/logo-universal.png'; -import './App.css'; -import {Greet} from "../wailsjs/go/main/App"; - -function App() { - const [resultText, setResultText] = useState("Please enter your name below 👇"); - const [name, setName] = useState(''); - const updateName = (e) => setName(e.target.value); - const updateResultText = (result) => setResultText(result); - - function greet() { - Greet(name).then(updateResultText); - } - - return ( -
- -
{resultText}
-
- - -
-
- ) -} - -export default App diff --git a/v2/pkg/templates/templates/react/frontend/src/assets/fonts/OFL.txt b/v2/pkg/templates/templates/react/frontend/src/assets/fonts/OFL.txt deleted file mode 100644 index 9cac04ce8..000000000 --- a/v2/pkg/templates/templates/react/frontend/src/assets/fonts/OFL.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com), - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/v2/pkg/templates/templates/react/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 b/v2/pkg/templates/templates/react/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 deleted file mode 100644 index 2f9cc5964..000000000 Binary files a/v2/pkg/templates/templates/react/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 and /dev/null differ diff --git a/v2/pkg/templates/templates/react/frontend/src/assets/images/logo-universal.png b/v2/pkg/templates/templates/react/frontend/src/assets/images/logo-universal.png deleted file mode 100644 index 5421ad881..000000000 Binary files a/v2/pkg/templates/templates/react/frontend/src/assets/images/logo-universal.png and /dev/null differ diff --git a/v2/pkg/templates/templates/react/frontend/src/main.jsx b/v2/pkg/templates/templates/react/frontend/src/main.jsx deleted file mode 100644 index e50e105db..000000000 --- a/v2/pkg/templates/templates/react/frontend/src/main.jsx +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react' -import {createRoot} from 'react-dom/client' -import './style.css' -import App from './App' - -const container = document.getElementById('root') - -const root = createRoot(container) - -root.render( - - - -) diff --git a/v2/pkg/templates/templates/react/frontend/src/style.css b/v2/pkg/templates/templates/react/frontend/src/style.css deleted file mode 100644 index 3940d6c63..000000000 --- a/v2/pkg/templates/templates/react/frontend/src/style.css +++ /dev/null @@ -1,26 +0,0 @@ -html { - background-color: rgba(27, 38, 54, 1); - text-align: center; - color: white; -} - -body { - margin: 0; - color: white; - font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", - "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", - sans-serif; -} - -@font-face { - font-family: "Nunito"; - font-style: normal; - font-weight: 400; - src: local(""), - url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2"); -} - -#app { - height: 100vh; - text-align: center; -} diff --git a/v2/pkg/templates/templates/react/frontend/vite.config.js b/v2/pkg/templates/templates/react/frontend/vite.config.js deleted file mode 100644 index 49550655a..000000000 --- a/v2/pkg/templates/templates/react/frontend/vite.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import {defineConfig} from 'vite' -import react from '@vitejs/plugin-react' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react()] -}) diff --git a/v2/pkg/templates/templates/react/frontend/wailsjs/go/main/App.d.ts b/v2/pkg/templates/templates/react/frontend/wailsjs/go/main/App.d.ts deleted file mode 100644 index 43173cfce..000000000 --- a/v2/pkg/templates/templates/react/frontend/wailsjs/go/main/App.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Greet(arg1: string): Promise; diff --git a/v2/pkg/templates/templates/react/frontend/wailsjs/go/main/App.js b/v2/pkg/templates/templates/react/frontend/wailsjs/go/main/App.js deleted file mode 100644 index 0ee085c95..000000000 --- a/v2/pkg/templates/templates/react/frontend/wailsjs/go/main/App.js +++ /dev/null @@ -1,7 +0,0 @@ -// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Greet(arg1) { - return window['go']['main']['App']['Greet'](arg1); -} diff --git a/v2/pkg/templates/templates/react/frontend/wailsjs/runtime/package.json b/v2/pkg/templates/templates/react/frontend/wailsjs/runtime/package.json deleted file mode 100644 index 1e7c8a5d7..000000000 --- a/v2/pkg/templates/templates/react/frontend/wailsjs/runtime/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "@wailsapp/runtime", - "version": "2.0.0", - "description": "Wails Javascript runtime library", - "main": "runtime.js", - "types": "runtime.d.ts", - "scripts": { - }, - "repository": { - "type": "git", - "url": "git+https://github.com/wailsapp/wails.git" - }, - "keywords": [ - "Wails", - "Javascript", - "Go" - ], - "author": "Lea Anthony ", - "license": "MIT", - "bugs": { - "url": "https://github.com/wailsapp/wails/issues" - }, - "homepage": "https://github.com/wailsapp/wails#readme" -} diff --git a/v2/pkg/templates/templates/react/frontend/wailsjs/runtime/runtime.d.ts b/v2/pkg/templates/templates/react/frontend/wailsjs/runtime/runtime.d.ts deleted file mode 100644 index 336fb07aa..000000000 --- a/v2/pkg/templates/templates/react/frontend/wailsjs/runtime/runtime.d.ts +++ /dev/null @@ -1,211 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export interface Position { - x: number; - y: number; -} - -export interface Size { - w: number; - h: number; -} - -export interface Screen { - isCurrent: boolean; - isPrimary: boolean; - width: number - height: number -} - -// Environment information such as platform, buildtype, ... -export interface EnvironmentInfo { - buildType: string; - platform: string; - arch: string; -} - -// [EventsEmit](https://wails.io/docs/reference/runtime/events#eventsemit) -// emits the given event. Optional data may be passed with the event. -// This will trigger any event listeners. -export function EventsEmit(eventName: string, ...data: any): void; - -// [EventsOn](https://wails.io/docs/reference/runtime/events#eventson) sets up a listener for the given event name. -export function EventsOn(eventName: string, callback: (...data: any) => void): void; - -// [EventsOnMultiple](https://wails.io/docs/reference/runtime/events#eventsonmultiple) -// sets up a listener for the given event name, but will only trigger a given number times. -export function EventsOnMultiple(eventName: string, callback: (...data: any) => void, maxCallbacks: number): void; - -// [EventsOnce](https://wails.io/docs/reference/runtime/events#eventsonce) -// sets up a listener for the given event name, but will only trigger once. -export function EventsOnce(eventName: string, callback: (...data: any) => void): void; - -// [EventsOff](https://wails.io/docs/reference/runtime/events#eventsff) -// unregisters the listener for the given event name. -export function EventsOff(eventName: string): void; - -// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) -// unregisters all event listeners. -export function EventsOffAll(): void; - -// [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) -// logs the given message as a raw message -export function LogPrint(message: string): void; - -// [LogTrace](https://wails.io/docs/reference/runtime/log#logtrace) -// logs the given message at the `trace` log level. -export function LogTrace(message: string): void; - -// [LogDebug](https://wails.io/docs/reference/runtime/log#logdebug) -// logs the given message at the `debug` log level. -export function LogDebug(message: string): void; - -// [LogError](https://wails.io/docs/reference/runtime/log#logerror) -// logs the given message at the `error` log level. -export function LogError(message: string): void; - -// [LogFatal](https://wails.io/docs/reference/runtime/log#logfatal) -// logs the given message at the `fatal` log level. -// The application will quit after calling this method. -export function LogFatal(message: string): void; - -// [LogInfo](https://wails.io/docs/reference/runtime/log#loginfo) -// logs the given message at the `info` log level. -export function LogInfo(message: string): void; - -// [LogWarning](https://wails.io/docs/reference/runtime/log#logwarning) -// logs the given message at the `warning` log level. -export function LogWarning(message: string): void; - -// [WindowReload](https://wails.io/docs/reference/runtime/window#windowreload) -// Forces a reload by the main application as well as connected browsers. -export function WindowReload(): void; - -// [WindowReloadApp](https://wails.io/docs/reference/runtime/window#windowreloadapp) -// Reloads the application frontend. -export function WindowReloadApp(): void; - -// [WindowSetAlwaysOnTop](https://wails.io/docs/reference/runtime/window#windowsetalwaysontop) -// Sets the window AlwaysOnTop or not on top. -export function WindowSetAlwaysOnTop(b: boolean): void; - -// [WindowSetSystemDefaultTheme](https://wails.io/docs/next/reference/runtime/window#windowsetsystemdefaulttheme) -// *Windows only* -// Sets window theme to system default (dark/light). -export function WindowSetSystemDefaultTheme(): void; - -// [WindowSetLightTheme](https://wails.io/docs/next/reference/runtime/window#windowsetlighttheme) -// *Windows only* -// Sets window to light theme. -export function WindowSetLightTheme(): void; - -// [WindowSetDarkTheme](https://wails.io/docs/next/reference/runtime/window#windowsetdarktheme) -// *Windows only* -// Sets window to dark theme. -export function WindowSetDarkTheme(): void; - -// [WindowCenter](https://wails.io/docs/reference/runtime/window#windowcenter) -// Centers the window on the monitor the window is currently on. -export function WindowCenter(): void; - -// [WindowSetTitle](https://wails.io/docs/reference/runtime/window#windowsettitle) -// Sets the text in the window title bar. -export function WindowSetTitle(title: string): void; - -// [WindowFullscreen](https://wails.io/docs/reference/runtime/window#windowfullscreen) -// Makes the window full screen. -export function WindowFullscreen(): void; - -// [WindowUnfullscreen](https://wails.io/docs/reference/runtime/window#windowunfullscreen) -// Restores the previous window dimensions and position prior to full screen. -export function WindowUnfullscreen(): void; - -// [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize) -// Sets the width and height of the window. -export function WindowSetSize(width: number, height: number): void; - -// [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize) -// Gets the width and height of the window. -export function WindowGetSize(): Promise; - -// [WindowSetMaxSize](https://wails.io/docs/reference/runtime/window#windowsetmaxsize) -// Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMaxSize(width: number, height: number): void; - -// [WindowSetMinSize](https://wails.io/docs/reference/runtime/window#windowsetminsize) -// Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMinSize(width: number, height: number): void; - -// [WindowSetPosition](https://wails.io/docs/reference/runtime/window#windowsetposition) -// Sets the window position relative to the monitor the window is currently on. -export function WindowSetPosition(x: number, y: number): void; - -// [WindowGetPosition](https://wails.io/docs/reference/runtime/window#windowgetposition) -// Gets the window position relative to the monitor the window is currently on. -export function WindowGetPosition(): Promise; - -// [WindowHide](https://wails.io/docs/reference/runtime/window#windowhide) -// Hides the window. -export function WindowHide(): void; - -// [WindowShow](https://wails.io/docs/reference/runtime/window#windowshow) -// Shows the window, if it is currently hidden. -export function WindowShow(): void; - -// [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise) -// Maximises the window to fill the screen. -export function WindowMaximise(): void; - -// [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise) -// Toggles between Maximised and UnMaximised. -export function WindowToggleMaximise(): void; - -// [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise) -// Restores the window to the dimensions and position prior to maximising. -export function WindowUnmaximise(): void; - -// [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise) -// Minimises the window. -export function WindowMinimise(): void; - -// [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise) -// Restores the window to the dimensions and position prior to minimising. -export function WindowUnminimise(): void; - -// [WindowSetBackgroundColour](https://wails.io/docs/reference/runtime/window#windowsetbackgroundcolour) -// Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels. -export function WindowSetBackgroundColour(R: number, G: number, B: number, A: number): void; - -// [ScreenGetAll](https://wails.io/docs/reference/runtime/window#screengetall) -// Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system. -export function ScreenGetAll(): Promise; - -// [BrowserOpenURL](https://wails.io/docs/reference/runtime/browser#browseropenurl) -// Opens the given URL in the system browser. -export function BrowserOpenURL(url: string): void; - -// [Environment](https://wails.io/docs/reference/runtime/intro#environment) -// Returns information about the environment -export function Environment(): Promise; - -// [Quit](https://wails.io/docs/reference/runtime/intro#quit) -// Quits the application. -export function Quit(): void; - -// [Hide](https://wails.io/docs/reference/runtime/intro#hide) -// Hides the application. -export function Hide(): void; - -// [Show](https://wails.io/docs/reference/runtime/intro#show) -// Shows the application. -export function Show(): void; diff --git a/v2/pkg/templates/templates/react/frontend/wailsjs/runtime/runtime.js b/v2/pkg/templates/templates/react/frontend/wailsjs/runtime/runtime.js deleted file mode 100644 index b5ae16d56..000000000 --- a/v2/pkg/templates/templates/react/frontend/wailsjs/runtime/runtime.js +++ /dev/null @@ -1,182 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export function LogPrint(message) { - window.runtime.LogPrint(message); -} - -export function LogTrace(message) { - window.runtime.LogTrace(message); -} - -export function LogDebug(message) { - window.runtime.LogDebug(message); -} - -export function LogInfo(message) { - window.runtime.LogInfo(message); -} - -export function LogWarning(message) { - window.runtime.LogWarning(message); -} - -export function LogError(message) { - window.runtime.LogError(message); -} - -export function LogFatal(message) { - window.runtime.LogFatal(message); -} - -export function EventsOnMultiple(eventName, callback, maxCallbacks) { - window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks); -} - -export function EventsOn(eventName, callback) { - EventsOnMultiple(eventName, callback, -1); -} - -export function EventsOff(eventName) { - return window.runtime.EventsOff(eventName); -} - -export function EventsOffAll() { - return window.runtime.EventsOffAll(); -} - -export function EventsOnce(eventName, callback) { - EventsOnMultiple(eventName, callback, 1); -} - -export function EventsEmit(eventName) { - let args = [eventName].slice.call(arguments); - return window.runtime.EventsEmit.apply(null, args); -} - -export function WindowReload() { - window.runtime.WindowReload(); -} - -export function WindowReloadApp() { - window.runtime.WindowReloadApp(); -} - -export function WindowSetAlwaysOnTop(b) { - window.runtime.WindowSetAlwaysOnTop(b); -} - -export function WindowSetSystemDefaultTheme() { - window.runtime.WindowSetSystemDefaultTheme(); -} - -export function WindowSetLightTheme() { - window.runtime.WindowSetLightTheme(); -} - -export function WindowSetDarkTheme() { - window.runtime.WindowSetDarkTheme(); -} - -export function WindowCenter() { - window.runtime.WindowCenter(); -} - -export function WindowSetTitle(title) { - window.runtime.WindowSetTitle(title); -} - -export function WindowFullscreen() { - window.runtime.WindowFullscreen(); -} - -export function WindowUnfullscreen() { - window.runtime.WindowUnfullscreen(); -} - -export function WindowGetSize() { - return window.runtime.WindowGetSize(); -} - -export function WindowSetSize(width, height) { - window.runtime.WindowSetSize(width, height); -} - -export function WindowSetMaxSize(width, height) { - window.runtime.WindowSetMaxSize(width, height); -} - -export function WindowSetMinSize(width, height) { - window.runtime.WindowSetMinSize(width, height); -} - -export function WindowSetPosition(x, y) { - window.runtime.WindowSetPosition(x, y); -} - -export function WindowGetPosition() { - return window.runtime.WindowGetPosition(); -} - -export function WindowHide() { - window.runtime.WindowHide(); -} - -export function WindowShow() { - window.runtime.WindowShow(); -} - -export function WindowMaximise() { - window.runtime.WindowMaximise(); -} - -export function WindowToggleMaximise() { - window.runtime.WindowToggleMaximise(); -} - -export function WindowUnmaximise() { - window.runtime.WindowUnmaximise(); -} - -export function WindowMinimise() { - window.runtime.WindowMinimise(); -} - -export function WindowUnminimise() { - window.runtime.WindowUnminimise(); -} - -export function WindowSetBackgroundColour(R, G, B, A) { - window.runtime.WindowSetBackgroundColour(R, G, B, A); -} - -export function ScreenGetAll() { - return window.runtime.ScreenGetAll(); -} - -export function BrowserOpenURL(url) { - window.runtime.BrowserOpenURL(url); -} - -export function Environment() { - return window.runtime.Environment(); -} - -export function Quit() { - window.runtime.Quit(); -} - -export function Hide() { - window.runtime.Hide(); -} - -export function Show() { - window.runtime.Show(); -} diff --git a/v2/pkg/templates/templates/react/go.mod.tmpl b/v2/pkg/templates/templates/react/go.mod.tmpl deleted file mode 100644 index 4b34d1668..000000000 --- a/v2/pkg/templates/templates/react/go.mod.tmpl +++ /dev/null @@ -1,7 +0,0 @@ -module changeme - -go 1.23.0 - -require github.com/wailsapp/wails/v2 {{.WailsVersion}} - -// replace github.com/wailsapp/wails/v2 {{.WailsVersion}} => {{.WailsDirectory}} \ No newline at end of file diff --git a/v2/pkg/templates/templates/react/main.go.tmpl b/v2/pkg/templates/templates/react/main.go.tmpl deleted file mode 100644 index e24782be3..000000000 --- a/v2/pkg/templates/templates/react/main.go.tmpl +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import ( - "embed" - - "github.com/wailsapp/wails/v2" - "github.com/wailsapp/wails/v2/pkg/options" - "github.com/wailsapp/wails/v2/pkg/options/assetserver" -) - -//go:embed all:frontend/dist -var assets embed.FS - -func main() { - // Create an instance of the app structure - app := NewApp() - - // Create application with options - err := wails.Run(&options.App{ - Title: "{{.ProjectName}}", - Width: 1024, - Height: 768, - AssetServer: &assetserver.Options{ - Assets: assets, - }, - BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, - OnStartup: app.startup, - Bind: []interface{}{ - app, - }, - }) - - if err != nil { - println("Error:", err.Error()) - } -} diff --git a/v2/pkg/templates/templates/react/template.json b/v2/pkg/templates/templates/react/template.json deleted file mode 100644 index eb6de08f3..000000000 --- a/v2/pkg/templates/templates/react/template.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "React + Vite", - "shortname": "react", - "author": "Lea Anthony", - "description": "React + Vite development server", - "helpurl": "https://wails.io" -} \ No newline at end of file diff --git a/v2/pkg/templates/templates/react/wails.tmpl.json b/v2/pkg/templates/templates/react/wails.tmpl.json deleted file mode 100644 index c39b2cb7d..000000000 --- a/v2/pkg/templates/templates/react/wails.tmpl.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "$schema": "https://wails.io/schemas/config.v2.json", - "name": "{{.ProjectName}}", - "outputfilename": "{{.BinaryName}}", - "frontend:install": "npm install", - "frontend:build": "npm run build", - "frontend:dev:watcher": "npm run dev", - "frontend:dev:serverUrl": "auto", - "author": { - "name": "{{.AuthorName}}", - "email": "{{.AuthorEmail}}" - } -} diff --git a/v2/pkg/templates/templates/svelte-ts/.gitignore.tmpl b/v2/pkg/templates/templates/svelte-ts/.gitignore.tmpl deleted file mode 100644 index 129d52294..000000000 --- a/v2/pkg/templates/templates/svelte-ts/.gitignore.tmpl +++ /dev/null @@ -1,3 +0,0 @@ -build/bin -node_modules -frontend/dist diff --git a/v2/pkg/templates/templates/svelte-ts/README.md b/v2/pkg/templates/templates/svelte-ts/README.md deleted file mode 100644 index 2e62a374f..000000000 --- a/v2/pkg/templates/templates/svelte-ts/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# README - -## About - -This is the official Wails Svelte-TS template. - -## Live Development - -To run in live development mode, run `wails dev` in the project directory. This will run a Vite development -server that will provide very fast hot reload of your frontend changes. If you want to develop in a browser -and have access to your Go methods, there is also a dev server that runs on http://localhost:34115. Connect -to this in your browser, and you can call your Go code from devtools. - -## Building - -To build a redistributable, production mode package, use `wails build`. diff --git a/v2/pkg/templates/templates/svelte-ts/app.tmpl.go b/v2/pkg/templates/templates/svelte-ts/app.tmpl.go deleted file mode 100644 index af53038a1..000000000 --- a/v2/pkg/templates/templates/svelte-ts/app.tmpl.go +++ /dev/null @@ -1,27 +0,0 @@ -package main - -import ( - "context" - "fmt" -) - -// App struct -type App struct { - ctx context.Context -} - -// NewApp creates a new App application struct -func NewApp() *App { - return &App{} -} - -// startup is called when the app starts. The context is saved -// so we can call the runtime methods -func (a *App) startup(ctx context.Context) { - a.ctx = ctx -} - -// Greet returns a greeting for the given name -func (a *App) Greet(name string) string { - return fmt.Sprintf("Hello %s, It's show time!", name) -} diff --git a/v2/pkg/templates/templates/svelte-ts/frontend/.vscode/extensions.json b/v2/pkg/templates/templates/svelte-ts/frontend/.vscode/extensions.json deleted file mode 100644 index b869ef8e2..000000000 --- a/v2/pkg/templates/templates/svelte-ts/frontend/.vscode/extensions.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "recommendations": [ - "svelte.svelte-vscode" - ] -} diff --git a/v2/pkg/templates/templates/svelte-ts/frontend/README.md b/v2/pkg/templates/templates/svelte-ts/frontend/README.md deleted file mode 100644 index bd0780d0a..000000000 --- a/v2/pkg/templates/templates/svelte-ts/frontend/README.md +++ /dev/null @@ -1,65 +0,0 @@ -# Svelte + TS + Vite - -This template should help get you started developing with Svelte and TypeScript in Vite. - -## Recommended IDE Setup - -[VS Code](https://code.visualstudio.com/) - -+ [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode). - -## Need an official Svelte framework? - -Check out [SvelteKit](https://github.com/sveltejs/kit#readme), which is also powered by Vite. Deploy anywhere with its -serverless-first approach and adapt to various platforms, with out of the box support for TypeScript, SCSS, and Less, -and easily-added support for mdsvex, GraphQL, PostCSS, Tailwind CSS, and more. - -## Technical considerations - -**Why use this over SvelteKit?** - -- It brings its own routing solution which might not be preferable for some users. -- It is first and foremost a framework that just happens to use Vite under the hood, not a Vite app. - `vite dev` and `vite build` wouldn't work in a SvelteKit environment, for example. - -This template contains as little as possible to get started with Vite + TypeScript + Svelte, while taking into account -the developer experience with regards to HMR and intellisense. It demonstrates capabilities on par with the -other `create-vite` templates and is a good starting point for beginners dipping their toes into a Vite + Svelte -project. - -Should you later need the extended capabilities and extensibility provided by SvelteKit, the template has been -structured similarly to SvelteKit so that it is easy to migrate. - -**Why `global.d.ts` instead of `compilerOptions.types` inside `jsconfig.json` or `tsconfig.json`?** - -Setting `compilerOptions.types` shuts out all other types not explicitly listed in the configuration. Using triple-slash -references keeps the default TypeScript setting of accepting type information from the entire workspace, while also -adding `svelte` and `vite/client` type information. - -**Why include `.vscode/extensions.json`?** - -Other templates indirectly recommend extensions via the README, but this file allows VS Code to prompt the user to -install the recommended extension upon opening the project. - -**Why enable `allowJs` in the TS template?** - -While `allowJs: false` would indeed prevent the use of `.js` files in the project, it does not prevent the use of -JavaScript syntax in `.svelte` files. In addition, it would force `checkJs: false`, bringing the worst of both worlds: -not being able to guarantee the entire codebase is TypeScript, and also having worse typechecking for the existing -JavaScript. In addition, there are valid use cases in which a mixed codebase may be relevant. - -**Why is HMR not preserving my local component state?** - -HMR state preservation comes with a number of gotchas! It has been disabled by default in both `svelte-hmr` -and `@sveltejs/vite-plugin-svelte` due to its often surprising behavior. You can read the -details [here](https://github.com/rixo/svelte-hmr#svelte-hmr). - -If you have state that's important to retain within a component, consider creating an external store which would not be -replaced by HMR. - -```ts -// store.ts -// An extremely simple external store -import { writable } from 'svelte/store' -export default writable(0) -``` diff --git a/v2/pkg/templates/templates/svelte-ts/frontend/dist/gitkeep b/v2/pkg/templates/templates/svelte-ts/frontend/dist/gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/v2/pkg/templates/templates/svelte-ts/frontend/index.tmpl.html b/v2/pkg/templates/templates/svelte-ts/frontend/index.tmpl.html deleted file mode 100644 index 3dd212f2d..000000000 --- a/v2/pkg/templates/templates/svelte-ts/frontend/index.tmpl.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - {{.ProjectName}} - - -
- - - diff --git a/v2/pkg/templates/templates/svelte-ts/frontend/package.json b/v2/pkg/templates/templates/svelte-ts/frontend/package.json deleted file mode 100644 index 2ee69eaf5..000000000 --- a/v2/pkg/templates/templates/svelte-ts/frontend/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "frontend", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "vite build", - "preview": "vite preview", - "check": "svelte-check --tsconfig ./tsconfig.json" - }, - "devDependencies": { - "@sveltejs/vite-plugin-svelte": "^1.0.1", - "@tsconfig/svelte": "^3.0.0", - "svelte": "^3.49.0", - "svelte-check": "^2.8.0", - "svelte-preprocess": "^4.10.7", - "tslib": "^2.4.0", - "typescript": "^4.6.4", - "vite": "^3.0.7" - } -} \ No newline at end of file diff --git a/v2/pkg/templates/templates/svelte-ts/frontend/src/App.svelte b/v2/pkg/templates/templates/svelte-ts/frontend/src/App.svelte deleted file mode 100644 index 1987eb090..000000000 --- a/v2/pkg/templates/templates/svelte-ts/frontend/src/App.svelte +++ /dev/null @@ -1,79 +0,0 @@ - - -
- -
{resultText}
-
- - -
-
- - diff --git a/v2/pkg/templates/templates/svelte-ts/frontend/src/assets/fonts/OFL.txt b/v2/pkg/templates/templates/svelte-ts/frontend/src/assets/fonts/OFL.txt deleted file mode 100644 index 9cac04ce8..000000000 --- a/v2/pkg/templates/templates/svelte-ts/frontend/src/assets/fonts/OFL.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com), - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/v2/pkg/templates/templates/svelte-ts/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 b/v2/pkg/templates/templates/svelte-ts/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 deleted file mode 100644 index 2f9cc5964..000000000 Binary files a/v2/pkg/templates/templates/svelte-ts/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 and /dev/null differ diff --git a/v2/pkg/templates/templates/svelte-ts/frontend/src/assets/images/logo-universal.png b/v2/pkg/templates/templates/svelte-ts/frontend/src/assets/images/logo-universal.png deleted file mode 100644 index 5421ad881..000000000 Binary files a/v2/pkg/templates/templates/svelte-ts/frontend/src/assets/images/logo-universal.png and /dev/null differ diff --git a/v2/pkg/templates/templates/svelte-ts/frontend/src/main.ts b/v2/pkg/templates/templates/svelte-ts/frontend/src/main.ts deleted file mode 100644 index 95c41a51d..000000000 --- a/v2/pkg/templates/templates/svelte-ts/frontend/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './style.css' -import App from './App.svelte' - -const app = new App({ - target: document.getElementById('app') -}) - -export default app diff --git a/v2/pkg/templates/templates/svelte-ts/frontend/src/style.css b/v2/pkg/templates/templates/svelte-ts/frontend/src/style.css deleted file mode 100644 index 3940d6c63..000000000 --- a/v2/pkg/templates/templates/svelte-ts/frontend/src/style.css +++ /dev/null @@ -1,26 +0,0 @@ -html { - background-color: rgba(27, 38, 54, 1); - text-align: center; - color: white; -} - -body { - margin: 0; - color: white; - font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", - "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", - sans-serif; -} - -@font-face { - font-family: "Nunito"; - font-style: normal; - font-weight: 400; - src: local(""), - url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2"); -} - -#app { - height: 100vh; - text-align: center; -} diff --git a/v2/pkg/templates/templates/svelte-ts/frontend/src/vite-env.d.ts b/v2/pkg/templates/templates/svelte-ts/frontend/src/vite-env.d.ts deleted file mode 100644 index 4078e7476..000000000 --- a/v2/pkg/templates/templates/svelte-ts/frontend/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/v2/pkg/templates/templates/svelte-ts/frontend/svelte.config.js b/v2/pkg/templates/templates/svelte-ts/frontend/svelte.config.js deleted file mode 100644 index 3630bb396..000000000 --- a/v2/pkg/templates/templates/svelte-ts/frontend/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import sveltePreprocess from 'svelte-preprocess' - -export default { - // Consult https://github.com/sveltejs/svelte-preprocess - // for more information about preprocessors - preprocess: sveltePreprocess() -} diff --git a/v2/pkg/templates/templates/svelte-ts/frontend/tsconfig.json b/v2/pkg/templates/templates/svelte-ts/frontend/tsconfig.json deleted file mode 100644 index 2cffdc568..000000000 --- a/v2/pkg/templates/templates/svelte-ts/frontend/tsconfig.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - "baseUrl": ".", - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "isolatedModules": true - }, - "include": [ - "src/**/*.d.ts", - "src/**/*.ts", - "src/**/*.js", - "src/**/*.svelte" - ], - "references": [ - { - "path": "./tsconfig.node.json" - } - ] -} diff --git a/v2/pkg/templates/templates/svelte-ts/frontend/tsconfig.node.json b/v2/pkg/templates/templates/svelte-ts/frontend/tsconfig.node.json deleted file mode 100644 index 05764b1c4..000000000 --- a/v2/pkg/templates/templates/svelte-ts/frontend/tsconfig.node.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "module": "ESNext", - "moduleResolution": "Node" - }, - "include": [ - "vite.config.ts" - ] -} diff --git a/v2/pkg/templates/templates/svelte-ts/frontend/vite.config.ts b/v2/pkg/templates/templates/svelte-ts/frontend/vite.config.ts deleted file mode 100644 index d37616f9a..000000000 --- a/v2/pkg/templates/templates/svelte-ts/frontend/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import {defineConfig} from 'vite' -import {svelte} from '@sveltejs/vite-plugin-svelte' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte()] -}) diff --git a/v2/pkg/templates/templates/svelte-ts/frontend/wailsjs/go/main/App.d.ts b/v2/pkg/templates/templates/svelte-ts/frontend/wailsjs/go/main/App.d.ts deleted file mode 100644 index 43173cfce..000000000 --- a/v2/pkg/templates/templates/svelte-ts/frontend/wailsjs/go/main/App.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Greet(arg1: string): Promise; diff --git a/v2/pkg/templates/templates/svelte-ts/frontend/wailsjs/go/main/App.js b/v2/pkg/templates/templates/svelte-ts/frontend/wailsjs/go/main/App.js deleted file mode 100644 index 0ee085c95..000000000 --- a/v2/pkg/templates/templates/svelte-ts/frontend/wailsjs/go/main/App.js +++ /dev/null @@ -1,7 +0,0 @@ -// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Greet(arg1) { - return window['go']['main']['App']['Greet'](arg1); -} diff --git a/v2/pkg/templates/templates/svelte-ts/frontend/wailsjs/runtime/package.json b/v2/pkg/templates/templates/svelte-ts/frontend/wailsjs/runtime/package.json deleted file mode 100644 index 1e7c8a5d7..000000000 --- a/v2/pkg/templates/templates/svelte-ts/frontend/wailsjs/runtime/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "@wailsapp/runtime", - "version": "2.0.0", - "description": "Wails Javascript runtime library", - "main": "runtime.js", - "types": "runtime.d.ts", - "scripts": { - }, - "repository": { - "type": "git", - "url": "git+https://github.com/wailsapp/wails.git" - }, - "keywords": [ - "Wails", - "Javascript", - "Go" - ], - "author": "Lea Anthony ", - "license": "MIT", - "bugs": { - "url": "https://github.com/wailsapp/wails/issues" - }, - "homepage": "https://github.com/wailsapp/wails#readme" -} diff --git a/v2/pkg/templates/templates/svelte-ts/frontend/wailsjs/runtime/runtime.d.ts b/v2/pkg/templates/templates/svelte-ts/frontend/wailsjs/runtime/runtime.d.ts deleted file mode 100644 index 336fb07aa..000000000 --- a/v2/pkg/templates/templates/svelte-ts/frontend/wailsjs/runtime/runtime.d.ts +++ /dev/null @@ -1,211 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export interface Position { - x: number; - y: number; -} - -export interface Size { - w: number; - h: number; -} - -export interface Screen { - isCurrent: boolean; - isPrimary: boolean; - width: number - height: number -} - -// Environment information such as platform, buildtype, ... -export interface EnvironmentInfo { - buildType: string; - platform: string; - arch: string; -} - -// [EventsEmit](https://wails.io/docs/reference/runtime/events#eventsemit) -// emits the given event. Optional data may be passed with the event. -// This will trigger any event listeners. -export function EventsEmit(eventName: string, ...data: any): void; - -// [EventsOn](https://wails.io/docs/reference/runtime/events#eventson) sets up a listener for the given event name. -export function EventsOn(eventName: string, callback: (...data: any) => void): void; - -// [EventsOnMultiple](https://wails.io/docs/reference/runtime/events#eventsonmultiple) -// sets up a listener for the given event name, but will only trigger a given number times. -export function EventsOnMultiple(eventName: string, callback: (...data: any) => void, maxCallbacks: number): void; - -// [EventsOnce](https://wails.io/docs/reference/runtime/events#eventsonce) -// sets up a listener for the given event name, but will only trigger once. -export function EventsOnce(eventName: string, callback: (...data: any) => void): void; - -// [EventsOff](https://wails.io/docs/reference/runtime/events#eventsff) -// unregisters the listener for the given event name. -export function EventsOff(eventName: string): void; - -// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) -// unregisters all event listeners. -export function EventsOffAll(): void; - -// [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) -// logs the given message as a raw message -export function LogPrint(message: string): void; - -// [LogTrace](https://wails.io/docs/reference/runtime/log#logtrace) -// logs the given message at the `trace` log level. -export function LogTrace(message: string): void; - -// [LogDebug](https://wails.io/docs/reference/runtime/log#logdebug) -// logs the given message at the `debug` log level. -export function LogDebug(message: string): void; - -// [LogError](https://wails.io/docs/reference/runtime/log#logerror) -// logs the given message at the `error` log level. -export function LogError(message: string): void; - -// [LogFatal](https://wails.io/docs/reference/runtime/log#logfatal) -// logs the given message at the `fatal` log level. -// The application will quit after calling this method. -export function LogFatal(message: string): void; - -// [LogInfo](https://wails.io/docs/reference/runtime/log#loginfo) -// logs the given message at the `info` log level. -export function LogInfo(message: string): void; - -// [LogWarning](https://wails.io/docs/reference/runtime/log#logwarning) -// logs the given message at the `warning` log level. -export function LogWarning(message: string): void; - -// [WindowReload](https://wails.io/docs/reference/runtime/window#windowreload) -// Forces a reload by the main application as well as connected browsers. -export function WindowReload(): void; - -// [WindowReloadApp](https://wails.io/docs/reference/runtime/window#windowreloadapp) -// Reloads the application frontend. -export function WindowReloadApp(): void; - -// [WindowSetAlwaysOnTop](https://wails.io/docs/reference/runtime/window#windowsetalwaysontop) -// Sets the window AlwaysOnTop or not on top. -export function WindowSetAlwaysOnTop(b: boolean): void; - -// [WindowSetSystemDefaultTheme](https://wails.io/docs/next/reference/runtime/window#windowsetsystemdefaulttheme) -// *Windows only* -// Sets window theme to system default (dark/light). -export function WindowSetSystemDefaultTheme(): void; - -// [WindowSetLightTheme](https://wails.io/docs/next/reference/runtime/window#windowsetlighttheme) -// *Windows only* -// Sets window to light theme. -export function WindowSetLightTheme(): void; - -// [WindowSetDarkTheme](https://wails.io/docs/next/reference/runtime/window#windowsetdarktheme) -// *Windows only* -// Sets window to dark theme. -export function WindowSetDarkTheme(): void; - -// [WindowCenter](https://wails.io/docs/reference/runtime/window#windowcenter) -// Centers the window on the monitor the window is currently on. -export function WindowCenter(): void; - -// [WindowSetTitle](https://wails.io/docs/reference/runtime/window#windowsettitle) -// Sets the text in the window title bar. -export function WindowSetTitle(title: string): void; - -// [WindowFullscreen](https://wails.io/docs/reference/runtime/window#windowfullscreen) -// Makes the window full screen. -export function WindowFullscreen(): void; - -// [WindowUnfullscreen](https://wails.io/docs/reference/runtime/window#windowunfullscreen) -// Restores the previous window dimensions and position prior to full screen. -export function WindowUnfullscreen(): void; - -// [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize) -// Sets the width and height of the window. -export function WindowSetSize(width: number, height: number): void; - -// [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize) -// Gets the width and height of the window. -export function WindowGetSize(): Promise; - -// [WindowSetMaxSize](https://wails.io/docs/reference/runtime/window#windowsetmaxsize) -// Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMaxSize(width: number, height: number): void; - -// [WindowSetMinSize](https://wails.io/docs/reference/runtime/window#windowsetminsize) -// Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMinSize(width: number, height: number): void; - -// [WindowSetPosition](https://wails.io/docs/reference/runtime/window#windowsetposition) -// Sets the window position relative to the monitor the window is currently on. -export function WindowSetPosition(x: number, y: number): void; - -// [WindowGetPosition](https://wails.io/docs/reference/runtime/window#windowgetposition) -// Gets the window position relative to the monitor the window is currently on. -export function WindowGetPosition(): Promise; - -// [WindowHide](https://wails.io/docs/reference/runtime/window#windowhide) -// Hides the window. -export function WindowHide(): void; - -// [WindowShow](https://wails.io/docs/reference/runtime/window#windowshow) -// Shows the window, if it is currently hidden. -export function WindowShow(): void; - -// [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise) -// Maximises the window to fill the screen. -export function WindowMaximise(): void; - -// [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise) -// Toggles between Maximised and UnMaximised. -export function WindowToggleMaximise(): void; - -// [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise) -// Restores the window to the dimensions and position prior to maximising. -export function WindowUnmaximise(): void; - -// [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise) -// Minimises the window. -export function WindowMinimise(): void; - -// [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise) -// Restores the window to the dimensions and position prior to minimising. -export function WindowUnminimise(): void; - -// [WindowSetBackgroundColour](https://wails.io/docs/reference/runtime/window#windowsetbackgroundcolour) -// Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels. -export function WindowSetBackgroundColour(R: number, G: number, B: number, A: number): void; - -// [ScreenGetAll](https://wails.io/docs/reference/runtime/window#screengetall) -// Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system. -export function ScreenGetAll(): Promise; - -// [BrowserOpenURL](https://wails.io/docs/reference/runtime/browser#browseropenurl) -// Opens the given URL in the system browser. -export function BrowserOpenURL(url: string): void; - -// [Environment](https://wails.io/docs/reference/runtime/intro#environment) -// Returns information about the environment -export function Environment(): Promise; - -// [Quit](https://wails.io/docs/reference/runtime/intro#quit) -// Quits the application. -export function Quit(): void; - -// [Hide](https://wails.io/docs/reference/runtime/intro#hide) -// Hides the application. -export function Hide(): void; - -// [Show](https://wails.io/docs/reference/runtime/intro#show) -// Shows the application. -export function Show(): void; diff --git a/v2/pkg/templates/templates/svelte-ts/frontend/wailsjs/runtime/runtime.js b/v2/pkg/templates/templates/svelte-ts/frontend/wailsjs/runtime/runtime.js deleted file mode 100644 index b5ae16d56..000000000 --- a/v2/pkg/templates/templates/svelte-ts/frontend/wailsjs/runtime/runtime.js +++ /dev/null @@ -1,182 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export function LogPrint(message) { - window.runtime.LogPrint(message); -} - -export function LogTrace(message) { - window.runtime.LogTrace(message); -} - -export function LogDebug(message) { - window.runtime.LogDebug(message); -} - -export function LogInfo(message) { - window.runtime.LogInfo(message); -} - -export function LogWarning(message) { - window.runtime.LogWarning(message); -} - -export function LogError(message) { - window.runtime.LogError(message); -} - -export function LogFatal(message) { - window.runtime.LogFatal(message); -} - -export function EventsOnMultiple(eventName, callback, maxCallbacks) { - window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks); -} - -export function EventsOn(eventName, callback) { - EventsOnMultiple(eventName, callback, -1); -} - -export function EventsOff(eventName) { - return window.runtime.EventsOff(eventName); -} - -export function EventsOffAll() { - return window.runtime.EventsOffAll(); -} - -export function EventsOnce(eventName, callback) { - EventsOnMultiple(eventName, callback, 1); -} - -export function EventsEmit(eventName) { - let args = [eventName].slice.call(arguments); - return window.runtime.EventsEmit.apply(null, args); -} - -export function WindowReload() { - window.runtime.WindowReload(); -} - -export function WindowReloadApp() { - window.runtime.WindowReloadApp(); -} - -export function WindowSetAlwaysOnTop(b) { - window.runtime.WindowSetAlwaysOnTop(b); -} - -export function WindowSetSystemDefaultTheme() { - window.runtime.WindowSetSystemDefaultTheme(); -} - -export function WindowSetLightTheme() { - window.runtime.WindowSetLightTheme(); -} - -export function WindowSetDarkTheme() { - window.runtime.WindowSetDarkTheme(); -} - -export function WindowCenter() { - window.runtime.WindowCenter(); -} - -export function WindowSetTitle(title) { - window.runtime.WindowSetTitle(title); -} - -export function WindowFullscreen() { - window.runtime.WindowFullscreen(); -} - -export function WindowUnfullscreen() { - window.runtime.WindowUnfullscreen(); -} - -export function WindowGetSize() { - return window.runtime.WindowGetSize(); -} - -export function WindowSetSize(width, height) { - window.runtime.WindowSetSize(width, height); -} - -export function WindowSetMaxSize(width, height) { - window.runtime.WindowSetMaxSize(width, height); -} - -export function WindowSetMinSize(width, height) { - window.runtime.WindowSetMinSize(width, height); -} - -export function WindowSetPosition(x, y) { - window.runtime.WindowSetPosition(x, y); -} - -export function WindowGetPosition() { - return window.runtime.WindowGetPosition(); -} - -export function WindowHide() { - window.runtime.WindowHide(); -} - -export function WindowShow() { - window.runtime.WindowShow(); -} - -export function WindowMaximise() { - window.runtime.WindowMaximise(); -} - -export function WindowToggleMaximise() { - window.runtime.WindowToggleMaximise(); -} - -export function WindowUnmaximise() { - window.runtime.WindowUnmaximise(); -} - -export function WindowMinimise() { - window.runtime.WindowMinimise(); -} - -export function WindowUnminimise() { - window.runtime.WindowUnminimise(); -} - -export function WindowSetBackgroundColour(R, G, B, A) { - window.runtime.WindowSetBackgroundColour(R, G, B, A); -} - -export function ScreenGetAll() { - return window.runtime.ScreenGetAll(); -} - -export function BrowserOpenURL(url) { - window.runtime.BrowserOpenURL(url); -} - -export function Environment() { - return window.runtime.Environment(); -} - -export function Quit() { - window.runtime.Quit(); -} - -export function Hide() { - window.runtime.Hide(); -} - -export function Show() { - window.runtime.Show(); -} diff --git a/v2/pkg/templates/templates/svelte-ts/go.mod.tmpl b/v2/pkg/templates/templates/svelte-ts/go.mod.tmpl deleted file mode 100644 index 4b34d1668..000000000 --- a/v2/pkg/templates/templates/svelte-ts/go.mod.tmpl +++ /dev/null @@ -1,7 +0,0 @@ -module changeme - -go 1.23.0 - -require github.com/wailsapp/wails/v2 {{.WailsVersion}} - -// replace github.com/wailsapp/wails/v2 {{.WailsVersion}} => {{.WailsDirectory}} \ No newline at end of file diff --git a/v2/pkg/templates/templates/svelte-ts/main.go.tmpl b/v2/pkg/templates/templates/svelte-ts/main.go.tmpl deleted file mode 100644 index e24782be3..000000000 --- a/v2/pkg/templates/templates/svelte-ts/main.go.tmpl +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import ( - "embed" - - "github.com/wailsapp/wails/v2" - "github.com/wailsapp/wails/v2/pkg/options" - "github.com/wailsapp/wails/v2/pkg/options/assetserver" -) - -//go:embed all:frontend/dist -var assets embed.FS - -func main() { - // Create an instance of the app structure - app := NewApp() - - // Create application with options - err := wails.Run(&options.App{ - Title: "{{.ProjectName}}", - Width: 1024, - Height: 768, - AssetServer: &assetserver.Options{ - Assets: assets, - }, - BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, - OnStartup: app.startup, - Bind: []interface{}{ - app, - }, - }) - - if err != nil { - println("Error:", err.Error()) - } -} diff --git a/v2/pkg/templates/templates/svelte-ts/template.json b/v2/pkg/templates/templates/svelte-ts/template.json deleted file mode 100644 index eec762bc6..000000000 --- a/v2/pkg/templates/templates/svelte-ts/template.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "Svelte + Vite (Typescript)", - "shortname": "svelte-ts", - "author": "Lea Anthony", - "description": "Svelte + TS + Vite development server", - "helpurl": "https://wails.io" -} \ No newline at end of file diff --git a/v2/pkg/templates/templates/svelte-ts/wails.tmpl.json b/v2/pkg/templates/templates/svelte-ts/wails.tmpl.json deleted file mode 100644 index c39b2cb7d..000000000 --- a/v2/pkg/templates/templates/svelte-ts/wails.tmpl.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "$schema": "https://wails.io/schemas/config.v2.json", - "name": "{{.ProjectName}}", - "outputfilename": "{{.BinaryName}}", - "frontend:install": "npm install", - "frontend:build": "npm run build", - "frontend:dev:watcher": "npm run dev", - "frontend:dev:serverUrl": "auto", - "author": { - "name": "{{.AuthorName}}", - "email": "{{.AuthorEmail}}" - } -} diff --git a/v2/pkg/templates/templates/svelte/.gitignore.tmpl b/v2/pkg/templates/templates/svelte/.gitignore.tmpl deleted file mode 100644 index 129d52294..000000000 --- a/v2/pkg/templates/templates/svelte/.gitignore.tmpl +++ /dev/null @@ -1,3 +0,0 @@ -build/bin -node_modules -frontend/dist diff --git a/v2/pkg/templates/templates/svelte/README.md b/v2/pkg/templates/templates/svelte/README.md deleted file mode 100644 index eefcd5c4e..000000000 --- a/v2/pkg/templates/templates/svelte/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# README - -## About - -This is the official Wails Svelte template. - -## Live Development - -To run in live development mode, run `wails dev` in the project directory. This will run a Vite development -server that will provide very fast hot reload of your frontend changes. If you want to develop in a browser -and have access to your Go methods, there is also a dev server that runs on http://localhost:34115. Connect -to this in your browser, and you can call your Go code from devtools. - -## Building - -To build a redistributable, production mode package, use `wails build`. diff --git a/v2/pkg/templates/templates/svelte/app.tmpl.go b/v2/pkg/templates/templates/svelte/app.tmpl.go deleted file mode 100644 index af53038a1..000000000 --- a/v2/pkg/templates/templates/svelte/app.tmpl.go +++ /dev/null @@ -1,27 +0,0 @@ -package main - -import ( - "context" - "fmt" -) - -// App struct -type App struct { - ctx context.Context -} - -// NewApp creates a new App application struct -func NewApp() *App { - return &App{} -} - -// startup is called when the app starts. The context is saved -// so we can call the runtime methods -func (a *App) startup(ctx context.Context) { - a.ctx = ctx -} - -// Greet returns a greeting for the given name -func (a *App) Greet(name string) string { - return fmt.Sprintf("Hello %s, It's show time!", name) -} diff --git a/v2/pkg/templates/templates/svelte/frontend/.vscode/extensions.json b/v2/pkg/templates/templates/svelte/frontend/.vscode/extensions.json deleted file mode 100644 index b869ef8e2..000000000 --- a/v2/pkg/templates/templates/svelte/frontend/.vscode/extensions.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "recommendations": [ - "svelte.svelte-vscode" - ] -} diff --git a/v2/pkg/templates/templates/svelte/frontend/README.md b/v2/pkg/templates/templates/svelte/frontend/README.md deleted file mode 100644 index a346289c5..000000000 --- a/v2/pkg/templates/templates/svelte/frontend/README.md +++ /dev/null @@ -1,63 +0,0 @@ -# Svelte + Vite - -This template should help get you started developing with Svelte in Vite. - -## Recommended IDE Setup - -[VS Code](https://code.visualstudio.com/) - -+ [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode). - -## Need an official Svelte framework? - -Check out [SvelteKit](https://github.com/sveltejs/kit#readme), which is also powered by Vite. Deploy anywhere with its -serverless-first approach and adapt to various platforms, with out of the box support for TypeScript, SCSS, and Less, -and easily-added support for mdsvex, GraphQL, PostCSS, Tailwind CSS, and more. - -## Technical considerations - -**Why use this over SvelteKit?** - -- It brings its own routing solution which might not be preferable for some users. -- It is first and foremost a framework that just happens to use Vite under the hood, not a Vite app. - `vite dev` and `vite build` wouldn't work in a SvelteKit environment, for example. - -This template contains as little as possible to get started with Vite + Svelte, while taking into account the developer -experience with regards to HMR and intellisense. It demonstrates capabilities on par with the other `create-vite` -templates and is a good starting point for beginners dipping their toes into a Vite + Svelte project. - -Should you later need the extended capabilities and extensibility provided by SvelteKit, the template has been -structured similarly to SvelteKit so that it is easy to migrate. - -**Why `global.d.ts` instead of `compilerOptions.types` inside `jsconfig.json` or `tsconfig.json`?** - -Setting `compilerOptions.types` shuts out all other types not explicitly listed in the configuration. Using triple-slash -references keeps the default TypeScript setting of accepting type information from the entire workspace, while also -adding `svelte` and `vite/client` type information. - -**Why include `.vscode/extensions.json`?** - -Other templates indirectly recommend extensions via the README, but this file allows VS Code to prompt the user to -install the recommended extension upon opening the project. - -**Why enable `checkJs` in the JS template?** - -It is likely that most cases of changing variable types in runtime are likely to be accidental, rather than deliberate. -This provides advanced typechecking out of the box. Should you like to take advantage of the dynamically-typed nature of -JavaScript, it is trivial to change the configuration. - -**Why is HMR not preserving my local component state?** - -HMR state preservation comes with a number of gotchas! It has been disabled by default in both `svelte-hmr` -and `@sveltejs/vite-plugin-svelte` due to its often surprising behavior. You can read the -details [here](https://github.com/rixo/svelte-hmr#svelte-hmr). - -If you have state that's important to retain within a component, consider creating an external store which would not be -replaced by HMR. - -```js -// store.js -// An extremely simple external store -import { writable } from 'svelte/store' -export default writable(0) -``` diff --git a/v2/pkg/templates/templates/svelte/frontend/dist/gitkeep b/v2/pkg/templates/templates/svelte/frontend/dist/gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/v2/pkg/templates/templates/svelte/frontend/index.tmpl.html b/v2/pkg/templates/templates/svelte/frontend/index.tmpl.html deleted file mode 100644 index 859919153..000000000 --- a/v2/pkg/templates/templates/svelte/frontend/index.tmpl.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - {{.ProjectName}} - - -
- - - diff --git a/v2/pkg/templates/templates/svelte/frontend/jsconfig.json b/v2/pkg/templates/templates/svelte/frontend/jsconfig.json deleted file mode 100644 index 3918b4fda..000000000 --- a/v2/pkg/templates/templates/svelte/frontend/jsconfig.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "compilerOptions": { - "moduleResolution": "Node", - "target": "ESNext", - "module": "ESNext", - /** - * svelte-preprocess cannot figure out whether you have - * a value or a type, so tell TypeScript to enforce using - * `import type` instead of `import` for Types. - */ - "importsNotUsedAsValues": "error", - "isolatedModules": true, - "resolveJsonModule": true, - /** - * To have warnings / errors of the Svelte compiler at the - * correct position, enable source maps by default. - */ - "sourceMap": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "baseUrl": ".", - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable this if you'd like to use dynamic types. - */ - "checkJs": true - }, - /** - * Use global.d.ts instead of compilerOptions.types - * to avoid limiting type declarations. - */ - "include": [ - "src/**/*.d.ts", - "src/**/*.js", - "src/**/*.svelte" - ] -} diff --git a/v2/pkg/templates/templates/svelte/frontend/package.json b/v2/pkg/templates/templates/svelte/frontend/package.json deleted file mode 100644 index 8c9ae62a8..000000000 --- a/v2/pkg/templates/templates/svelte/frontend/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "frontend", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "vite build", - "preview": "vite preview" - }, - "devDependencies": { - "@sveltejs/vite-plugin-svelte": "^1.0.1", - "svelte": "^3.49.0", - "vite": "^3.0.7" - } -} \ No newline at end of file diff --git a/v2/pkg/templates/templates/svelte/frontend/src/App.svelte b/v2/pkg/templates/templates/svelte/frontend/src/App.svelte deleted file mode 100644 index 2a2ce2282..000000000 --- a/v2/pkg/templates/templates/svelte/frontend/src/App.svelte +++ /dev/null @@ -1,79 +0,0 @@ - - -
- -
{resultText}
-
- - -
-
- - diff --git a/v2/pkg/templates/templates/svelte/frontend/src/assets/fonts/OFL.txt b/v2/pkg/templates/templates/svelte/frontend/src/assets/fonts/OFL.txt deleted file mode 100644 index 9cac04ce8..000000000 --- a/v2/pkg/templates/templates/svelte/frontend/src/assets/fonts/OFL.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com), - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/v2/pkg/templates/templates/svelte/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 b/v2/pkg/templates/templates/svelte/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 deleted file mode 100644 index 2f9cc5964..000000000 Binary files a/v2/pkg/templates/templates/svelte/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 and /dev/null differ diff --git a/v2/pkg/templates/templates/svelte/frontend/src/assets/images/logo-universal.png b/v2/pkg/templates/templates/svelte/frontend/src/assets/images/logo-universal.png deleted file mode 100644 index d63303bfa..000000000 Binary files a/v2/pkg/templates/templates/svelte/frontend/src/assets/images/logo-universal.png and /dev/null differ diff --git a/v2/pkg/templates/templates/svelte/frontend/src/main.js b/v2/pkg/templates/templates/svelte/frontend/src/main.js deleted file mode 100644 index 95c41a51d..000000000 --- a/v2/pkg/templates/templates/svelte/frontend/src/main.js +++ /dev/null @@ -1,8 +0,0 @@ -import './style.css' -import App from './App.svelte' - -const app = new App({ - target: document.getElementById('app') -}) - -export default app diff --git a/v2/pkg/templates/templates/svelte/frontend/src/style.css b/v2/pkg/templates/templates/svelte/frontend/src/style.css deleted file mode 100644 index 3940d6c63..000000000 --- a/v2/pkg/templates/templates/svelte/frontend/src/style.css +++ /dev/null @@ -1,26 +0,0 @@ -html { - background-color: rgba(27, 38, 54, 1); - text-align: center; - color: white; -} - -body { - margin: 0; - color: white; - font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", - "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", - sans-serif; -} - -@font-face { - font-family: "Nunito"; - font-style: normal; - font-weight: 400; - src: local(""), - url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2"); -} - -#app { - height: 100vh; - text-align: center; -} diff --git a/v2/pkg/templates/templates/svelte/frontend/src/vite-env.d.ts b/v2/pkg/templates/templates/svelte/frontend/src/vite-env.d.ts deleted file mode 100644 index 4078e7476..000000000 --- a/v2/pkg/templates/templates/svelte/frontend/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/v2/pkg/templates/templates/svelte/frontend/vite.config.js b/v2/pkg/templates/templates/svelte/frontend/vite.config.js deleted file mode 100644 index d37616f9a..000000000 --- a/v2/pkg/templates/templates/svelte/frontend/vite.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import {defineConfig} from 'vite' -import {svelte} from '@sveltejs/vite-plugin-svelte' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte()] -}) diff --git a/v2/pkg/templates/templates/svelte/frontend/wailsjs/go/main/App.d.ts b/v2/pkg/templates/templates/svelte/frontend/wailsjs/go/main/App.d.ts deleted file mode 100644 index 43173cfce..000000000 --- a/v2/pkg/templates/templates/svelte/frontend/wailsjs/go/main/App.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Greet(arg1: string): Promise; diff --git a/v2/pkg/templates/templates/svelte/frontend/wailsjs/go/main/App.js b/v2/pkg/templates/templates/svelte/frontend/wailsjs/go/main/App.js deleted file mode 100644 index 0ee085c95..000000000 --- a/v2/pkg/templates/templates/svelte/frontend/wailsjs/go/main/App.js +++ /dev/null @@ -1,7 +0,0 @@ -// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Greet(arg1) { - return window['go']['main']['App']['Greet'](arg1); -} diff --git a/v2/pkg/templates/templates/svelte/frontend/wailsjs/runtime/package.json b/v2/pkg/templates/templates/svelte/frontend/wailsjs/runtime/package.json deleted file mode 100644 index 1e7c8a5d7..000000000 --- a/v2/pkg/templates/templates/svelte/frontend/wailsjs/runtime/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "@wailsapp/runtime", - "version": "2.0.0", - "description": "Wails Javascript runtime library", - "main": "runtime.js", - "types": "runtime.d.ts", - "scripts": { - }, - "repository": { - "type": "git", - "url": "git+https://github.com/wailsapp/wails.git" - }, - "keywords": [ - "Wails", - "Javascript", - "Go" - ], - "author": "Lea Anthony ", - "license": "MIT", - "bugs": { - "url": "https://github.com/wailsapp/wails/issues" - }, - "homepage": "https://github.com/wailsapp/wails#readme" -} diff --git a/v2/pkg/templates/templates/svelte/frontend/wailsjs/runtime/runtime.d.ts b/v2/pkg/templates/templates/svelte/frontend/wailsjs/runtime/runtime.d.ts deleted file mode 100644 index 336fb07aa..000000000 --- a/v2/pkg/templates/templates/svelte/frontend/wailsjs/runtime/runtime.d.ts +++ /dev/null @@ -1,211 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export interface Position { - x: number; - y: number; -} - -export interface Size { - w: number; - h: number; -} - -export interface Screen { - isCurrent: boolean; - isPrimary: boolean; - width: number - height: number -} - -// Environment information such as platform, buildtype, ... -export interface EnvironmentInfo { - buildType: string; - platform: string; - arch: string; -} - -// [EventsEmit](https://wails.io/docs/reference/runtime/events#eventsemit) -// emits the given event. Optional data may be passed with the event. -// This will trigger any event listeners. -export function EventsEmit(eventName: string, ...data: any): void; - -// [EventsOn](https://wails.io/docs/reference/runtime/events#eventson) sets up a listener for the given event name. -export function EventsOn(eventName: string, callback: (...data: any) => void): void; - -// [EventsOnMultiple](https://wails.io/docs/reference/runtime/events#eventsonmultiple) -// sets up a listener for the given event name, but will only trigger a given number times. -export function EventsOnMultiple(eventName: string, callback: (...data: any) => void, maxCallbacks: number): void; - -// [EventsOnce](https://wails.io/docs/reference/runtime/events#eventsonce) -// sets up a listener for the given event name, but will only trigger once. -export function EventsOnce(eventName: string, callback: (...data: any) => void): void; - -// [EventsOff](https://wails.io/docs/reference/runtime/events#eventsff) -// unregisters the listener for the given event name. -export function EventsOff(eventName: string): void; - -// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) -// unregisters all event listeners. -export function EventsOffAll(): void; - -// [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) -// logs the given message as a raw message -export function LogPrint(message: string): void; - -// [LogTrace](https://wails.io/docs/reference/runtime/log#logtrace) -// logs the given message at the `trace` log level. -export function LogTrace(message: string): void; - -// [LogDebug](https://wails.io/docs/reference/runtime/log#logdebug) -// logs the given message at the `debug` log level. -export function LogDebug(message: string): void; - -// [LogError](https://wails.io/docs/reference/runtime/log#logerror) -// logs the given message at the `error` log level. -export function LogError(message: string): void; - -// [LogFatal](https://wails.io/docs/reference/runtime/log#logfatal) -// logs the given message at the `fatal` log level. -// The application will quit after calling this method. -export function LogFatal(message: string): void; - -// [LogInfo](https://wails.io/docs/reference/runtime/log#loginfo) -// logs the given message at the `info` log level. -export function LogInfo(message: string): void; - -// [LogWarning](https://wails.io/docs/reference/runtime/log#logwarning) -// logs the given message at the `warning` log level. -export function LogWarning(message: string): void; - -// [WindowReload](https://wails.io/docs/reference/runtime/window#windowreload) -// Forces a reload by the main application as well as connected browsers. -export function WindowReload(): void; - -// [WindowReloadApp](https://wails.io/docs/reference/runtime/window#windowreloadapp) -// Reloads the application frontend. -export function WindowReloadApp(): void; - -// [WindowSetAlwaysOnTop](https://wails.io/docs/reference/runtime/window#windowsetalwaysontop) -// Sets the window AlwaysOnTop or not on top. -export function WindowSetAlwaysOnTop(b: boolean): void; - -// [WindowSetSystemDefaultTheme](https://wails.io/docs/next/reference/runtime/window#windowsetsystemdefaulttheme) -// *Windows only* -// Sets window theme to system default (dark/light). -export function WindowSetSystemDefaultTheme(): void; - -// [WindowSetLightTheme](https://wails.io/docs/next/reference/runtime/window#windowsetlighttheme) -// *Windows only* -// Sets window to light theme. -export function WindowSetLightTheme(): void; - -// [WindowSetDarkTheme](https://wails.io/docs/next/reference/runtime/window#windowsetdarktheme) -// *Windows only* -// Sets window to dark theme. -export function WindowSetDarkTheme(): void; - -// [WindowCenter](https://wails.io/docs/reference/runtime/window#windowcenter) -// Centers the window on the monitor the window is currently on. -export function WindowCenter(): void; - -// [WindowSetTitle](https://wails.io/docs/reference/runtime/window#windowsettitle) -// Sets the text in the window title bar. -export function WindowSetTitle(title: string): void; - -// [WindowFullscreen](https://wails.io/docs/reference/runtime/window#windowfullscreen) -// Makes the window full screen. -export function WindowFullscreen(): void; - -// [WindowUnfullscreen](https://wails.io/docs/reference/runtime/window#windowunfullscreen) -// Restores the previous window dimensions and position prior to full screen. -export function WindowUnfullscreen(): void; - -// [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize) -// Sets the width and height of the window. -export function WindowSetSize(width: number, height: number): void; - -// [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize) -// Gets the width and height of the window. -export function WindowGetSize(): Promise; - -// [WindowSetMaxSize](https://wails.io/docs/reference/runtime/window#windowsetmaxsize) -// Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMaxSize(width: number, height: number): void; - -// [WindowSetMinSize](https://wails.io/docs/reference/runtime/window#windowsetminsize) -// Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMinSize(width: number, height: number): void; - -// [WindowSetPosition](https://wails.io/docs/reference/runtime/window#windowsetposition) -// Sets the window position relative to the monitor the window is currently on. -export function WindowSetPosition(x: number, y: number): void; - -// [WindowGetPosition](https://wails.io/docs/reference/runtime/window#windowgetposition) -// Gets the window position relative to the monitor the window is currently on. -export function WindowGetPosition(): Promise; - -// [WindowHide](https://wails.io/docs/reference/runtime/window#windowhide) -// Hides the window. -export function WindowHide(): void; - -// [WindowShow](https://wails.io/docs/reference/runtime/window#windowshow) -// Shows the window, if it is currently hidden. -export function WindowShow(): void; - -// [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise) -// Maximises the window to fill the screen. -export function WindowMaximise(): void; - -// [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise) -// Toggles between Maximised and UnMaximised. -export function WindowToggleMaximise(): void; - -// [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise) -// Restores the window to the dimensions and position prior to maximising. -export function WindowUnmaximise(): void; - -// [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise) -// Minimises the window. -export function WindowMinimise(): void; - -// [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise) -// Restores the window to the dimensions and position prior to minimising. -export function WindowUnminimise(): void; - -// [WindowSetBackgroundColour](https://wails.io/docs/reference/runtime/window#windowsetbackgroundcolour) -// Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels. -export function WindowSetBackgroundColour(R: number, G: number, B: number, A: number): void; - -// [ScreenGetAll](https://wails.io/docs/reference/runtime/window#screengetall) -// Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system. -export function ScreenGetAll(): Promise; - -// [BrowserOpenURL](https://wails.io/docs/reference/runtime/browser#browseropenurl) -// Opens the given URL in the system browser. -export function BrowserOpenURL(url: string): void; - -// [Environment](https://wails.io/docs/reference/runtime/intro#environment) -// Returns information about the environment -export function Environment(): Promise; - -// [Quit](https://wails.io/docs/reference/runtime/intro#quit) -// Quits the application. -export function Quit(): void; - -// [Hide](https://wails.io/docs/reference/runtime/intro#hide) -// Hides the application. -export function Hide(): void; - -// [Show](https://wails.io/docs/reference/runtime/intro#show) -// Shows the application. -export function Show(): void; diff --git a/v2/pkg/templates/templates/svelte/frontend/wailsjs/runtime/runtime.js b/v2/pkg/templates/templates/svelte/frontend/wailsjs/runtime/runtime.js deleted file mode 100644 index b5ae16d56..000000000 --- a/v2/pkg/templates/templates/svelte/frontend/wailsjs/runtime/runtime.js +++ /dev/null @@ -1,182 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export function LogPrint(message) { - window.runtime.LogPrint(message); -} - -export function LogTrace(message) { - window.runtime.LogTrace(message); -} - -export function LogDebug(message) { - window.runtime.LogDebug(message); -} - -export function LogInfo(message) { - window.runtime.LogInfo(message); -} - -export function LogWarning(message) { - window.runtime.LogWarning(message); -} - -export function LogError(message) { - window.runtime.LogError(message); -} - -export function LogFatal(message) { - window.runtime.LogFatal(message); -} - -export function EventsOnMultiple(eventName, callback, maxCallbacks) { - window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks); -} - -export function EventsOn(eventName, callback) { - EventsOnMultiple(eventName, callback, -1); -} - -export function EventsOff(eventName) { - return window.runtime.EventsOff(eventName); -} - -export function EventsOffAll() { - return window.runtime.EventsOffAll(); -} - -export function EventsOnce(eventName, callback) { - EventsOnMultiple(eventName, callback, 1); -} - -export function EventsEmit(eventName) { - let args = [eventName].slice.call(arguments); - return window.runtime.EventsEmit.apply(null, args); -} - -export function WindowReload() { - window.runtime.WindowReload(); -} - -export function WindowReloadApp() { - window.runtime.WindowReloadApp(); -} - -export function WindowSetAlwaysOnTop(b) { - window.runtime.WindowSetAlwaysOnTop(b); -} - -export function WindowSetSystemDefaultTheme() { - window.runtime.WindowSetSystemDefaultTheme(); -} - -export function WindowSetLightTheme() { - window.runtime.WindowSetLightTheme(); -} - -export function WindowSetDarkTheme() { - window.runtime.WindowSetDarkTheme(); -} - -export function WindowCenter() { - window.runtime.WindowCenter(); -} - -export function WindowSetTitle(title) { - window.runtime.WindowSetTitle(title); -} - -export function WindowFullscreen() { - window.runtime.WindowFullscreen(); -} - -export function WindowUnfullscreen() { - window.runtime.WindowUnfullscreen(); -} - -export function WindowGetSize() { - return window.runtime.WindowGetSize(); -} - -export function WindowSetSize(width, height) { - window.runtime.WindowSetSize(width, height); -} - -export function WindowSetMaxSize(width, height) { - window.runtime.WindowSetMaxSize(width, height); -} - -export function WindowSetMinSize(width, height) { - window.runtime.WindowSetMinSize(width, height); -} - -export function WindowSetPosition(x, y) { - window.runtime.WindowSetPosition(x, y); -} - -export function WindowGetPosition() { - return window.runtime.WindowGetPosition(); -} - -export function WindowHide() { - window.runtime.WindowHide(); -} - -export function WindowShow() { - window.runtime.WindowShow(); -} - -export function WindowMaximise() { - window.runtime.WindowMaximise(); -} - -export function WindowToggleMaximise() { - window.runtime.WindowToggleMaximise(); -} - -export function WindowUnmaximise() { - window.runtime.WindowUnmaximise(); -} - -export function WindowMinimise() { - window.runtime.WindowMinimise(); -} - -export function WindowUnminimise() { - window.runtime.WindowUnminimise(); -} - -export function WindowSetBackgroundColour(R, G, B, A) { - window.runtime.WindowSetBackgroundColour(R, G, B, A); -} - -export function ScreenGetAll() { - return window.runtime.ScreenGetAll(); -} - -export function BrowserOpenURL(url) { - window.runtime.BrowserOpenURL(url); -} - -export function Environment() { - return window.runtime.Environment(); -} - -export function Quit() { - window.runtime.Quit(); -} - -export function Hide() { - window.runtime.Hide(); -} - -export function Show() { - window.runtime.Show(); -} diff --git a/v2/pkg/templates/templates/svelte/go.mod.tmpl b/v2/pkg/templates/templates/svelte/go.mod.tmpl deleted file mode 100644 index 4b34d1668..000000000 --- a/v2/pkg/templates/templates/svelte/go.mod.tmpl +++ /dev/null @@ -1,7 +0,0 @@ -module changeme - -go 1.23.0 - -require github.com/wailsapp/wails/v2 {{.WailsVersion}} - -// replace github.com/wailsapp/wails/v2 {{.WailsVersion}} => {{.WailsDirectory}} \ No newline at end of file diff --git a/v2/pkg/templates/templates/svelte/main.go.tmpl b/v2/pkg/templates/templates/svelte/main.go.tmpl deleted file mode 100644 index e24782be3..000000000 --- a/v2/pkg/templates/templates/svelte/main.go.tmpl +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import ( - "embed" - - "github.com/wailsapp/wails/v2" - "github.com/wailsapp/wails/v2/pkg/options" - "github.com/wailsapp/wails/v2/pkg/options/assetserver" -) - -//go:embed all:frontend/dist -var assets embed.FS - -func main() { - // Create an instance of the app structure - app := NewApp() - - // Create application with options - err := wails.Run(&options.App{ - Title: "{{.ProjectName}}", - Width: 1024, - Height: 768, - AssetServer: &assetserver.Options{ - Assets: assets, - }, - BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, - OnStartup: app.startup, - Bind: []interface{}{ - app, - }, - }) - - if err != nil { - println("Error:", err.Error()) - } -} diff --git a/v2/pkg/templates/templates/svelte/template.json b/v2/pkg/templates/templates/svelte/template.json deleted file mode 100644 index fb02c7a8b..000000000 --- a/v2/pkg/templates/templates/svelte/template.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "Svelte + Vite", - "shortname": "svelte", - "author": "Lea Anthony", - "description": "Svelte + Vite development server", - "helpurl": "https://wails.io" -} \ No newline at end of file diff --git a/v2/pkg/templates/templates/svelte/wails.tmpl.json b/v2/pkg/templates/templates/svelte/wails.tmpl.json deleted file mode 100644 index c39b2cb7d..000000000 --- a/v2/pkg/templates/templates/svelte/wails.tmpl.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "$schema": "https://wails.io/schemas/config.v2.json", - "name": "{{.ProjectName}}", - "outputfilename": "{{.BinaryName}}", - "frontend:install": "npm install", - "frontend:build": "npm run build", - "frontend:dev:watcher": "npm run dev", - "frontend:dev:serverUrl": "auto", - "author": { - "name": "{{.AuthorName}}", - "email": "{{.AuthorEmail}}" - } -} diff --git a/v2/pkg/templates/templates/vanilla-ts/.gitignore.tmpl b/v2/pkg/templates/templates/vanilla-ts/.gitignore.tmpl deleted file mode 100644 index 129d52294..000000000 --- a/v2/pkg/templates/templates/vanilla-ts/.gitignore.tmpl +++ /dev/null @@ -1,3 +0,0 @@ -build/bin -node_modules -frontend/dist diff --git a/v2/pkg/templates/templates/vanilla-ts/README.md b/v2/pkg/templates/templates/vanilla-ts/README.md deleted file mode 100644 index 4d7bcd378..000000000 --- a/v2/pkg/templates/templates/vanilla-ts/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# README - -## About - -This is the official Wails Vanilla-TS template. - -You can configure the project by editing `wails.json`. More information about the project settings can be found -here: https://wails.io/docs/reference/project-config - -## Live Development - -To run in live development mode, run `wails dev` in the project directory. This will run a Vite development -server that will provide very fast hot reload of your frontend changes. If you want to develop in a browser -and have access to your Go methods, there is also a dev server that runs on http://localhost:34115. Connect -to this in your browser, and you can call your Go code from devtools. - -## Building - -To build a redistributable, production mode package, use `wails build`. diff --git a/v2/pkg/templates/templates/vanilla-ts/app.tmpl.go b/v2/pkg/templates/templates/vanilla-ts/app.tmpl.go deleted file mode 100644 index af53038a1..000000000 --- a/v2/pkg/templates/templates/vanilla-ts/app.tmpl.go +++ /dev/null @@ -1,27 +0,0 @@ -package main - -import ( - "context" - "fmt" -) - -// App struct -type App struct { - ctx context.Context -} - -// NewApp creates a new App application struct -func NewApp() *App { - return &App{} -} - -// startup is called when the app starts. The context is saved -// so we can call the runtime methods -func (a *App) startup(ctx context.Context) { - a.ctx = ctx -} - -// Greet returns a greeting for the given name -func (a *App) Greet(name string) string { - return fmt.Sprintf("Hello %s, It's show time!", name) -} diff --git a/v2/pkg/templates/templates/vanilla-ts/frontend/dist/gitkeep b/v2/pkg/templates/templates/vanilla-ts/frontend/dist/gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/v2/pkg/templates/templates/vanilla-ts/frontend/index.tmpl.html b/v2/pkg/templates/templates/vanilla-ts/frontend/index.tmpl.html deleted file mode 100644 index 3dd212f2d..000000000 --- a/v2/pkg/templates/templates/vanilla-ts/frontend/index.tmpl.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - {{.ProjectName}} - - -
- - - diff --git a/v2/pkg/templates/templates/vanilla-ts/frontend/package.json b/v2/pkg/templates/templates/vanilla-ts/frontend/package.json deleted file mode 100644 index c57eb8610..000000000 --- a/v2/pkg/templates/templates/vanilla-ts/frontend/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "frontend", - "private": true, - "version": "0.0.0", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "typescript": "^4.5.4", - "vite": "^3.0.7" - } -} \ No newline at end of file diff --git a/v2/pkg/templates/templates/vanilla-ts/frontend/src/app.css b/v2/pkg/templates/templates/vanilla-ts/frontend/src/app.css deleted file mode 100644 index 59d06f692..000000000 --- a/v2/pkg/templates/templates/vanilla-ts/frontend/src/app.css +++ /dev/null @@ -1,54 +0,0 @@ -#logo { - display: block; - width: 50%; - height: 50%; - margin: auto; - padding: 10% 0 0; - background-position: center; - background-repeat: no-repeat; - background-size: 100% 100%; - background-origin: content-box; -} - -.result { - height: 20px; - line-height: 20px; - margin: 1.5rem auto; -} - -.input-box .btn { - width: 60px; - height: 30px; - line-height: 30px; - border-radius: 3px; - border: none; - margin: 0 0 0 20px; - padding: 0 8px; - cursor: pointer; -} - -.input-box .btn:hover { - background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%); - color: #333333; -} - -.input-box .input { - border: none; - border-radius: 3px; - outline: none; - height: 30px; - line-height: 30px; - padding: 0 10px; - background-color: rgba(240, 240, 240, 1); - -webkit-font-smoothing: antialiased; -} - -.input-box .input:hover { - border: none; - background-color: rgba(255, 255, 255, 1); -} - -.input-box .input:focus { - border: none; - background-color: rgba(255, 255, 255, 1); -} \ No newline at end of file diff --git a/v2/pkg/templates/templates/vanilla-ts/frontend/src/assets/fonts/OFL.txt b/v2/pkg/templates/templates/vanilla-ts/frontend/src/assets/fonts/OFL.txt deleted file mode 100644 index 9cac04ce8..000000000 --- a/v2/pkg/templates/templates/vanilla-ts/frontend/src/assets/fonts/OFL.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com), - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/v2/pkg/templates/templates/vanilla-ts/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 b/v2/pkg/templates/templates/vanilla-ts/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 deleted file mode 100644 index 2f9cc5964..000000000 Binary files a/v2/pkg/templates/templates/vanilla-ts/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 and /dev/null differ diff --git a/v2/pkg/templates/templates/vanilla-ts/frontend/src/assets/images/logo-universal.png b/v2/pkg/templates/templates/vanilla-ts/frontend/src/assets/images/logo-universal.png deleted file mode 100644 index d63303bfa..000000000 Binary files a/v2/pkg/templates/templates/vanilla-ts/frontend/src/assets/images/logo-universal.png and /dev/null differ diff --git a/v2/pkg/templates/templates/vanilla-ts/frontend/src/main.ts b/v2/pkg/templates/templates/vanilla-ts/frontend/src/main.ts deleted file mode 100644 index b68d7d961..000000000 --- a/v2/pkg/templates/templates/vanilla-ts/frontend/src/main.ts +++ /dev/null @@ -1,49 +0,0 @@ -import './style.css'; -import './app.css'; - -import logo from './assets/images/logo-universal.png'; -import {Greet} from '../wailsjs/go/main/App'; - -// Setup the greet function -window.greet = function () { - // Get name - let name = nameElement!.value; - - // Check if the input is empty - if (name === "") return; - - // Call App.Greet(name) - try { - Greet(name) - .then((result) => { - // Update result with data back from App.Greet() - resultElement!.innerText = result; - }) - .catch((err) => { - console.error(err); - }); - } catch (err) { - console.error(err); - } -}; - -document.querySelector('#app')!.innerHTML = ` - -
Please enter your name below 👇
-
- - -
- -`; -(document.getElementById('logo') as HTMLImageElement).src = logo; - -let nameElement = (document.getElementById("name") as HTMLInputElement); -nameElement.focus(); -let resultElement = document.getElementById("result"); - -declare global { - interface Window { - greet: () => void; - } -} diff --git a/v2/pkg/templates/templates/vanilla-ts/frontend/src/style.css b/v2/pkg/templates/templates/vanilla-ts/frontend/src/style.css deleted file mode 100644 index 3940d6c63..000000000 --- a/v2/pkg/templates/templates/vanilla-ts/frontend/src/style.css +++ /dev/null @@ -1,26 +0,0 @@ -html { - background-color: rgba(27, 38, 54, 1); - text-align: center; - color: white; -} - -body { - margin: 0; - color: white; - font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", - "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", - sans-serif; -} - -@font-face { - font-family: "Nunito"; - font-style: normal; - font-weight: 400; - src: local(""), - url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2"); -} - -#app { - height: 100vh; - text-align: center; -} diff --git a/v2/pkg/templates/templates/vanilla-ts/frontend/src/vite-env.d.ts b/v2/pkg/templates/templates/vanilla-ts/frontend/src/vite-env.d.ts deleted file mode 100644 index 11f02fe2a..000000000 --- a/v2/pkg/templates/templates/vanilla-ts/frontend/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/v2/pkg/templates/templates/vanilla-ts/frontend/tsconfig.json b/v2/pkg/templates/templates/vanilla-ts/frontend/tsconfig.json deleted file mode 100644 index 62645742d..000000000 --- a/v2/pkg/templates/templates/vanilla-ts/frontend/tsconfig.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": [ - "ESNext", - "DOM" - ], - "moduleResolution": "Node", - "strict": true, - "sourceMap": true, - "resolveJsonModule": true, - "isolatedModules": true, - "esModuleInterop": true, - "noEmit": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "skipLibCheck": true - }, - "include": [ - "src" - ] -} diff --git a/v2/pkg/templates/templates/vanilla-ts/frontend/wailsjs/go/main/App.d.ts b/v2/pkg/templates/templates/vanilla-ts/frontend/wailsjs/go/main/App.d.ts deleted file mode 100644 index 43173cfce..000000000 --- a/v2/pkg/templates/templates/vanilla-ts/frontend/wailsjs/go/main/App.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Greet(arg1: string): Promise; diff --git a/v2/pkg/templates/templates/vanilla-ts/frontend/wailsjs/go/main/App.js b/v2/pkg/templates/templates/vanilla-ts/frontend/wailsjs/go/main/App.js deleted file mode 100644 index 0ee085c95..000000000 --- a/v2/pkg/templates/templates/vanilla-ts/frontend/wailsjs/go/main/App.js +++ /dev/null @@ -1,7 +0,0 @@ -// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Greet(arg1) { - return window['go']['main']['App']['Greet'](arg1); -} diff --git a/v2/pkg/templates/templates/vanilla-ts/frontend/wailsjs/runtime/package.json b/v2/pkg/templates/templates/vanilla-ts/frontend/wailsjs/runtime/package.json deleted file mode 100644 index 1e7c8a5d7..000000000 --- a/v2/pkg/templates/templates/vanilla-ts/frontend/wailsjs/runtime/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "@wailsapp/runtime", - "version": "2.0.0", - "description": "Wails Javascript runtime library", - "main": "runtime.js", - "types": "runtime.d.ts", - "scripts": { - }, - "repository": { - "type": "git", - "url": "git+https://github.com/wailsapp/wails.git" - }, - "keywords": [ - "Wails", - "Javascript", - "Go" - ], - "author": "Lea Anthony ", - "license": "MIT", - "bugs": { - "url": "https://github.com/wailsapp/wails/issues" - }, - "homepage": "https://github.com/wailsapp/wails#readme" -} diff --git a/v2/pkg/templates/templates/vanilla-ts/frontend/wailsjs/runtime/runtime.d.ts b/v2/pkg/templates/templates/vanilla-ts/frontend/wailsjs/runtime/runtime.d.ts deleted file mode 100644 index 336fb07aa..000000000 --- a/v2/pkg/templates/templates/vanilla-ts/frontend/wailsjs/runtime/runtime.d.ts +++ /dev/null @@ -1,211 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export interface Position { - x: number; - y: number; -} - -export interface Size { - w: number; - h: number; -} - -export interface Screen { - isCurrent: boolean; - isPrimary: boolean; - width: number - height: number -} - -// Environment information such as platform, buildtype, ... -export interface EnvironmentInfo { - buildType: string; - platform: string; - arch: string; -} - -// [EventsEmit](https://wails.io/docs/reference/runtime/events#eventsemit) -// emits the given event. Optional data may be passed with the event. -// This will trigger any event listeners. -export function EventsEmit(eventName: string, ...data: any): void; - -// [EventsOn](https://wails.io/docs/reference/runtime/events#eventson) sets up a listener for the given event name. -export function EventsOn(eventName: string, callback: (...data: any) => void): void; - -// [EventsOnMultiple](https://wails.io/docs/reference/runtime/events#eventsonmultiple) -// sets up a listener for the given event name, but will only trigger a given number times. -export function EventsOnMultiple(eventName: string, callback: (...data: any) => void, maxCallbacks: number): void; - -// [EventsOnce](https://wails.io/docs/reference/runtime/events#eventsonce) -// sets up a listener for the given event name, but will only trigger once. -export function EventsOnce(eventName: string, callback: (...data: any) => void): void; - -// [EventsOff](https://wails.io/docs/reference/runtime/events#eventsff) -// unregisters the listener for the given event name. -export function EventsOff(eventName: string): void; - -// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) -// unregisters all event listeners. -export function EventsOffAll(): void; - -// [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) -// logs the given message as a raw message -export function LogPrint(message: string): void; - -// [LogTrace](https://wails.io/docs/reference/runtime/log#logtrace) -// logs the given message at the `trace` log level. -export function LogTrace(message: string): void; - -// [LogDebug](https://wails.io/docs/reference/runtime/log#logdebug) -// logs the given message at the `debug` log level. -export function LogDebug(message: string): void; - -// [LogError](https://wails.io/docs/reference/runtime/log#logerror) -// logs the given message at the `error` log level. -export function LogError(message: string): void; - -// [LogFatal](https://wails.io/docs/reference/runtime/log#logfatal) -// logs the given message at the `fatal` log level. -// The application will quit after calling this method. -export function LogFatal(message: string): void; - -// [LogInfo](https://wails.io/docs/reference/runtime/log#loginfo) -// logs the given message at the `info` log level. -export function LogInfo(message: string): void; - -// [LogWarning](https://wails.io/docs/reference/runtime/log#logwarning) -// logs the given message at the `warning` log level. -export function LogWarning(message: string): void; - -// [WindowReload](https://wails.io/docs/reference/runtime/window#windowreload) -// Forces a reload by the main application as well as connected browsers. -export function WindowReload(): void; - -// [WindowReloadApp](https://wails.io/docs/reference/runtime/window#windowreloadapp) -// Reloads the application frontend. -export function WindowReloadApp(): void; - -// [WindowSetAlwaysOnTop](https://wails.io/docs/reference/runtime/window#windowsetalwaysontop) -// Sets the window AlwaysOnTop or not on top. -export function WindowSetAlwaysOnTop(b: boolean): void; - -// [WindowSetSystemDefaultTheme](https://wails.io/docs/next/reference/runtime/window#windowsetsystemdefaulttheme) -// *Windows only* -// Sets window theme to system default (dark/light). -export function WindowSetSystemDefaultTheme(): void; - -// [WindowSetLightTheme](https://wails.io/docs/next/reference/runtime/window#windowsetlighttheme) -// *Windows only* -// Sets window to light theme. -export function WindowSetLightTheme(): void; - -// [WindowSetDarkTheme](https://wails.io/docs/next/reference/runtime/window#windowsetdarktheme) -// *Windows only* -// Sets window to dark theme. -export function WindowSetDarkTheme(): void; - -// [WindowCenter](https://wails.io/docs/reference/runtime/window#windowcenter) -// Centers the window on the monitor the window is currently on. -export function WindowCenter(): void; - -// [WindowSetTitle](https://wails.io/docs/reference/runtime/window#windowsettitle) -// Sets the text in the window title bar. -export function WindowSetTitle(title: string): void; - -// [WindowFullscreen](https://wails.io/docs/reference/runtime/window#windowfullscreen) -// Makes the window full screen. -export function WindowFullscreen(): void; - -// [WindowUnfullscreen](https://wails.io/docs/reference/runtime/window#windowunfullscreen) -// Restores the previous window dimensions and position prior to full screen. -export function WindowUnfullscreen(): void; - -// [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize) -// Sets the width and height of the window. -export function WindowSetSize(width: number, height: number): void; - -// [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize) -// Gets the width and height of the window. -export function WindowGetSize(): Promise; - -// [WindowSetMaxSize](https://wails.io/docs/reference/runtime/window#windowsetmaxsize) -// Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMaxSize(width: number, height: number): void; - -// [WindowSetMinSize](https://wails.io/docs/reference/runtime/window#windowsetminsize) -// Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMinSize(width: number, height: number): void; - -// [WindowSetPosition](https://wails.io/docs/reference/runtime/window#windowsetposition) -// Sets the window position relative to the monitor the window is currently on. -export function WindowSetPosition(x: number, y: number): void; - -// [WindowGetPosition](https://wails.io/docs/reference/runtime/window#windowgetposition) -// Gets the window position relative to the monitor the window is currently on. -export function WindowGetPosition(): Promise; - -// [WindowHide](https://wails.io/docs/reference/runtime/window#windowhide) -// Hides the window. -export function WindowHide(): void; - -// [WindowShow](https://wails.io/docs/reference/runtime/window#windowshow) -// Shows the window, if it is currently hidden. -export function WindowShow(): void; - -// [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise) -// Maximises the window to fill the screen. -export function WindowMaximise(): void; - -// [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise) -// Toggles between Maximised and UnMaximised. -export function WindowToggleMaximise(): void; - -// [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise) -// Restores the window to the dimensions and position prior to maximising. -export function WindowUnmaximise(): void; - -// [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise) -// Minimises the window. -export function WindowMinimise(): void; - -// [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise) -// Restores the window to the dimensions and position prior to minimising. -export function WindowUnminimise(): void; - -// [WindowSetBackgroundColour](https://wails.io/docs/reference/runtime/window#windowsetbackgroundcolour) -// Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels. -export function WindowSetBackgroundColour(R: number, G: number, B: number, A: number): void; - -// [ScreenGetAll](https://wails.io/docs/reference/runtime/window#screengetall) -// Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system. -export function ScreenGetAll(): Promise; - -// [BrowserOpenURL](https://wails.io/docs/reference/runtime/browser#browseropenurl) -// Opens the given URL in the system browser. -export function BrowserOpenURL(url: string): void; - -// [Environment](https://wails.io/docs/reference/runtime/intro#environment) -// Returns information about the environment -export function Environment(): Promise; - -// [Quit](https://wails.io/docs/reference/runtime/intro#quit) -// Quits the application. -export function Quit(): void; - -// [Hide](https://wails.io/docs/reference/runtime/intro#hide) -// Hides the application. -export function Hide(): void; - -// [Show](https://wails.io/docs/reference/runtime/intro#show) -// Shows the application. -export function Show(): void; diff --git a/v2/pkg/templates/templates/vanilla-ts/frontend/wailsjs/runtime/runtime.js b/v2/pkg/templates/templates/vanilla-ts/frontend/wailsjs/runtime/runtime.js deleted file mode 100644 index b5ae16d56..000000000 --- a/v2/pkg/templates/templates/vanilla-ts/frontend/wailsjs/runtime/runtime.js +++ /dev/null @@ -1,182 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export function LogPrint(message) { - window.runtime.LogPrint(message); -} - -export function LogTrace(message) { - window.runtime.LogTrace(message); -} - -export function LogDebug(message) { - window.runtime.LogDebug(message); -} - -export function LogInfo(message) { - window.runtime.LogInfo(message); -} - -export function LogWarning(message) { - window.runtime.LogWarning(message); -} - -export function LogError(message) { - window.runtime.LogError(message); -} - -export function LogFatal(message) { - window.runtime.LogFatal(message); -} - -export function EventsOnMultiple(eventName, callback, maxCallbacks) { - window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks); -} - -export function EventsOn(eventName, callback) { - EventsOnMultiple(eventName, callback, -1); -} - -export function EventsOff(eventName) { - return window.runtime.EventsOff(eventName); -} - -export function EventsOffAll() { - return window.runtime.EventsOffAll(); -} - -export function EventsOnce(eventName, callback) { - EventsOnMultiple(eventName, callback, 1); -} - -export function EventsEmit(eventName) { - let args = [eventName].slice.call(arguments); - return window.runtime.EventsEmit.apply(null, args); -} - -export function WindowReload() { - window.runtime.WindowReload(); -} - -export function WindowReloadApp() { - window.runtime.WindowReloadApp(); -} - -export function WindowSetAlwaysOnTop(b) { - window.runtime.WindowSetAlwaysOnTop(b); -} - -export function WindowSetSystemDefaultTheme() { - window.runtime.WindowSetSystemDefaultTheme(); -} - -export function WindowSetLightTheme() { - window.runtime.WindowSetLightTheme(); -} - -export function WindowSetDarkTheme() { - window.runtime.WindowSetDarkTheme(); -} - -export function WindowCenter() { - window.runtime.WindowCenter(); -} - -export function WindowSetTitle(title) { - window.runtime.WindowSetTitle(title); -} - -export function WindowFullscreen() { - window.runtime.WindowFullscreen(); -} - -export function WindowUnfullscreen() { - window.runtime.WindowUnfullscreen(); -} - -export function WindowGetSize() { - return window.runtime.WindowGetSize(); -} - -export function WindowSetSize(width, height) { - window.runtime.WindowSetSize(width, height); -} - -export function WindowSetMaxSize(width, height) { - window.runtime.WindowSetMaxSize(width, height); -} - -export function WindowSetMinSize(width, height) { - window.runtime.WindowSetMinSize(width, height); -} - -export function WindowSetPosition(x, y) { - window.runtime.WindowSetPosition(x, y); -} - -export function WindowGetPosition() { - return window.runtime.WindowGetPosition(); -} - -export function WindowHide() { - window.runtime.WindowHide(); -} - -export function WindowShow() { - window.runtime.WindowShow(); -} - -export function WindowMaximise() { - window.runtime.WindowMaximise(); -} - -export function WindowToggleMaximise() { - window.runtime.WindowToggleMaximise(); -} - -export function WindowUnmaximise() { - window.runtime.WindowUnmaximise(); -} - -export function WindowMinimise() { - window.runtime.WindowMinimise(); -} - -export function WindowUnminimise() { - window.runtime.WindowUnminimise(); -} - -export function WindowSetBackgroundColour(R, G, B, A) { - window.runtime.WindowSetBackgroundColour(R, G, B, A); -} - -export function ScreenGetAll() { - return window.runtime.ScreenGetAll(); -} - -export function BrowserOpenURL(url) { - window.runtime.BrowserOpenURL(url); -} - -export function Environment() { - return window.runtime.Environment(); -} - -export function Quit() { - window.runtime.Quit(); -} - -export function Hide() { - window.runtime.Hide(); -} - -export function Show() { - window.runtime.Show(); -} diff --git a/v2/pkg/templates/templates/vanilla-ts/go.mod.tmpl b/v2/pkg/templates/templates/vanilla-ts/go.mod.tmpl deleted file mode 100644 index 4b34d1668..000000000 --- a/v2/pkg/templates/templates/vanilla-ts/go.mod.tmpl +++ /dev/null @@ -1,7 +0,0 @@ -module changeme - -go 1.23.0 - -require github.com/wailsapp/wails/v2 {{.WailsVersion}} - -// replace github.com/wailsapp/wails/v2 {{.WailsVersion}} => {{.WailsDirectory}} \ No newline at end of file diff --git a/v2/pkg/templates/templates/vanilla-ts/main.go.tmpl b/v2/pkg/templates/templates/vanilla-ts/main.go.tmpl deleted file mode 100644 index e24782be3..000000000 --- a/v2/pkg/templates/templates/vanilla-ts/main.go.tmpl +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import ( - "embed" - - "github.com/wailsapp/wails/v2" - "github.com/wailsapp/wails/v2/pkg/options" - "github.com/wailsapp/wails/v2/pkg/options/assetserver" -) - -//go:embed all:frontend/dist -var assets embed.FS - -func main() { - // Create an instance of the app structure - app := NewApp() - - // Create application with options - err := wails.Run(&options.App{ - Title: "{{.ProjectName}}", - Width: 1024, - Height: 768, - AssetServer: &assetserver.Options{ - Assets: assets, - }, - BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, - OnStartup: app.startup, - Bind: []interface{}{ - app, - }, - }) - - if err != nil { - println("Error:", err.Error()) - } -} diff --git a/v2/pkg/templates/templates/vanilla-ts/template.json b/v2/pkg/templates/templates/vanilla-ts/template.json deleted file mode 100644 index 5aed52c89..000000000 --- a/v2/pkg/templates/templates/vanilla-ts/template.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "Vanilla + Vite (Typescript)", - "shortname": "vanilla-ts", - "author": "Lea Anthony", - "description": "Vanilla + Vite development server", - "helpurl": "https://wails.io" -} \ No newline at end of file diff --git a/v2/pkg/templates/templates/vanilla-ts/wails.tmpl.json b/v2/pkg/templates/templates/vanilla-ts/wails.tmpl.json deleted file mode 100644 index c39b2cb7d..000000000 --- a/v2/pkg/templates/templates/vanilla-ts/wails.tmpl.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "$schema": "https://wails.io/schemas/config.v2.json", - "name": "{{.ProjectName}}", - "outputfilename": "{{.BinaryName}}", - "frontend:install": "npm install", - "frontend:build": "npm run build", - "frontend:dev:watcher": "npm run dev", - "frontend:dev:serverUrl": "auto", - "author": { - "name": "{{.AuthorName}}", - "email": "{{.AuthorEmail}}" - } -} diff --git a/v2/pkg/templates/templates/vanilla/.gitignore.tmpl b/v2/pkg/templates/templates/vanilla/.gitignore.tmpl deleted file mode 100644 index 129d52294..000000000 --- a/v2/pkg/templates/templates/vanilla/.gitignore.tmpl +++ /dev/null @@ -1,3 +0,0 @@ -build/bin -node_modules -frontend/dist diff --git a/v2/pkg/templates/templates/vanilla/README.md b/v2/pkg/templates/templates/vanilla/README.md deleted file mode 100644 index 397b08b92..000000000 --- a/v2/pkg/templates/templates/vanilla/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# README - -## About - -This is the official Wails Vanilla template. - -You can configure the project by editing `wails.json`. More information about the project settings can be found -here: https://wails.io/docs/reference/project-config - -## Live Development - -To run in live development mode, run `wails dev` in the project directory. This will run a Vite development -server that will provide very fast hot reload of your frontend changes. If you want to develop in a browser -and have access to your Go methods, there is also a dev server that runs on http://localhost:34115. Connect -to this in your browser, and you can call your Go code from devtools. - -## Building - -To build a redistributable, production mode package, use `wails build`. diff --git a/v2/pkg/templates/templates/vanilla/app.tmpl.go b/v2/pkg/templates/templates/vanilla/app.tmpl.go deleted file mode 100644 index af53038a1..000000000 --- a/v2/pkg/templates/templates/vanilla/app.tmpl.go +++ /dev/null @@ -1,27 +0,0 @@ -package main - -import ( - "context" - "fmt" -) - -// App struct -type App struct { - ctx context.Context -} - -// NewApp creates a new App application struct -func NewApp() *App { - return &App{} -} - -// startup is called when the app starts. The context is saved -// so we can call the runtime methods -func (a *App) startup(ctx context.Context) { - a.ctx = ctx -} - -// Greet returns a greeting for the given name -func (a *App) Greet(name string) string { - return fmt.Sprintf("Hello %s, It's show time!", name) -} diff --git a/v2/pkg/templates/templates/vanilla/frontend/dist/gitkeep b/v2/pkg/templates/templates/vanilla/frontend/dist/gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/v2/pkg/templates/templates/vanilla/frontend/index.tmpl.html b/v2/pkg/templates/templates/vanilla/frontend/index.tmpl.html deleted file mode 100644 index 859919153..000000000 --- a/v2/pkg/templates/templates/vanilla/frontend/index.tmpl.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - {{.ProjectName}} - - -
- - - diff --git a/v2/pkg/templates/templates/vanilla/frontend/package.json b/v2/pkg/templates/templates/vanilla/frontend/package.json deleted file mode 100644 index a1b6f8e1a..000000000 --- a/v2/pkg/templates/templates/vanilla/frontend/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "frontend", - "private": true, - "version": "0.0.0", - "scripts": { - "dev": "vite", - "build": "vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^3.0.7" - } -} \ No newline at end of file diff --git a/v2/pkg/templates/templates/vanilla/frontend/src/app.css b/v2/pkg/templates/templates/vanilla/frontend/src/app.css deleted file mode 100644 index 59d06f692..000000000 --- a/v2/pkg/templates/templates/vanilla/frontend/src/app.css +++ /dev/null @@ -1,54 +0,0 @@ -#logo { - display: block; - width: 50%; - height: 50%; - margin: auto; - padding: 10% 0 0; - background-position: center; - background-repeat: no-repeat; - background-size: 100% 100%; - background-origin: content-box; -} - -.result { - height: 20px; - line-height: 20px; - margin: 1.5rem auto; -} - -.input-box .btn { - width: 60px; - height: 30px; - line-height: 30px; - border-radius: 3px; - border: none; - margin: 0 0 0 20px; - padding: 0 8px; - cursor: pointer; -} - -.input-box .btn:hover { - background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%); - color: #333333; -} - -.input-box .input { - border: none; - border-radius: 3px; - outline: none; - height: 30px; - line-height: 30px; - padding: 0 10px; - background-color: rgba(240, 240, 240, 1); - -webkit-font-smoothing: antialiased; -} - -.input-box .input:hover { - border: none; - background-color: rgba(255, 255, 255, 1); -} - -.input-box .input:focus { - border: none; - background-color: rgba(255, 255, 255, 1); -} \ No newline at end of file diff --git a/v2/pkg/templates/templates/vanilla/frontend/src/assets/fonts/OFL.txt b/v2/pkg/templates/templates/vanilla/frontend/src/assets/fonts/OFL.txt deleted file mode 100644 index 9cac04ce8..000000000 --- a/v2/pkg/templates/templates/vanilla/frontend/src/assets/fonts/OFL.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com), - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/v2/pkg/templates/templates/vanilla/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 b/v2/pkg/templates/templates/vanilla/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 deleted file mode 100644 index 2f9cc5964..000000000 Binary files a/v2/pkg/templates/templates/vanilla/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 and /dev/null differ diff --git a/v2/pkg/templates/templates/vanilla/frontend/src/assets/images/logo-universal.png b/v2/pkg/templates/templates/vanilla/frontend/src/assets/images/logo-universal.png deleted file mode 100644 index d63303bfa..000000000 Binary files a/v2/pkg/templates/templates/vanilla/frontend/src/assets/images/logo-universal.png and /dev/null differ diff --git a/v2/pkg/templates/templates/vanilla/frontend/src/main.js b/v2/pkg/templates/templates/vanilla/frontend/src/main.js deleted file mode 100644 index 4ad5a2cae..000000000 --- a/v2/pkg/templates/templates/vanilla/frontend/src/main.js +++ /dev/null @@ -1,43 +0,0 @@ -import './style.css'; -import './app.css'; - -import logo from './assets/images/logo-universal.png'; -import {Greet} from '../wailsjs/go/main/App'; - -document.querySelector('#app').innerHTML = ` - -
Please enter your name below 👇
-
- - -
- -`; -document.getElementById('logo').src = logo; - -let nameElement = document.getElementById("name"); -nameElement.focus(); -let resultElement = document.getElementById("result"); - -// Setup the greet function -window.greet = function () { - // Get name - let name = nameElement.value; - - // Check if the input is empty - if (name === "") return; - - // Call App.Greet(name) - try { - Greet(name) - .then((result) => { - // Update result with data back from App.Greet() - resultElement.innerText = result; - }) - .catch((err) => { - console.error(err); - }); - } catch (err) { - console.error(err); - } -}; diff --git a/v2/pkg/templates/templates/vanilla/frontend/src/style.css b/v2/pkg/templates/templates/vanilla/frontend/src/style.css deleted file mode 100644 index 3940d6c63..000000000 --- a/v2/pkg/templates/templates/vanilla/frontend/src/style.css +++ /dev/null @@ -1,26 +0,0 @@ -html { - background-color: rgba(27, 38, 54, 1); - text-align: center; - color: white; -} - -body { - margin: 0; - color: white; - font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", - "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", - sans-serif; -} - -@font-face { - font-family: "Nunito"; - font-style: normal; - font-weight: 400; - src: local(""), - url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2"); -} - -#app { - height: 100vh; - text-align: center; -} diff --git a/v2/pkg/templates/templates/vanilla/frontend/wailsjs/go/main/App.d.ts b/v2/pkg/templates/templates/vanilla/frontend/wailsjs/go/main/App.d.ts deleted file mode 100644 index 43173cfce..000000000 --- a/v2/pkg/templates/templates/vanilla/frontend/wailsjs/go/main/App.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Greet(arg1: string): Promise; diff --git a/v2/pkg/templates/templates/vanilla/frontend/wailsjs/go/main/App.js b/v2/pkg/templates/templates/vanilla/frontend/wailsjs/go/main/App.js deleted file mode 100644 index 0ee085c95..000000000 --- a/v2/pkg/templates/templates/vanilla/frontend/wailsjs/go/main/App.js +++ /dev/null @@ -1,7 +0,0 @@ -// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Greet(arg1) { - return window['go']['main']['App']['Greet'](arg1); -} diff --git a/v2/pkg/templates/templates/vanilla/frontend/wailsjs/runtime/package.json b/v2/pkg/templates/templates/vanilla/frontend/wailsjs/runtime/package.json deleted file mode 100644 index 1e7c8a5d7..000000000 --- a/v2/pkg/templates/templates/vanilla/frontend/wailsjs/runtime/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "@wailsapp/runtime", - "version": "2.0.0", - "description": "Wails Javascript runtime library", - "main": "runtime.js", - "types": "runtime.d.ts", - "scripts": { - }, - "repository": { - "type": "git", - "url": "git+https://github.com/wailsapp/wails.git" - }, - "keywords": [ - "Wails", - "Javascript", - "Go" - ], - "author": "Lea Anthony ", - "license": "MIT", - "bugs": { - "url": "https://github.com/wailsapp/wails/issues" - }, - "homepage": "https://github.com/wailsapp/wails#readme" -} diff --git a/v2/pkg/templates/templates/vanilla/frontend/wailsjs/runtime/runtime.d.ts b/v2/pkg/templates/templates/vanilla/frontend/wailsjs/runtime/runtime.d.ts deleted file mode 100644 index 336fb07aa..000000000 --- a/v2/pkg/templates/templates/vanilla/frontend/wailsjs/runtime/runtime.d.ts +++ /dev/null @@ -1,211 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export interface Position { - x: number; - y: number; -} - -export interface Size { - w: number; - h: number; -} - -export interface Screen { - isCurrent: boolean; - isPrimary: boolean; - width: number - height: number -} - -// Environment information such as platform, buildtype, ... -export interface EnvironmentInfo { - buildType: string; - platform: string; - arch: string; -} - -// [EventsEmit](https://wails.io/docs/reference/runtime/events#eventsemit) -// emits the given event. Optional data may be passed with the event. -// This will trigger any event listeners. -export function EventsEmit(eventName: string, ...data: any): void; - -// [EventsOn](https://wails.io/docs/reference/runtime/events#eventson) sets up a listener for the given event name. -export function EventsOn(eventName: string, callback: (...data: any) => void): void; - -// [EventsOnMultiple](https://wails.io/docs/reference/runtime/events#eventsonmultiple) -// sets up a listener for the given event name, but will only trigger a given number times. -export function EventsOnMultiple(eventName: string, callback: (...data: any) => void, maxCallbacks: number): void; - -// [EventsOnce](https://wails.io/docs/reference/runtime/events#eventsonce) -// sets up a listener for the given event name, but will only trigger once. -export function EventsOnce(eventName: string, callback: (...data: any) => void): void; - -// [EventsOff](https://wails.io/docs/reference/runtime/events#eventsff) -// unregisters the listener for the given event name. -export function EventsOff(eventName: string): void; - -// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) -// unregisters all event listeners. -export function EventsOffAll(): void; - -// [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) -// logs the given message as a raw message -export function LogPrint(message: string): void; - -// [LogTrace](https://wails.io/docs/reference/runtime/log#logtrace) -// logs the given message at the `trace` log level. -export function LogTrace(message: string): void; - -// [LogDebug](https://wails.io/docs/reference/runtime/log#logdebug) -// logs the given message at the `debug` log level. -export function LogDebug(message: string): void; - -// [LogError](https://wails.io/docs/reference/runtime/log#logerror) -// logs the given message at the `error` log level. -export function LogError(message: string): void; - -// [LogFatal](https://wails.io/docs/reference/runtime/log#logfatal) -// logs the given message at the `fatal` log level. -// The application will quit after calling this method. -export function LogFatal(message: string): void; - -// [LogInfo](https://wails.io/docs/reference/runtime/log#loginfo) -// logs the given message at the `info` log level. -export function LogInfo(message: string): void; - -// [LogWarning](https://wails.io/docs/reference/runtime/log#logwarning) -// logs the given message at the `warning` log level. -export function LogWarning(message: string): void; - -// [WindowReload](https://wails.io/docs/reference/runtime/window#windowreload) -// Forces a reload by the main application as well as connected browsers. -export function WindowReload(): void; - -// [WindowReloadApp](https://wails.io/docs/reference/runtime/window#windowreloadapp) -// Reloads the application frontend. -export function WindowReloadApp(): void; - -// [WindowSetAlwaysOnTop](https://wails.io/docs/reference/runtime/window#windowsetalwaysontop) -// Sets the window AlwaysOnTop or not on top. -export function WindowSetAlwaysOnTop(b: boolean): void; - -// [WindowSetSystemDefaultTheme](https://wails.io/docs/next/reference/runtime/window#windowsetsystemdefaulttheme) -// *Windows only* -// Sets window theme to system default (dark/light). -export function WindowSetSystemDefaultTheme(): void; - -// [WindowSetLightTheme](https://wails.io/docs/next/reference/runtime/window#windowsetlighttheme) -// *Windows only* -// Sets window to light theme. -export function WindowSetLightTheme(): void; - -// [WindowSetDarkTheme](https://wails.io/docs/next/reference/runtime/window#windowsetdarktheme) -// *Windows only* -// Sets window to dark theme. -export function WindowSetDarkTheme(): void; - -// [WindowCenter](https://wails.io/docs/reference/runtime/window#windowcenter) -// Centers the window on the monitor the window is currently on. -export function WindowCenter(): void; - -// [WindowSetTitle](https://wails.io/docs/reference/runtime/window#windowsettitle) -// Sets the text in the window title bar. -export function WindowSetTitle(title: string): void; - -// [WindowFullscreen](https://wails.io/docs/reference/runtime/window#windowfullscreen) -// Makes the window full screen. -export function WindowFullscreen(): void; - -// [WindowUnfullscreen](https://wails.io/docs/reference/runtime/window#windowunfullscreen) -// Restores the previous window dimensions and position prior to full screen. -export function WindowUnfullscreen(): void; - -// [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize) -// Sets the width and height of the window. -export function WindowSetSize(width: number, height: number): void; - -// [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize) -// Gets the width and height of the window. -export function WindowGetSize(): Promise; - -// [WindowSetMaxSize](https://wails.io/docs/reference/runtime/window#windowsetmaxsize) -// Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMaxSize(width: number, height: number): void; - -// [WindowSetMinSize](https://wails.io/docs/reference/runtime/window#windowsetminsize) -// Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMinSize(width: number, height: number): void; - -// [WindowSetPosition](https://wails.io/docs/reference/runtime/window#windowsetposition) -// Sets the window position relative to the monitor the window is currently on. -export function WindowSetPosition(x: number, y: number): void; - -// [WindowGetPosition](https://wails.io/docs/reference/runtime/window#windowgetposition) -// Gets the window position relative to the monitor the window is currently on. -export function WindowGetPosition(): Promise; - -// [WindowHide](https://wails.io/docs/reference/runtime/window#windowhide) -// Hides the window. -export function WindowHide(): void; - -// [WindowShow](https://wails.io/docs/reference/runtime/window#windowshow) -// Shows the window, if it is currently hidden. -export function WindowShow(): void; - -// [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise) -// Maximises the window to fill the screen. -export function WindowMaximise(): void; - -// [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise) -// Toggles between Maximised and UnMaximised. -export function WindowToggleMaximise(): void; - -// [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise) -// Restores the window to the dimensions and position prior to maximising. -export function WindowUnmaximise(): void; - -// [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise) -// Minimises the window. -export function WindowMinimise(): void; - -// [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise) -// Restores the window to the dimensions and position prior to minimising. -export function WindowUnminimise(): void; - -// [WindowSetBackgroundColour](https://wails.io/docs/reference/runtime/window#windowsetbackgroundcolour) -// Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels. -export function WindowSetBackgroundColour(R: number, G: number, B: number, A: number): void; - -// [ScreenGetAll](https://wails.io/docs/reference/runtime/window#screengetall) -// Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system. -export function ScreenGetAll(): Promise; - -// [BrowserOpenURL](https://wails.io/docs/reference/runtime/browser#browseropenurl) -// Opens the given URL in the system browser. -export function BrowserOpenURL(url: string): void; - -// [Environment](https://wails.io/docs/reference/runtime/intro#environment) -// Returns information about the environment -export function Environment(): Promise; - -// [Quit](https://wails.io/docs/reference/runtime/intro#quit) -// Quits the application. -export function Quit(): void; - -// [Hide](https://wails.io/docs/reference/runtime/intro#hide) -// Hides the application. -export function Hide(): void; - -// [Show](https://wails.io/docs/reference/runtime/intro#show) -// Shows the application. -export function Show(): void; diff --git a/v2/pkg/templates/templates/vanilla/frontend/wailsjs/runtime/runtime.js b/v2/pkg/templates/templates/vanilla/frontend/wailsjs/runtime/runtime.js deleted file mode 100644 index b5ae16d56..000000000 --- a/v2/pkg/templates/templates/vanilla/frontend/wailsjs/runtime/runtime.js +++ /dev/null @@ -1,182 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export function LogPrint(message) { - window.runtime.LogPrint(message); -} - -export function LogTrace(message) { - window.runtime.LogTrace(message); -} - -export function LogDebug(message) { - window.runtime.LogDebug(message); -} - -export function LogInfo(message) { - window.runtime.LogInfo(message); -} - -export function LogWarning(message) { - window.runtime.LogWarning(message); -} - -export function LogError(message) { - window.runtime.LogError(message); -} - -export function LogFatal(message) { - window.runtime.LogFatal(message); -} - -export function EventsOnMultiple(eventName, callback, maxCallbacks) { - window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks); -} - -export function EventsOn(eventName, callback) { - EventsOnMultiple(eventName, callback, -1); -} - -export function EventsOff(eventName) { - return window.runtime.EventsOff(eventName); -} - -export function EventsOffAll() { - return window.runtime.EventsOffAll(); -} - -export function EventsOnce(eventName, callback) { - EventsOnMultiple(eventName, callback, 1); -} - -export function EventsEmit(eventName) { - let args = [eventName].slice.call(arguments); - return window.runtime.EventsEmit.apply(null, args); -} - -export function WindowReload() { - window.runtime.WindowReload(); -} - -export function WindowReloadApp() { - window.runtime.WindowReloadApp(); -} - -export function WindowSetAlwaysOnTop(b) { - window.runtime.WindowSetAlwaysOnTop(b); -} - -export function WindowSetSystemDefaultTheme() { - window.runtime.WindowSetSystemDefaultTheme(); -} - -export function WindowSetLightTheme() { - window.runtime.WindowSetLightTheme(); -} - -export function WindowSetDarkTheme() { - window.runtime.WindowSetDarkTheme(); -} - -export function WindowCenter() { - window.runtime.WindowCenter(); -} - -export function WindowSetTitle(title) { - window.runtime.WindowSetTitle(title); -} - -export function WindowFullscreen() { - window.runtime.WindowFullscreen(); -} - -export function WindowUnfullscreen() { - window.runtime.WindowUnfullscreen(); -} - -export function WindowGetSize() { - return window.runtime.WindowGetSize(); -} - -export function WindowSetSize(width, height) { - window.runtime.WindowSetSize(width, height); -} - -export function WindowSetMaxSize(width, height) { - window.runtime.WindowSetMaxSize(width, height); -} - -export function WindowSetMinSize(width, height) { - window.runtime.WindowSetMinSize(width, height); -} - -export function WindowSetPosition(x, y) { - window.runtime.WindowSetPosition(x, y); -} - -export function WindowGetPosition() { - return window.runtime.WindowGetPosition(); -} - -export function WindowHide() { - window.runtime.WindowHide(); -} - -export function WindowShow() { - window.runtime.WindowShow(); -} - -export function WindowMaximise() { - window.runtime.WindowMaximise(); -} - -export function WindowToggleMaximise() { - window.runtime.WindowToggleMaximise(); -} - -export function WindowUnmaximise() { - window.runtime.WindowUnmaximise(); -} - -export function WindowMinimise() { - window.runtime.WindowMinimise(); -} - -export function WindowUnminimise() { - window.runtime.WindowUnminimise(); -} - -export function WindowSetBackgroundColour(R, G, B, A) { - window.runtime.WindowSetBackgroundColour(R, G, B, A); -} - -export function ScreenGetAll() { - return window.runtime.ScreenGetAll(); -} - -export function BrowserOpenURL(url) { - window.runtime.BrowserOpenURL(url); -} - -export function Environment() { - return window.runtime.Environment(); -} - -export function Quit() { - window.runtime.Quit(); -} - -export function Hide() { - window.runtime.Hide(); -} - -export function Show() { - window.runtime.Show(); -} diff --git a/v2/pkg/templates/templates/vanilla/go.mod.tmpl b/v2/pkg/templates/templates/vanilla/go.mod.tmpl deleted file mode 100644 index 4b34d1668..000000000 --- a/v2/pkg/templates/templates/vanilla/go.mod.tmpl +++ /dev/null @@ -1,7 +0,0 @@ -module changeme - -go 1.23.0 - -require github.com/wailsapp/wails/v2 {{.WailsVersion}} - -// replace github.com/wailsapp/wails/v2 {{.WailsVersion}} => {{.WailsDirectory}} \ No newline at end of file diff --git a/v2/pkg/templates/templates/vanilla/main.go.tmpl b/v2/pkg/templates/templates/vanilla/main.go.tmpl deleted file mode 100644 index e24782be3..000000000 --- a/v2/pkg/templates/templates/vanilla/main.go.tmpl +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import ( - "embed" - - "github.com/wailsapp/wails/v2" - "github.com/wailsapp/wails/v2/pkg/options" - "github.com/wailsapp/wails/v2/pkg/options/assetserver" -) - -//go:embed all:frontend/dist -var assets embed.FS - -func main() { - // Create an instance of the app structure - app := NewApp() - - // Create application with options - err := wails.Run(&options.App{ - Title: "{{.ProjectName}}", - Width: 1024, - Height: 768, - AssetServer: &assetserver.Options{ - Assets: assets, - }, - BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, - OnStartup: app.startup, - Bind: []interface{}{ - app, - }, - }) - - if err != nil { - println("Error:", err.Error()) - } -} diff --git a/v2/pkg/templates/templates/vanilla/template.json b/v2/pkg/templates/templates/vanilla/template.json deleted file mode 100644 index 8153663b0..000000000 --- a/v2/pkg/templates/templates/vanilla/template.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "Vanilla + Vite", - "shortname": "vanilla", - "author": "Lea Anthony", - "description": "Vanilla + Vite development server", - "helpurl": "https://wails.io" -} \ No newline at end of file diff --git a/v2/pkg/templates/templates/vanilla/wails.tmpl.json b/v2/pkg/templates/templates/vanilla/wails.tmpl.json deleted file mode 100644 index c39b2cb7d..000000000 --- a/v2/pkg/templates/templates/vanilla/wails.tmpl.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "$schema": "https://wails.io/schemas/config.v2.json", - "name": "{{.ProjectName}}", - "outputfilename": "{{.BinaryName}}", - "frontend:install": "npm install", - "frontend:build": "npm run build", - "frontend:dev:watcher": "npm run dev", - "frontend:dev:serverUrl": "auto", - "author": { - "name": "{{.AuthorName}}", - "email": "{{.AuthorEmail}}" - } -} diff --git a/v2/pkg/templates/templates/vue-ts/.gitignore.tmpl b/v2/pkg/templates/templates/vue-ts/.gitignore.tmpl deleted file mode 100644 index 129d52294..000000000 --- a/v2/pkg/templates/templates/vue-ts/.gitignore.tmpl +++ /dev/null @@ -1,3 +0,0 @@ -build/bin -node_modules -frontend/dist diff --git a/v2/pkg/templates/templates/vue-ts/README.md b/v2/pkg/templates/templates/vue-ts/README.md deleted file mode 100644 index f0eaef091..000000000 --- a/v2/pkg/templates/templates/vue-ts/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# README - -## About - -This is the official Wails Vue-TS template. - -You can configure the project by editing `wails.json`. More information about the project settings can be found -here: https://wails.io/docs/reference/project-config - -## Live Development - -To run in live development mode, run `wails dev` in the project directory. This will run a Vite development -server that will provide very fast hot reload of your frontend changes. If you want to develop in a browser -and have access to your Go methods, there is also a dev server that runs on http://localhost:34115. Connect -to this in your browser, and you can call your Go code from devtools. - -## Building - -To build a redistributable, production mode package, use `wails build`. diff --git a/v2/pkg/templates/templates/vue-ts/app.tmpl.go b/v2/pkg/templates/templates/vue-ts/app.tmpl.go deleted file mode 100644 index af53038a1..000000000 --- a/v2/pkg/templates/templates/vue-ts/app.tmpl.go +++ /dev/null @@ -1,27 +0,0 @@ -package main - -import ( - "context" - "fmt" -) - -// App struct -type App struct { - ctx context.Context -} - -// NewApp creates a new App application struct -func NewApp() *App { - return &App{} -} - -// startup is called when the app starts. The context is saved -// so we can call the runtime methods -func (a *App) startup(ctx context.Context) { - a.ctx = ctx -} - -// Greet returns a greeting for the given name -func (a *App) Greet(name string) string { - return fmt.Sprintf("Hello %s, It's show time!", name) -} diff --git a/v2/pkg/templates/templates/vue-ts/frontend/README.md b/v2/pkg/templates/templates/vue-ts/frontend/README.md deleted file mode 100644 index 98f4a52ae..000000000 --- a/v2/pkg/templates/templates/vue-ts/frontend/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# Vue 3 + TypeScript + Vite - -This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue -3 ` - - - diff --git a/v2/pkg/templates/templates/vue-ts/frontend/package.json b/v2/pkg/templates/templates/vue-ts/frontend/package.json deleted file mode 100644 index e65d0eff4..000000000 --- a/v2/pkg/templates/templates/vue-ts/frontend/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "frontend", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "vue-tsc --noEmit && vite build", - "preview": "vite preview" - }, - "dependencies": { - "vue": "^3.2.37" - }, - "devDependencies": { - "@vitejs/plugin-vue": "^3.0.3", - "typescript": "^4.6.4", - "vite": "^3.0.7", - "vue-tsc": "^1.8.27", - "@babel/types": "^7.18.10" - } -} diff --git a/v2/pkg/templates/templates/vue-ts/frontend/src/App.vue b/v2/pkg/templates/templates/vue-ts/frontend/src/App.vue deleted file mode 100644 index b63d187c5..000000000 --- a/v2/pkg/templates/templates/vue-ts/frontend/src/App.vue +++ /dev/null @@ -1,21 +0,0 @@ - - - - - diff --git a/v2/pkg/templates/templates/vue-ts/frontend/src/assets/fonts/OFL.txt b/v2/pkg/templates/templates/vue-ts/frontend/src/assets/fonts/OFL.txt deleted file mode 100644 index 9cac04ce8..000000000 --- a/v2/pkg/templates/templates/vue-ts/frontend/src/assets/fonts/OFL.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com), - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/v2/pkg/templates/templates/vue-ts/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 b/v2/pkg/templates/templates/vue-ts/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 deleted file mode 100644 index 2f9cc5964..000000000 Binary files a/v2/pkg/templates/templates/vue-ts/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 and /dev/null differ diff --git a/v2/pkg/templates/templates/vue-ts/frontend/src/assets/images/logo-universal.png b/v2/pkg/templates/templates/vue-ts/frontend/src/assets/images/logo-universal.png deleted file mode 100644 index d63303bfa..000000000 Binary files a/v2/pkg/templates/templates/vue-ts/frontend/src/assets/images/logo-universal.png and /dev/null differ diff --git a/v2/pkg/templates/templates/vue-ts/frontend/src/components/HelloWorld.vue b/v2/pkg/templates/templates/vue-ts/frontend/src/components/HelloWorld.vue deleted file mode 100644 index 3ab3df798..000000000 --- a/v2/pkg/templates/templates/vue-ts/frontend/src/components/HelloWorld.vue +++ /dev/null @@ -1,71 +0,0 @@ - - - - - diff --git a/v2/pkg/templates/templates/vue-ts/frontend/src/main.ts b/v2/pkg/templates/templates/vue-ts/frontend/src/main.ts deleted file mode 100644 index f9754fe19..000000000 --- a/v2/pkg/templates/templates/vue-ts/frontend/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import {createApp} from 'vue' -import App from './App.vue' -import './style.css'; - -createApp(App).mount('#app') diff --git a/v2/pkg/templates/templates/vue-ts/frontend/src/style.css b/v2/pkg/templates/templates/vue-ts/frontend/src/style.css deleted file mode 100644 index 3940d6c63..000000000 --- a/v2/pkg/templates/templates/vue-ts/frontend/src/style.css +++ /dev/null @@ -1,26 +0,0 @@ -html { - background-color: rgba(27, 38, 54, 1); - text-align: center; - color: white; -} - -body { - margin: 0; - color: white; - font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", - "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", - sans-serif; -} - -@font-face { - font-family: "Nunito"; - font-style: normal; - font-weight: 400; - src: local(""), - url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2"); -} - -#app { - height: 100vh; - text-align: center; -} diff --git a/v2/pkg/templates/templates/vue-ts/frontend/src/vite-env.d.ts b/v2/pkg/templates/templates/vue-ts/frontend/src/vite-env.d.ts deleted file mode 100644 index dcfaef436..000000000 --- a/v2/pkg/templates/templates/vue-ts/frontend/src/vite-env.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -/// - -declare module '*.vue' { - import type {DefineComponent} from 'vue' - const component: DefineComponent<{}, {}, any> - export default component -} diff --git a/v2/pkg/templates/templates/vue-ts/frontend/tsconfig.json b/v2/pkg/templates/templates/vue-ts/frontend/tsconfig.json deleted file mode 100644 index 3cc844d92..000000000 --- a/v2/pkg/templates/templates/vue-ts/frontend/tsconfig.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "moduleResolution": "Node", - "strict": true, - "jsx": "preserve", - "sourceMap": true, - "resolveJsonModule": true, - "isolatedModules": true, - "esModuleInterop": true, - "lib": [ - "ESNext", - "DOM" - ], - "skipLibCheck": true - }, - "include": [ - "src/**/*.ts", - "src/**/*.d.ts", - "src/**/*.tsx", - "src/**/*.vue" - ], - "references": [ - { - "path": "./tsconfig.node.json" - } - ] -} diff --git a/v2/pkg/templates/templates/vue-ts/frontend/tsconfig.node.json b/v2/pkg/templates/templates/vue-ts/frontend/tsconfig.node.json deleted file mode 100644 index b8afcc8fa..000000000 --- a/v2/pkg/templates/templates/vue-ts/frontend/tsconfig.node.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "module": "ESNext", - "moduleResolution": "Node", - "allowSyntheticDefaultImports": true - }, - "include": [ - "vite.config.ts" - ] -} diff --git a/v2/pkg/templates/templates/vue-ts/frontend/vite.config.ts b/v2/pkg/templates/templates/vue-ts/frontend/vite.config.ts deleted file mode 100644 index a30c338ed..000000000 --- a/v2/pkg/templates/templates/vue-ts/frontend/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import {defineConfig} from 'vite' -import vue from '@vitejs/plugin-vue' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue()] -}) diff --git a/v2/pkg/templates/templates/vue-ts/frontend/wailsjs/go/main/App.d.ts b/v2/pkg/templates/templates/vue-ts/frontend/wailsjs/go/main/App.d.ts deleted file mode 100644 index 43173cfce..000000000 --- a/v2/pkg/templates/templates/vue-ts/frontend/wailsjs/go/main/App.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Greet(arg1: string): Promise; diff --git a/v2/pkg/templates/templates/vue-ts/frontend/wailsjs/go/main/App.js b/v2/pkg/templates/templates/vue-ts/frontend/wailsjs/go/main/App.js deleted file mode 100644 index 0ee085c95..000000000 --- a/v2/pkg/templates/templates/vue-ts/frontend/wailsjs/go/main/App.js +++ /dev/null @@ -1,7 +0,0 @@ -// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Greet(arg1) { - return window['go']['main']['App']['Greet'](arg1); -} diff --git a/v2/pkg/templates/templates/vue-ts/frontend/wailsjs/runtime/package.json b/v2/pkg/templates/templates/vue-ts/frontend/wailsjs/runtime/package.json deleted file mode 100644 index 1e7c8a5d7..000000000 --- a/v2/pkg/templates/templates/vue-ts/frontend/wailsjs/runtime/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "@wailsapp/runtime", - "version": "2.0.0", - "description": "Wails Javascript runtime library", - "main": "runtime.js", - "types": "runtime.d.ts", - "scripts": { - }, - "repository": { - "type": "git", - "url": "git+https://github.com/wailsapp/wails.git" - }, - "keywords": [ - "Wails", - "Javascript", - "Go" - ], - "author": "Lea Anthony ", - "license": "MIT", - "bugs": { - "url": "https://github.com/wailsapp/wails/issues" - }, - "homepage": "https://github.com/wailsapp/wails#readme" -} diff --git a/v2/pkg/templates/templates/vue-ts/frontend/wailsjs/runtime/runtime.d.ts b/v2/pkg/templates/templates/vue-ts/frontend/wailsjs/runtime/runtime.d.ts deleted file mode 100644 index 336fb07aa..000000000 --- a/v2/pkg/templates/templates/vue-ts/frontend/wailsjs/runtime/runtime.d.ts +++ /dev/null @@ -1,211 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export interface Position { - x: number; - y: number; -} - -export interface Size { - w: number; - h: number; -} - -export interface Screen { - isCurrent: boolean; - isPrimary: boolean; - width: number - height: number -} - -// Environment information such as platform, buildtype, ... -export interface EnvironmentInfo { - buildType: string; - platform: string; - arch: string; -} - -// [EventsEmit](https://wails.io/docs/reference/runtime/events#eventsemit) -// emits the given event. Optional data may be passed with the event. -// This will trigger any event listeners. -export function EventsEmit(eventName: string, ...data: any): void; - -// [EventsOn](https://wails.io/docs/reference/runtime/events#eventson) sets up a listener for the given event name. -export function EventsOn(eventName: string, callback: (...data: any) => void): void; - -// [EventsOnMultiple](https://wails.io/docs/reference/runtime/events#eventsonmultiple) -// sets up a listener for the given event name, but will only trigger a given number times. -export function EventsOnMultiple(eventName: string, callback: (...data: any) => void, maxCallbacks: number): void; - -// [EventsOnce](https://wails.io/docs/reference/runtime/events#eventsonce) -// sets up a listener for the given event name, but will only trigger once. -export function EventsOnce(eventName: string, callback: (...data: any) => void): void; - -// [EventsOff](https://wails.io/docs/reference/runtime/events#eventsff) -// unregisters the listener for the given event name. -export function EventsOff(eventName: string): void; - -// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) -// unregisters all event listeners. -export function EventsOffAll(): void; - -// [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) -// logs the given message as a raw message -export function LogPrint(message: string): void; - -// [LogTrace](https://wails.io/docs/reference/runtime/log#logtrace) -// logs the given message at the `trace` log level. -export function LogTrace(message: string): void; - -// [LogDebug](https://wails.io/docs/reference/runtime/log#logdebug) -// logs the given message at the `debug` log level. -export function LogDebug(message: string): void; - -// [LogError](https://wails.io/docs/reference/runtime/log#logerror) -// logs the given message at the `error` log level. -export function LogError(message: string): void; - -// [LogFatal](https://wails.io/docs/reference/runtime/log#logfatal) -// logs the given message at the `fatal` log level. -// The application will quit after calling this method. -export function LogFatal(message: string): void; - -// [LogInfo](https://wails.io/docs/reference/runtime/log#loginfo) -// logs the given message at the `info` log level. -export function LogInfo(message: string): void; - -// [LogWarning](https://wails.io/docs/reference/runtime/log#logwarning) -// logs the given message at the `warning` log level. -export function LogWarning(message: string): void; - -// [WindowReload](https://wails.io/docs/reference/runtime/window#windowreload) -// Forces a reload by the main application as well as connected browsers. -export function WindowReload(): void; - -// [WindowReloadApp](https://wails.io/docs/reference/runtime/window#windowreloadapp) -// Reloads the application frontend. -export function WindowReloadApp(): void; - -// [WindowSetAlwaysOnTop](https://wails.io/docs/reference/runtime/window#windowsetalwaysontop) -// Sets the window AlwaysOnTop or not on top. -export function WindowSetAlwaysOnTop(b: boolean): void; - -// [WindowSetSystemDefaultTheme](https://wails.io/docs/next/reference/runtime/window#windowsetsystemdefaulttheme) -// *Windows only* -// Sets window theme to system default (dark/light). -export function WindowSetSystemDefaultTheme(): void; - -// [WindowSetLightTheme](https://wails.io/docs/next/reference/runtime/window#windowsetlighttheme) -// *Windows only* -// Sets window to light theme. -export function WindowSetLightTheme(): void; - -// [WindowSetDarkTheme](https://wails.io/docs/next/reference/runtime/window#windowsetdarktheme) -// *Windows only* -// Sets window to dark theme. -export function WindowSetDarkTheme(): void; - -// [WindowCenter](https://wails.io/docs/reference/runtime/window#windowcenter) -// Centers the window on the monitor the window is currently on. -export function WindowCenter(): void; - -// [WindowSetTitle](https://wails.io/docs/reference/runtime/window#windowsettitle) -// Sets the text in the window title bar. -export function WindowSetTitle(title: string): void; - -// [WindowFullscreen](https://wails.io/docs/reference/runtime/window#windowfullscreen) -// Makes the window full screen. -export function WindowFullscreen(): void; - -// [WindowUnfullscreen](https://wails.io/docs/reference/runtime/window#windowunfullscreen) -// Restores the previous window dimensions and position prior to full screen. -export function WindowUnfullscreen(): void; - -// [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize) -// Sets the width and height of the window. -export function WindowSetSize(width: number, height: number): void; - -// [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize) -// Gets the width and height of the window. -export function WindowGetSize(): Promise; - -// [WindowSetMaxSize](https://wails.io/docs/reference/runtime/window#windowsetmaxsize) -// Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMaxSize(width: number, height: number): void; - -// [WindowSetMinSize](https://wails.io/docs/reference/runtime/window#windowsetminsize) -// Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMinSize(width: number, height: number): void; - -// [WindowSetPosition](https://wails.io/docs/reference/runtime/window#windowsetposition) -// Sets the window position relative to the monitor the window is currently on. -export function WindowSetPosition(x: number, y: number): void; - -// [WindowGetPosition](https://wails.io/docs/reference/runtime/window#windowgetposition) -// Gets the window position relative to the monitor the window is currently on. -export function WindowGetPosition(): Promise; - -// [WindowHide](https://wails.io/docs/reference/runtime/window#windowhide) -// Hides the window. -export function WindowHide(): void; - -// [WindowShow](https://wails.io/docs/reference/runtime/window#windowshow) -// Shows the window, if it is currently hidden. -export function WindowShow(): void; - -// [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise) -// Maximises the window to fill the screen. -export function WindowMaximise(): void; - -// [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise) -// Toggles between Maximised and UnMaximised. -export function WindowToggleMaximise(): void; - -// [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise) -// Restores the window to the dimensions and position prior to maximising. -export function WindowUnmaximise(): void; - -// [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise) -// Minimises the window. -export function WindowMinimise(): void; - -// [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise) -// Restores the window to the dimensions and position prior to minimising. -export function WindowUnminimise(): void; - -// [WindowSetBackgroundColour](https://wails.io/docs/reference/runtime/window#windowsetbackgroundcolour) -// Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels. -export function WindowSetBackgroundColour(R: number, G: number, B: number, A: number): void; - -// [ScreenGetAll](https://wails.io/docs/reference/runtime/window#screengetall) -// Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system. -export function ScreenGetAll(): Promise; - -// [BrowserOpenURL](https://wails.io/docs/reference/runtime/browser#browseropenurl) -// Opens the given URL in the system browser. -export function BrowserOpenURL(url: string): void; - -// [Environment](https://wails.io/docs/reference/runtime/intro#environment) -// Returns information about the environment -export function Environment(): Promise; - -// [Quit](https://wails.io/docs/reference/runtime/intro#quit) -// Quits the application. -export function Quit(): void; - -// [Hide](https://wails.io/docs/reference/runtime/intro#hide) -// Hides the application. -export function Hide(): void; - -// [Show](https://wails.io/docs/reference/runtime/intro#show) -// Shows the application. -export function Show(): void; diff --git a/v2/pkg/templates/templates/vue-ts/frontend/wailsjs/runtime/runtime.js b/v2/pkg/templates/templates/vue-ts/frontend/wailsjs/runtime/runtime.js deleted file mode 100644 index b5ae16d56..000000000 --- a/v2/pkg/templates/templates/vue-ts/frontend/wailsjs/runtime/runtime.js +++ /dev/null @@ -1,182 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export function LogPrint(message) { - window.runtime.LogPrint(message); -} - -export function LogTrace(message) { - window.runtime.LogTrace(message); -} - -export function LogDebug(message) { - window.runtime.LogDebug(message); -} - -export function LogInfo(message) { - window.runtime.LogInfo(message); -} - -export function LogWarning(message) { - window.runtime.LogWarning(message); -} - -export function LogError(message) { - window.runtime.LogError(message); -} - -export function LogFatal(message) { - window.runtime.LogFatal(message); -} - -export function EventsOnMultiple(eventName, callback, maxCallbacks) { - window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks); -} - -export function EventsOn(eventName, callback) { - EventsOnMultiple(eventName, callback, -1); -} - -export function EventsOff(eventName) { - return window.runtime.EventsOff(eventName); -} - -export function EventsOffAll() { - return window.runtime.EventsOffAll(); -} - -export function EventsOnce(eventName, callback) { - EventsOnMultiple(eventName, callback, 1); -} - -export function EventsEmit(eventName) { - let args = [eventName].slice.call(arguments); - return window.runtime.EventsEmit.apply(null, args); -} - -export function WindowReload() { - window.runtime.WindowReload(); -} - -export function WindowReloadApp() { - window.runtime.WindowReloadApp(); -} - -export function WindowSetAlwaysOnTop(b) { - window.runtime.WindowSetAlwaysOnTop(b); -} - -export function WindowSetSystemDefaultTheme() { - window.runtime.WindowSetSystemDefaultTheme(); -} - -export function WindowSetLightTheme() { - window.runtime.WindowSetLightTheme(); -} - -export function WindowSetDarkTheme() { - window.runtime.WindowSetDarkTheme(); -} - -export function WindowCenter() { - window.runtime.WindowCenter(); -} - -export function WindowSetTitle(title) { - window.runtime.WindowSetTitle(title); -} - -export function WindowFullscreen() { - window.runtime.WindowFullscreen(); -} - -export function WindowUnfullscreen() { - window.runtime.WindowUnfullscreen(); -} - -export function WindowGetSize() { - return window.runtime.WindowGetSize(); -} - -export function WindowSetSize(width, height) { - window.runtime.WindowSetSize(width, height); -} - -export function WindowSetMaxSize(width, height) { - window.runtime.WindowSetMaxSize(width, height); -} - -export function WindowSetMinSize(width, height) { - window.runtime.WindowSetMinSize(width, height); -} - -export function WindowSetPosition(x, y) { - window.runtime.WindowSetPosition(x, y); -} - -export function WindowGetPosition() { - return window.runtime.WindowGetPosition(); -} - -export function WindowHide() { - window.runtime.WindowHide(); -} - -export function WindowShow() { - window.runtime.WindowShow(); -} - -export function WindowMaximise() { - window.runtime.WindowMaximise(); -} - -export function WindowToggleMaximise() { - window.runtime.WindowToggleMaximise(); -} - -export function WindowUnmaximise() { - window.runtime.WindowUnmaximise(); -} - -export function WindowMinimise() { - window.runtime.WindowMinimise(); -} - -export function WindowUnminimise() { - window.runtime.WindowUnminimise(); -} - -export function WindowSetBackgroundColour(R, G, B, A) { - window.runtime.WindowSetBackgroundColour(R, G, B, A); -} - -export function ScreenGetAll() { - return window.runtime.ScreenGetAll(); -} - -export function BrowserOpenURL(url) { - window.runtime.BrowserOpenURL(url); -} - -export function Environment() { - return window.runtime.Environment(); -} - -export function Quit() { - window.runtime.Quit(); -} - -export function Hide() { - window.runtime.Hide(); -} - -export function Show() { - window.runtime.Show(); -} diff --git a/v2/pkg/templates/templates/vue-ts/go.mod.tmpl b/v2/pkg/templates/templates/vue-ts/go.mod.tmpl deleted file mode 100644 index 4b34d1668..000000000 --- a/v2/pkg/templates/templates/vue-ts/go.mod.tmpl +++ /dev/null @@ -1,7 +0,0 @@ -module changeme - -go 1.23.0 - -require github.com/wailsapp/wails/v2 {{.WailsVersion}} - -// replace github.com/wailsapp/wails/v2 {{.WailsVersion}} => {{.WailsDirectory}} \ No newline at end of file diff --git a/v2/pkg/templates/templates/vue-ts/main.go.tmpl b/v2/pkg/templates/templates/vue-ts/main.go.tmpl deleted file mode 100644 index e24782be3..000000000 --- a/v2/pkg/templates/templates/vue-ts/main.go.tmpl +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import ( - "embed" - - "github.com/wailsapp/wails/v2" - "github.com/wailsapp/wails/v2/pkg/options" - "github.com/wailsapp/wails/v2/pkg/options/assetserver" -) - -//go:embed all:frontend/dist -var assets embed.FS - -func main() { - // Create an instance of the app structure - app := NewApp() - - // Create application with options - err := wails.Run(&options.App{ - Title: "{{.ProjectName}}", - Width: 1024, - Height: 768, - AssetServer: &assetserver.Options{ - Assets: assets, - }, - BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, - OnStartup: app.startup, - Bind: []interface{}{ - app, - }, - }) - - if err != nil { - println("Error:", err.Error()) - } -} diff --git a/v2/pkg/templates/templates/vue-ts/template.json b/v2/pkg/templates/templates/vue-ts/template.json deleted file mode 100644 index 6efc20293..000000000 --- a/v2/pkg/templates/templates/vue-ts/template.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "Vue + Vite (Typescript)", - "shortname": "vue-ts", - "author": "Lea Anthony", - "description": "Vue + Vite development server", - "helpurl": "https://wails.io" -} \ No newline at end of file diff --git a/v2/pkg/templates/templates/vue-ts/wails.tmpl.json b/v2/pkg/templates/templates/vue-ts/wails.tmpl.json deleted file mode 100644 index c39b2cb7d..000000000 --- a/v2/pkg/templates/templates/vue-ts/wails.tmpl.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "$schema": "https://wails.io/schemas/config.v2.json", - "name": "{{.ProjectName}}", - "outputfilename": "{{.BinaryName}}", - "frontend:install": "npm install", - "frontend:build": "npm run build", - "frontend:dev:watcher": "npm run dev", - "frontend:dev:serverUrl": "auto", - "author": { - "name": "{{.AuthorName}}", - "email": "{{.AuthorEmail}}" - } -} diff --git a/v2/pkg/templates/templates/vue/.gitignore.tmpl b/v2/pkg/templates/templates/vue/.gitignore.tmpl deleted file mode 100644 index 129d52294..000000000 --- a/v2/pkg/templates/templates/vue/.gitignore.tmpl +++ /dev/null @@ -1,3 +0,0 @@ -build/bin -node_modules -frontend/dist diff --git a/v2/pkg/templates/templates/vue/README.md b/v2/pkg/templates/templates/vue/README.md deleted file mode 100644 index d27aaeecb..000000000 --- a/v2/pkg/templates/templates/vue/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# README - -## About - -This is the official Wails Vue template. - -You can configure the project by editing `wails.json`. More information about the project settings can be found -here: https://wails.io/docs/reference/project-config - -## Live Development - -To run in live development mode, run `wails dev` in the project directory. This will run a Vite development -server that will provide very fast hot reload of your frontend changes. If you want to develop in a browser -and have access to your Go methods, there is also a dev server that runs on http://localhost:34115. Connect -to this in your browser, and you can call your Go code from devtools. - -## Building - -To build a redistributable, production mode package, use `wails build`. diff --git a/v2/pkg/templates/templates/vue/app.tmpl.go b/v2/pkg/templates/templates/vue/app.tmpl.go deleted file mode 100644 index af53038a1..000000000 --- a/v2/pkg/templates/templates/vue/app.tmpl.go +++ /dev/null @@ -1,27 +0,0 @@ -package main - -import ( - "context" - "fmt" -) - -// App struct -type App struct { - ctx context.Context -} - -// NewApp creates a new App application struct -func NewApp() *App { - return &App{} -} - -// startup is called when the app starts. The context is saved -// so we can call the runtime methods -func (a *App) startup(ctx context.Context) { - a.ctx = ctx -} - -// Greet returns a greeting for the given name -func (a *App) Greet(name string) string { - return fmt.Sprintf("Hello %s, It's show time!", name) -} diff --git a/v2/pkg/templates/templates/vue/frontend/README.md b/v2/pkg/templates/templates/vue/frontend/README.md deleted file mode 100644 index b4719bec0..000000000 --- a/v2/pkg/templates/templates/vue/frontend/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Vue 3 + Vite - -This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 ` - - - diff --git a/v2/pkg/templates/templates/vue/frontend/package.json b/v2/pkg/templates/templates/vue/frontend/package.json deleted file mode 100644 index 43da9cbd8..000000000 --- a/v2/pkg/templates/templates/vue/frontend/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "frontend", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "vite build", - "preview": "vite preview" - }, - "dependencies": { - "vue": "^3.2.37" - }, - "devDependencies": { - "@vitejs/plugin-vue": "^3.0.3", - "vite": "^3.0.7" - } -} \ No newline at end of file diff --git a/v2/pkg/templates/templates/vue/frontend/src/App.vue b/v2/pkg/templates/templates/vue/frontend/src/App.vue deleted file mode 100644 index 15d2f1215..000000000 --- a/v2/pkg/templates/templates/vue/frontend/src/App.vue +++ /dev/null @@ -1,21 +0,0 @@ - - - - - diff --git a/v2/pkg/templates/templates/vue/frontend/src/assets/fonts/OFL.txt b/v2/pkg/templates/templates/vue/frontend/src/assets/fonts/OFL.txt deleted file mode 100644 index 9cac04ce8..000000000 --- a/v2/pkg/templates/templates/vue/frontend/src/assets/fonts/OFL.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com), - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/v2/pkg/templates/templates/vue/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 b/v2/pkg/templates/templates/vue/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 deleted file mode 100644 index 2f9cc5964..000000000 Binary files a/v2/pkg/templates/templates/vue/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 and /dev/null differ diff --git a/v2/pkg/templates/templates/vue/frontend/src/assets/images/logo-universal.png b/v2/pkg/templates/templates/vue/frontend/src/assets/images/logo-universal.png deleted file mode 100644 index e9913c1d4..000000000 Binary files a/v2/pkg/templates/templates/vue/frontend/src/assets/images/logo-universal.png and /dev/null differ diff --git a/v2/pkg/templates/templates/vue/frontend/src/components/HelloWorld.vue b/v2/pkg/templates/templates/vue/frontend/src/components/HelloWorld.vue deleted file mode 100644 index 29c023fbe..000000000 --- a/v2/pkg/templates/templates/vue/frontend/src/components/HelloWorld.vue +++ /dev/null @@ -1,71 +0,0 @@ - - - - - diff --git a/v2/pkg/templates/templates/vue/frontend/src/main.js b/v2/pkg/templates/templates/vue/frontend/src/main.js deleted file mode 100644 index f9754fe19..000000000 --- a/v2/pkg/templates/templates/vue/frontend/src/main.js +++ /dev/null @@ -1,5 +0,0 @@ -import {createApp} from 'vue' -import App from './App.vue' -import './style.css'; - -createApp(App).mount('#app') diff --git a/v2/pkg/templates/templates/vue/frontend/src/style.css b/v2/pkg/templates/templates/vue/frontend/src/style.css deleted file mode 100644 index 3940d6c63..000000000 --- a/v2/pkg/templates/templates/vue/frontend/src/style.css +++ /dev/null @@ -1,26 +0,0 @@ -html { - background-color: rgba(27, 38, 54, 1); - text-align: center; - color: white; -} - -body { - margin: 0; - color: white; - font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", - "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", - sans-serif; -} - -@font-face { - font-family: "Nunito"; - font-style: normal; - font-weight: 400; - src: local(""), - url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2"); -} - -#app { - height: 100vh; - text-align: center; -} diff --git a/v2/pkg/templates/templates/vue/frontend/vite.config.js b/v2/pkg/templates/templates/vue/frontend/vite.config.js deleted file mode 100644 index a30c338ed..000000000 --- a/v2/pkg/templates/templates/vue/frontend/vite.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import {defineConfig} from 'vite' -import vue from '@vitejs/plugin-vue' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue()] -}) diff --git a/v2/pkg/templates/templates/vue/frontend/wailsjs/go/main/App.d.ts b/v2/pkg/templates/templates/vue/frontend/wailsjs/go/main/App.d.ts deleted file mode 100644 index 43173cfce..000000000 --- a/v2/pkg/templates/templates/vue/frontend/wailsjs/go/main/App.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Greet(arg1: string): Promise; diff --git a/v2/pkg/templates/templates/vue/frontend/wailsjs/go/main/App.js b/v2/pkg/templates/templates/vue/frontend/wailsjs/go/main/App.js deleted file mode 100644 index 0ee085c95..000000000 --- a/v2/pkg/templates/templates/vue/frontend/wailsjs/go/main/App.js +++ /dev/null @@ -1,7 +0,0 @@ -// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Greet(arg1) { - return window['go']['main']['App']['Greet'](arg1); -} diff --git a/v2/pkg/templates/templates/vue/frontend/wailsjs/runtime/package.json b/v2/pkg/templates/templates/vue/frontend/wailsjs/runtime/package.json deleted file mode 100644 index 1e7c8a5d7..000000000 --- a/v2/pkg/templates/templates/vue/frontend/wailsjs/runtime/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "@wailsapp/runtime", - "version": "2.0.0", - "description": "Wails Javascript runtime library", - "main": "runtime.js", - "types": "runtime.d.ts", - "scripts": { - }, - "repository": { - "type": "git", - "url": "git+https://github.com/wailsapp/wails.git" - }, - "keywords": [ - "Wails", - "Javascript", - "Go" - ], - "author": "Lea Anthony ", - "license": "MIT", - "bugs": { - "url": "https://github.com/wailsapp/wails/issues" - }, - "homepage": "https://github.com/wailsapp/wails#readme" -} diff --git a/v2/pkg/templates/templates/vue/frontend/wailsjs/runtime/runtime.d.ts b/v2/pkg/templates/templates/vue/frontend/wailsjs/runtime/runtime.d.ts deleted file mode 100644 index 336fb07aa..000000000 --- a/v2/pkg/templates/templates/vue/frontend/wailsjs/runtime/runtime.d.ts +++ /dev/null @@ -1,211 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export interface Position { - x: number; - y: number; -} - -export interface Size { - w: number; - h: number; -} - -export interface Screen { - isCurrent: boolean; - isPrimary: boolean; - width: number - height: number -} - -// Environment information such as platform, buildtype, ... -export interface EnvironmentInfo { - buildType: string; - platform: string; - arch: string; -} - -// [EventsEmit](https://wails.io/docs/reference/runtime/events#eventsemit) -// emits the given event. Optional data may be passed with the event. -// This will trigger any event listeners. -export function EventsEmit(eventName: string, ...data: any): void; - -// [EventsOn](https://wails.io/docs/reference/runtime/events#eventson) sets up a listener for the given event name. -export function EventsOn(eventName: string, callback: (...data: any) => void): void; - -// [EventsOnMultiple](https://wails.io/docs/reference/runtime/events#eventsonmultiple) -// sets up a listener for the given event name, but will only trigger a given number times. -export function EventsOnMultiple(eventName: string, callback: (...data: any) => void, maxCallbacks: number): void; - -// [EventsOnce](https://wails.io/docs/reference/runtime/events#eventsonce) -// sets up a listener for the given event name, but will only trigger once. -export function EventsOnce(eventName: string, callback: (...data: any) => void): void; - -// [EventsOff](https://wails.io/docs/reference/runtime/events#eventsff) -// unregisters the listener for the given event name. -export function EventsOff(eventName: string): void; - -// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) -// unregisters all event listeners. -export function EventsOffAll(): void; - -// [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) -// logs the given message as a raw message -export function LogPrint(message: string): void; - -// [LogTrace](https://wails.io/docs/reference/runtime/log#logtrace) -// logs the given message at the `trace` log level. -export function LogTrace(message: string): void; - -// [LogDebug](https://wails.io/docs/reference/runtime/log#logdebug) -// logs the given message at the `debug` log level. -export function LogDebug(message: string): void; - -// [LogError](https://wails.io/docs/reference/runtime/log#logerror) -// logs the given message at the `error` log level. -export function LogError(message: string): void; - -// [LogFatal](https://wails.io/docs/reference/runtime/log#logfatal) -// logs the given message at the `fatal` log level. -// The application will quit after calling this method. -export function LogFatal(message: string): void; - -// [LogInfo](https://wails.io/docs/reference/runtime/log#loginfo) -// logs the given message at the `info` log level. -export function LogInfo(message: string): void; - -// [LogWarning](https://wails.io/docs/reference/runtime/log#logwarning) -// logs the given message at the `warning` log level. -export function LogWarning(message: string): void; - -// [WindowReload](https://wails.io/docs/reference/runtime/window#windowreload) -// Forces a reload by the main application as well as connected browsers. -export function WindowReload(): void; - -// [WindowReloadApp](https://wails.io/docs/reference/runtime/window#windowreloadapp) -// Reloads the application frontend. -export function WindowReloadApp(): void; - -// [WindowSetAlwaysOnTop](https://wails.io/docs/reference/runtime/window#windowsetalwaysontop) -// Sets the window AlwaysOnTop or not on top. -export function WindowSetAlwaysOnTop(b: boolean): void; - -// [WindowSetSystemDefaultTheme](https://wails.io/docs/next/reference/runtime/window#windowsetsystemdefaulttheme) -// *Windows only* -// Sets window theme to system default (dark/light). -export function WindowSetSystemDefaultTheme(): void; - -// [WindowSetLightTheme](https://wails.io/docs/next/reference/runtime/window#windowsetlighttheme) -// *Windows only* -// Sets window to light theme. -export function WindowSetLightTheme(): void; - -// [WindowSetDarkTheme](https://wails.io/docs/next/reference/runtime/window#windowsetdarktheme) -// *Windows only* -// Sets window to dark theme. -export function WindowSetDarkTheme(): void; - -// [WindowCenter](https://wails.io/docs/reference/runtime/window#windowcenter) -// Centers the window on the monitor the window is currently on. -export function WindowCenter(): void; - -// [WindowSetTitle](https://wails.io/docs/reference/runtime/window#windowsettitle) -// Sets the text in the window title bar. -export function WindowSetTitle(title: string): void; - -// [WindowFullscreen](https://wails.io/docs/reference/runtime/window#windowfullscreen) -// Makes the window full screen. -export function WindowFullscreen(): void; - -// [WindowUnfullscreen](https://wails.io/docs/reference/runtime/window#windowunfullscreen) -// Restores the previous window dimensions and position prior to full screen. -export function WindowUnfullscreen(): void; - -// [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize) -// Sets the width and height of the window. -export function WindowSetSize(width: number, height: number): void; - -// [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize) -// Gets the width and height of the window. -export function WindowGetSize(): Promise; - -// [WindowSetMaxSize](https://wails.io/docs/reference/runtime/window#windowsetmaxsize) -// Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMaxSize(width: number, height: number): void; - -// [WindowSetMinSize](https://wails.io/docs/reference/runtime/window#windowsetminsize) -// Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMinSize(width: number, height: number): void; - -// [WindowSetPosition](https://wails.io/docs/reference/runtime/window#windowsetposition) -// Sets the window position relative to the monitor the window is currently on. -export function WindowSetPosition(x: number, y: number): void; - -// [WindowGetPosition](https://wails.io/docs/reference/runtime/window#windowgetposition) -// Gets the window position relative to the monitor the window is currently on. -export function WindowGetPosition(): Promise; - -// [WindowHide](https://wails.io/docs/reference/runtime/window#windowhide) -// Hides the window. -export function WindowHide(): void; - -// [WindowShow](https://wails.io/docs/reference/runtime/window#windowshow) -// Shows the window, if it is currently hidden. -export function WindowShow(): void; - -// [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise) -// Maximises the window to fill the screen. -export function WindowMaximise(): void; - -// [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise) -// Toggles between Maximised and UnMaximised. -export function WindowToggleMaximise(): void; - -// [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise) -// Restores the window to the dimensions and position prior to maximising. -export function WindowUnmaximise(): void; - -// [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise) -// Minimises the window. -export function WindowMinimise(): void; - -// [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise) -// Restores the window to the dimensions and position prior to minimising. -export function WindowUnminimise(): void; - -// [WindowSetBackgroundColour](https://wails.io/docs/reference/runtime/window#windowsetbackgroundcolour) -// Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels. -export function WindowSetBackgroundColour(R: number, G: number, B: number, A: number): void; - -// [ScreenGetAll](https://wails.io/docs/reference/runtime/window#screengetall) -// Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system. -export function ScreenGetAll(): Promise; - -// [BrowserOpenURL](https://wails.io/docs/reference/runtime/browser#browseropenurl) -// Opens the given URL in the system browser. -export function BrowserOpenURL(url: string): void; - -// [Environment](https://wails.io/docs/reference/runtime/intro#environment) -// Returns information about the environment -export function Environment(): Promise; - -// [Quit](https://wails.io/docs/reference/runtime/intro#quit) -// Quits the application. -export function Quit(): void; - -// [Hide](https://wails.io/docs/reference/runtime/intro#hide) -// Hides the application. -export function Hide(): void; - -// [Show](https://wails.io/docs/reference/runtime/intro#show) -// Shows the application. -export function Show(): void; diff --git a/v2/pkg/templates/templates/vue/frontend/wailsjs/runtime/runtime.js b/v2/pkg/templates/templates/vue/frontend/wailsjs/runtime/runtime.js deleted file mode 100644 index b5ae16d56..000000000 --- a/v2/pkg/templates/templates/vue/frontend/wailsjs/runtime/runtime.js +++ /dev/null @@ -1,182 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export function LogPrint(message) { - window.runtime.LogPrint(message); -} - -export function LogTrace(message) { - window.runtime.LogTrace(message); -} - -export function LogDebug(message) { - window.runtime.LogDebug(message); -} - -export function LogInfo(message) { - window.runtime.LogInfo(message); -} - -export function LogWarning(message) { - window.runtime.LogWarning(message); -} - -export function LogError(message) { - window.runtime.LogError(message); -} - -export function LogFatal(message) { - window.runtime.LogFatal(message); -} - -export function EventsOnMultiple(eventName, callback, maxCallbacks) { - window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks); -} - -export function EventsOn(eventName, callback) { - EventsOnMultiple(eventName, callback, -1); -} - -export function EventsOff(eventName) { - return window.runtime.EventsOff(eventName); -} - -export function EventsOffAll() { - return window.runtime.EventsOffAll(); -} - -export function EventsOnce(eventName, callback) { - EventsOnMultiple(eventName, callback, 1); -} - -export function EventsEmit(eventName) { - let args = [eventName].slice.call(arguments); - return window.runtime.EventsEmit.apply(null, args); -} - -export function WindowReload() { - window.runtime.WindowReload(); -} - -export function WindowReloadApp() { - window.runtime.WindowReloadApp(); -} - -export function WindowSetAlwaysOnTop(b) { - window.runtime.WindowSetAlwaysOnTop(b); -} - -export function WindowSetSystemDefaultTheme() { - window.runtime.WindowSetSystemDefaultTheme(); -} - -export function WindowSetLightTheme() { - window.runtime.WindowSetLightTheme(); -} - -export function WindowSetDarkTheme() { - window.runtime.WindowSetDarkTheme(); -} - -export function WindowCenter() { - window.runtime.WindowCenter(); -} - -export function WindowSetTitle(title) { - window.runtime.WindowSetTitle(title); -} - -export function WindowFullscreen() { - window.runtime.WindowFullscreen(); -} - -export function WindowUnfullscreen() { - window.runtime.WindowUnfullscreen(); -} - -export function WindowGetSize() { - return window.runtime.WindowGetSize(); -} - -export function WindowSetSize(width, height) { - window.runtime.WindowSetSize(width, height); -} - -export function WindowSetMaxSize(width, height) { - window.runtime.WindowSetMaxSize(width, height); -} - -export function WindowSetMinSize(width, height) { - window.runtime.WindowSetMinSize(width, height); -} - -export function WindowSetPosition(x, y) { - window.runtime.WindowSetPosition(x, y); -} - -export function WindowGetPosition() { - return window.runtime.WindowGetPosition(); -} - -export function WindowHide() { - window.runtime.WindowHide(); -} - -export function WindowShow() { - window.runtime.WindowShow(); -} - -export function WindowMaximise() { - window.runtime.WindowMaximise(); -} - -export function WindowToggleMaximise() { - window.runtime.WindowToggleMaximise(); -} - -export function WindowUnmaximise() { - window.runtime.WindowUnmaximise(); -} - -export function WindowMinimise() { - window.runtime.WindowMinimise(); -} - -export function WindowUnminimise() { - window.runtime.WindowUnminimise(); -} - -export function WindowSetBackgroundColour(R, G, B, A) { - window.runtime.WindowSetBackgroundColour(R, G, B, A); -} - -export function ScreenGetAll() { - return window.runtime.ScreenGetAll(); -} - -export function BrowserOpenURL(url) { - window.runtime.BrowserOpenURL(url); -} - -export function Environment() { - return window.runtime.Environment(); -} - -export function Quit() { - window.runtime.Quit(); -} - -export function Hide() { - window.runtime.Hide(); -} - -export function Show() { - window.runtime.Show(); -} diff --git a/v2/pkg/templates/templates/vue/go.mod.tmpl b/v2/pkg/templates/templates/vue/go.mod.tmpl deleted file mode 100644 index 4b34d1668..000000000 --- a/v2/pkg/templates/templates/vue/go.mod.tmpl +++ /dev/null @@ -1,7 +0,0 @@ -module changeme - -go 1.23.0 - -require github.com/wailsapp/wails/v2 {{.WailsVersion}} - -// replace github.com/wailsapp/wails/v2 {{.WailsVersion}} => {{.WailsDirectory}} \ No newline at end of file diff --git a/v2/pkg/templates/templates/vue/main.go.tmpl b/v2/pkg/templates/templates/vue/main.go.tmpl deleted file mode 100644 index e24782be3..000000000 --- a/v2/pkg/templates/templates/vue/main.go.tmpl +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import ( - "embed" - - "github.com/wailsapp/wails/v2" - "github.com/wailsapp/wails/v2/pkg/options" - "github.com/wailsapp/wails/v2/pkg/options/assetserver" -) - -//go:embed all:frontend/dist -var assets embed.FS - -func main() { - // Create an instance of the app structure - app := NewApp() - - // Create application with options - err := wails.Run(&options.App{ - Title: "{{.ProjectName}}", - Width: 1024, - Height: 768, - AssetServer: &assetserver.Options{ - Assets: assets, - }, - BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, - OnStartup: app.startup, - Bind: []interface{}{ - app, - }, - }) - - if err != nil { - println("Error:", err.Error()) - } -} diff --git a/v2/pkg/templates/templates/vue/template.json b/v2/pkg/templates/templates/vue/template.json deleted file mode 100644 index c2529e353..000000000 --- a/v2/pkg/templates/templates/vue/template.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "Vue + Vite", - "shortname": "vue", - "author": "Lea Anthony", - "description": "Vue + Vite development server", - "helpurl": "https://wails.io" -} \ No newline at end of file diff --git a/v2/pkg/templates/templates/vue/wails.tmpl.json b/v2/pkg/templates/templates/vue/wails.tmpl.json deleted file mode 100644 index c39b2cb7d..000000000 --- a/v2/pkg/templates/templates/vue/wails.tmpl.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "$schema": "https://wails.io/schemas/config.v2.json", - "name": "{{.ProjectName}}", - "outputfilename": "{{.BinaryName}}", - "frontend:install": "npm install", - "frontend:build": "npm run build", - "frontend:dev:watcher": "npm run dev", - "frontend:dev:serverUrl": "auto", - "author": { - "name": "{{.AuthorName}}", - "email": "{{.AuthorEmail}}" - } -} diff --git a/v2/pkg/templates/templates_test.go b/v2/pkg/templates/templates_test.go deleted file mode 100644 index 658ecadb6..000000000 --- a/v2/pkg/templates/templates_test.go +++ /dev/null @@ -1,99 +0,0 @@ -package templates - -import ( - "os" - "path/filepath" - "runtime" - "testing" - - "github.com/matryer/is" -) - -func TestList(t *testing.T) { - - is2 := is.New(t) - templateList, err := List() - is2.NoErr(err) - - is2.Equal(len(templateList), 13) -} - -func TestShortname(t *testing.T) { - - is2 := is.New(t) - - vanillaTemplate, err := getTemplateByShortname("vanilla") - is2.NoErr(err) - - is2.Equal(vanillaTemplate.Name, "Vanilla + Vite") -} - -func TestInstall(t *testing.T) { - - is2 := is.New(t) - - // Change to the directory of this file - _, filename, _, _ := runtime.Caller(0) - - err := os.Chdir(filepath.Dir(filename)) - is2.NoErr(err) - - options := &Options{ - ProjectName: "test", - TemplateName: "vanilla", - AuthorName: "Lea Anthony", - AuthorEmail: "lea.anthony@gmail.com", - } - - defer func() { - _ = os.RemoveAll(options.ProjectName) - }() - _, _, err = Install(options) - is2.NoErr(err) - -} - -func TestInstallFailsInNonEmptyDirectory(t *testing.T) { - is2 := is.New(t) - - // Create a temp directory with a file in it - tempDir, err := os.MkdirTemp("", "wails-test-nonempty-*") - is2.NoErr(err) - defer func() { - _ = os.RemoveAll(tempDir) - }() - - // Create a file in the directory to make it non-empty - err = os.WriteFile(filepath.Join(tempDir, "existing-file.txt"), []byte("test"), 0644) - is2.NoErr(err) - - options := &Options{ - ProjectName: "test", - TemplateName: "vanilla", - TargetDir: tempDir, - } - - _, _, err = Install(options) - is2.True(err != nil) // Should fail - is2.True(err.Error() == "cannot initialise project in non-empty directory: "+tempDir) -} - -func TestInstallSucceedsInEmptyDirectory(t *testing.T) { - is2 := is.New(t) - - // Create an empty temp directory - tempDir, err := os.MkdirTemp("", "wails-test-empty-*") - is2.NoErr(err) - defer func() { - _ = os.RemoveAll(tempDir) - }() - - options := &Options{ - ProjectName: "test", - TemplateName: "vanilla", - TargetDir: tempDir, - } - - _, _, err = Install(options) - is2.NoErr(err) // Should succeed in empty directory -} diff --git a/v2/tools/release/release.go b/v2/tools/release/release.go deleted file mode 100644 index 4178fcc95..000000000 --- a/v2/tools/release/release.go +++ /dev/null @@ -1,127 +0,0 @@ -package main - -import ( - "encoding/json" - "os" - "os/exec" - "strconv" - "strings" - "time" - - "github.com/samber/lo" - - "github.com/wailsapp/wails/v2/internal/s" -) - -const versionFile = "../../cmd/wails/internal/version.txt" - -func checkError(err error) { - if err != nil { - println(err.Error()) - os.Exit(1) - } -} - -// TODO:This can be replaced with "https://github.com/coreos/go-semver/blob/main/semver/semver.go" -func updateVersion() string { - currentVersionData, err := os.ReadFile(versionFile) - checkError(err) - currentVersion := string(currentVersionData) - vsplit := strings.Split(currentVersion, ".") - minorVersion, err := strconv.Atoi(vsplit[len(vsplit)-1]) - checkError(err) - minorVersion++ - vsplit[len(vsplit)-1] = strconv.Itoa(minorVersion) - newVersion := strings.Join(vsplit, ".") - err = os.WriteFile(versionFile, []byte(newVersion), 0o755) - checkError(err) - return newVersion -} - -func runCommand(name string, arg ...string) { - cmd := exec.Command(name, arg...) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - err := cmd.Run() - checkError(err) -} - -func IsPointRelease(currentVersion string, newVersion string) bool { - // The first n-1 parts of the version should be the same - if currentVersion[:len(currentVersion)-2] != newVersion[:len(newVersion)-2] { - return false - } - // split on the last dot in the string - currentVersionSplit := strings.Split(currentVersion, ".") - newVersionSplit := strings.Split(newVersion, ".") - // compare the - // if the last part of the version is the same, it's a point release - currentMinor := lo.Must(strconv.Atoi(currentVersionSplit[len(currentVersionSplit)-1])) - newMinor := lo.Must(strconv.Atoi(newVersionSplit[len(newVersionSplit)-1])) - return newMinor == currentMinor+1 -} - -func main() { - var newVersion string - var isPointRelease bool - if len(os.Args) > 1 { - newVersion = os.Args[1] - currentVersion, err := os.ReadFile(versionFile) - checkError(err) - err = os.WriteFile(versionFile, []byte(newVersion), 0o755) - checkError(err) - isPointRelease = IsPointRelease(string(currentVersion), newVersion) - } else { - newVersion = updateVersion() - } - - // Update ChangeLog - s.CD("../../../website") - - // Read in `src/pages/changelog.mdx` - changelogData, err := os.ReadFile("src/pages/changelog.mdx") - checkError(err) - changelog := string(changelogData) - // Split on the line that has `## [Unreleased]` - changelogSplit := strings.Split(changelog, "## [Unreleased]") - // Get today's date in YYYY-MM-DD format - today := time.Now().Format("2006-01-02") - // Add the new version to the top of the changelog - newChangelog := changelogSplit[0] + "## [Unreleased]\n\n## " + newVersion + " - " + today + changelogSplit[1] - // Write the changelog back - err = os.WriteFile("src/pages/changelog.mdx", []byte(newChangelog), 0o755) - checkError(err) - - if !isPointRelease { - runCommand("npx", "-y", "pnpm", "install") - - s.ECHO("Generating new Docs for version: " + newVersion) - - runCommand("npx", "pnpm", "run", "docusaurus", "docs:version", newVersion) - - runCommand("npx", "pnpm", "run", "write-translations") - - // Load the version list/* - versionsData, err := os.ReadFile("versions.json") - checkError(err) - var versions []string - err = json.Unmarshal(versionsData, &versions) - checkError(err) - oldestVersion := versions[len(versions)-1] - s.ECHO(oldestVersion) - versions = versions[0 : len(versions)-1] - newVersions, err := json.Marshal(&versions) - checkError(err) - err = os.WriteFile("versions.json", newVersions, 0o755) - checkError(err) - - s.ECHO("Removing old version: " + oldestVersion) - s.CD("versioned_docs") - s.RMDIR("version-" + oldestVersion) - s.CD("../versioned_sidebars") - s.RM("version-" + oldestVersion + "-sidebars.json") - s.CD("..") - - runCommand("npx", "pnpm", "run", "build") - } -} diff --git a/v2/wails.go b/v2/wails.go index 54be64ca2..33d07a561 100644 --- a/v2/wails.go +++ b/v2/wails.go @@ -3,13 +3,23 @@ package wails import ( - _ "github.com/wailsapp/wails/v2/internal/goversion" // Add Compile-Time version check for minimum go version - "github.com/wailsapp/wails/v2/pkg/application" + app "github.com/wailsapp/wails/v2/internal/appng" "github.com/wailsapp/wails/v2/pkg/options" ) // Run creates an application based on the given config and executes it func Run(options *options.App) error { - mainApp := application.NewWithOptions(options) - return mainApp.Run() + + // Call an Init method manually + err := Init() + if err != nil { + return err + } + + mainapp, err := app.CreateApp(options) + if err != nil { + return err + } + + return mainapp.Run() } diff --git a/v3/scripts/validate-changelog.go b/v3/scripts/validate-changelog.go deleted file mode 100644 index 659285a20..000000000 --- a/v3/scripts/validate-changelog.go +++ /dev/null @@ -1,270 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "os" - "path/filepath" - "strings" -) - -func main() { - if len(os.Args) < 3 { - fmt.Println("Usage: go run validate-changelog.go ") - os.Exit(1) - } - - changelogPath := os.Args[1] - addedLinesPath := os.Args[2] - - // Read changelog - content, err := readFile(changelogPath) - if err != nil { - fmt.Printf("ERROR: Failed to read changelog: %v\n", err) - os.Exit(1) - } - - // Read the lines added in this PR - addedContent, err := readFile(addedLinesPath) - if err != nil { - fmt.Printf("ERROR: Failed to read PR added lines: %v\n", err) - os.Exit(1) - } - - addedLines := strings.Split(addedContent, "\n") - fmt.Printf("📝 Lines added in this PR: %d\n", len(addedLines)) - - // Parse changelog to find where added lines ended up - lines := strings.Split(content, "\n") - - // Find problematic entries - only check lines that were ADDED in this PR - var issues []Issue - currentSection := "" - - for lineNum, line := range lines { - // Track current section - if strings.HasPrefix(line, "## ") { - if strings.Contains(line, "[Unreleased]") { - currentSection = "Unreleased" - } else if strings.Contains(line, "v3.0.0-alpha") { - // Extract version from line like "## v3.0.0-alpha.10 - 2025-07-06" - parts := strings.Split(strings.TrimSpace(line[3:]), " - ") - if len(parts) >= 1 { - currentSection = strings.TrimSpace(parts[0]) - } - } - } - - // Check if this line was added in this PR AND is in a released version - if currentSection != "" && currentSection != "Unreleased" && - strings.HasPrefix(strings.TrimSpace(line), "- ") && - wasAddedInThisPR(line, addedLines) { - - issues = append(issues, Issue{ - Line: lineNum, - Content: strings.TrimSpace(line), - Section: currentSection, - Category: getCurrentCategory(lines, lineNum), - }) - fmt.Printf("🚨 MISPLACED: Line added to released version %s: %s\n", currentSection, strings.TrimSpace(line)) - } - } - - if len(issues) == 0 { - fmt.Println("VALIDATION_RESULT=success") - fmt.Println("No misplaced changelog entries found ✅") - return - } - - // Try to fix the issues - fmt.Printf("Found %d potentially misplaced entries:\n", len(issues)) - for _, issue := range issues { - fmt.Printf(" - Line %d in %s: %s\n", issue.Line+1, issue.Section, issue.Content) - } - - // Attempt automatic fix - fixed, err := attemptFix(content, issues, changelogPath) - if err != nil { - fmt.Printf("VALIDATION_RESULT=error\n") - fmt.Printf("ERROR: Failed to fix changelog: %v\n", err) - os.Exit(1) - } - - if fixed { - fmt.Println("VALIDATION_RESULT=fixed") - fmt.Println("✅ Changelog has been automatically fixed") - } else { - fmt.Println("VALIDATION_RESULT=cannot_fix") - fmt.Println("❌ Cannot automatically fix changelog issues") - os.Exit(1) - } -} - -type Issue struct { - Line int - Content string - Section string - Category string -} - -func wasAddedInThisPR(line string, addedLines []string) bool { - trimmedLine := strings.TrimSpace(line) - for _, addedLine := range addedLines { - trimmedAdded := strings.TrimSpace(addedLine) - if trimmedAdded == trimmedLine { - return true - } - if strings.Contains(trimmedAdded, trimmedLine) && len(trimmedAdded) > 0 { - return true - } - } - return false -} - -func getCurrentCategory(lines []string, lineNum int) string { - for i := lineNum - 1; i >= 0; i-- { - line := strings.TrimSpace(lines[i]) - if strings.HasPrefix(line, "### ") { - return strings.TrimSpace(line[4:]) - } - if strings.HasPrefix(line, "## ") && - !strings.Contains(line, "[Unreleased]") && - !strings.Contains(line, "v3.0.0-alpha") { - return strings.TrimSpace(line[3:]) - } - if strings.HasPrefix(line, "## ") && - (strings.Contains(line, "[Unreleased]") || strings.Contains(line, "v3.0.0-alpha")) { - break - } - } - return "Added" -} - -func attemptFix(content string, issues []Issue, outputPath string) (bool, error) { - lines := strings.Split(content, "\n") - - // Find unreleased section - unreleasedStart := -1 - unreleasedEnd := -1 - - for i, line := range lines { - if strings.Contains(line, "[Unreleased]") { - unreleasedStart = i - for j := i + 1; j < len(lines); j++ { - if strings.HasPrefix(lines[j], "## ") && !strings.Contains(lines[j], "[Unreleased]") { - unreleasedEnd = j - break - } - } - break - } - } - - if unreleasedStart == -1 { - return false, fmt.Errorf("Could not find [Unreleased] section") - } - - // Group issues by category - issuesByCategory := make(map[string][]Issue) - for _, issue := range issues { - issuesByCategory[issue.Category] = append(issuesByCategory[issue.Category], issue) - } - - // Remove issues from original locations (in reverse order) - var linesToRemove []int - for _, issue := range issues { - linesToRemove = append(linesToRemove, issue.Line) - } - - // Sort in reverse order - for i := 0; i < len(linesToRemove); i++ { - for j := i + 1; j < len(linesToRemove); j++ { - if linesToRemove[i] < linesToRemove[j] { - linesToRemove[i], linesToRemove[j] = linesToRemove[j], linesToRemove[i] - } - } - } - - // Remove lines - for _, lineNum := range linesToRemove { - lines = append(lines[:lineNum], lines[lineNum+1:]...) - } - - // Add entries to unreleased section - for category, categoryIssues := range issuesByCategory { - categoryFound := false - insertPos := unreleasedStart + 1 - - for i := unreleasedStart + 1; i < unreleasedEnd && i < len(lines); i++ { - if strings.Contains(lines[i], "### "+category) || strings.Contains(lines[i], "## "+category) { - categoryFound = true - for j := i + 1; j < unreleasedEnd && j < len(lines); j++ { - if strings.HasPrefix(lines[j], "### ") || strings.HasPrefix(lines[j], "## ") { - insertPos = j - break - } - if j == len(lines)-1 || j == unreleasedEnd-1 { - insertPos = j + 1 - break - } - } - break - } - } - - if !categoryFound { - if unreleasedEnd > 0 { - insertPos = unreleasedEnd - } else { - insertPos = unreleasedStart + 1 - } - - newLines := []string{ - "", - "### " + category, - "", - } - lines = append(lines[:insertPos], append(newLines, lines[insertPos:]...)...) - insertPos += len(newLines) - unreleasedEnd += len(newLines) - } - - // Add entries to the category - for _, issue := range categoryIssues { - lines = append(lines[:insertPos], append([]string{issue.Content}, lines[insertPos:]...)...) - insertPos++ - unreleasedEnd++ - } - } - - // Write back to file - newContent := strings.Join(lines, "\n") - return true, writeFile(outputPath, newContent) -} - -func readFile(path string) (string, error) { - file, err := os.Open(path) - if err != nil { - return "", err - } - defer file.Close() - - var content strings.Builder - scanner := bufio.NewScanner(file) - for scanner.Scan() { - content.WriteString(scanner.Text()) - content.WriteString("\n") - } - - return content.String(), scanner.Err() -} - -func writeFile(path, content string) error { - dir := filepath.Dir(path) - err := os.MkdirAll(dir, 0755) - if err != nil { - return err - } - - return os.WriteFile(path, []byte(content), 0644) -} \ No newline at end of file diff --git a/website/.gitattributes b/website/.gitattributes deleted file mode 100644 index 65ac44a9e..000000000 --- a/website/.gitattributes +++ /dev/null @@ -1,3 +0,0 @@ -# Mark all files as documentation so it gets excluded from github language statistics -# https://github.com/github-linguist/linguist/blob/master/docs/overrides.md#documentation -** linguist-documentation diff --git a/website/.gitignore b/website/.gitignore index a4774bce0..b2d6de306 100644 --- a/website/.gitignore +++ b/website/.gitignore @@ -6,7 +6,6 @@ # Generated files .docusaurus -.task .cache-loader # Misc diff --git a/website/.nvmrc b/website/.nvmrc deleted file mode 100644 index 741b4916e..000000000 --- a/website/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -18.14.0 \ No newline at end of file diff --git a/website/.prettierignore b/website/.prettierignore deleted file mode 100644 index 124df96de..000000000 --- a/website/.prettierignore +++ /dev/null @@ -1,2 +0,0 @@ -i18n -versioned_docs \ No newline at end of file diff --git a/website/.vscode/extensions.json b/website/.vscode/extensions.json deleted file mode 100644 index 3433c01b0..000000000 --- a/website/.vscode/extensions.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "recommendations": [ - "esbenp.prettier-vscode" - ] -} \ No newline at end of file diff --git a/website/.vscode/settings.json b/website/.vscode/settings.json deleted file mode 100644 index f4441702d..000000000 --- a/website/.vscode/settings.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "[mdx]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "[css]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "[html]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "[javascript]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "[json]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "[markdown]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, -} \ No newline at end of file diff --git a/website/README.md b/website/README.md index 5194c28d2..26cec95bc 100644 --- a/website/README.md +++ b/website/README.md @@ -5,44 +5,17 @@ This website is built using [Docusaurus 2](https://docusaurus.io/), a modern sta ### Installation ``` -$ npm +$ yarn ``` ### Local Development ``` -$ npm run start +$ yarn start ``` -Other languages: - -``` -npm run start -- --locale -``` - -language - The language code configured in the i18n field in the docusaurus.config.js file. - -This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. - -### Translate - -After the English source file is updated, run the following command to submit the source file to Crowdin: - -``` -npm run crowdin push -- -b -``` - -branch - Branch name in crowdin project - -Run the following command to pull the translated files in crowdin to the local: - -``` -npm run crowdin pull -- -b -l -``` - -languageCode - **Note** that this refers to the language code in the crowdin project. - -The recommended practice is to update the English source file locally, then translate the file in crowdin, and finally pull the translated file to the local. +This command starts a local development server and opens up a browser window. Most changes are reflected live without +having to restart the server. ### Build @@ -50,4 +23,14 @@ The recommended practice is to update the English source file locally, then tran $ yarn build ``` -This command generates static content into the `build` directory and can be served using any static contents hosting service. +This command generates static content into the `build` directory and can be served using any static contents hosting +service. + +### Deployment + +``` +$ GIT_USER= USE_SSH=true yarn deploy +``` + +If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to +the `gh-pages` branch. diff --git a/website/Taskfile.yml b/website/Taskfile.yml deleted file mode 100644 index dbb09105d..000000000 --- a/website/Taskfile.yml +++ /dev/null @@ -1,55 +0,0 @@ -# https://taskfile.dev - -version: "3" - -tasks: - install: - desc: Install Dependencies - aliases: [i] - cmds: - - corepack enable - - corepack prepare pnpm@8.3.1 --activate - - pnpm install - sources: - - package.json - - pnpm-lock.yaml - - default: - desc: Start Website - deps: [install] - aliases: [s, start] - cmds: - - npx docusaurus start - - build: - desc: Build Website - deps: [install] - cmds: - - npx docusaurus build - - preview: - desc: Preview Website - deps: [build] - aliases: [serve] - cmds: - - npx docusaurus serve - - crowdin:push: - desc: Upload source files to Crowdin - deps: [install] - cmds: - - npx crowdin push -b v2 - - crowdin:pull: - desc: Download approved translation files from Crowdin to local - deps: [install] - cmds: - - npx crowdin pull -b v2 --export-only-approved - - format:md: - cmds: - - npx prettier --write "**/*.{md,mdx}" - - format: - cmds: - - task: format:md diff --git a/website/babel.config.js b/website/babel.config.js index bfd75dbdf..0adade1fb 100644 --- a/website/babel.config.js +++ b/website/babel.config.js @@ -1,3 +1,3 @@ module.exports = { - presets: [require.resolve("@docusaurus/core/lib/babel/preset")], + presets: [require.resolve('@docusaurus/core/lib/babel/preset')], }; diff --git a/website/blog/2021-09-27-v2-beta1-release-notes.mdx b/website/blog/2021-09-27-v2-beta1-release-notes.mdx index 62466176f..95d5bd951 100644 --- a/website/blog/2021-09-27-v2-beta1-release-notes.mdx +++ b/website/blog/2021-09-27-v2-beta1-release-notes.mdx @@ -5,136 +5,109 @@ authors: [leaanthony] tags: [wails, v2] --- -```mdx-code-block -
- -
-
-``` -When I first announced Wails on Reddit, just over 2 years ago from a train in Sydney, I did not expect it to get much -attention. A few days later, a prolific tech vlogger released a tutorial video, gave it a positive review and from that +
+ +
+
+ + +When I first announced Wails on Reddit, just over 2 years ago from a train in Sydney, I did not expect it to get much +attention. A few days later, a prolific tech vlogger released a tutorial video, gave it a positive review and from that point on, interest in the project has skyrocketed. -It was clear that people were excited about adding web frontends to their Go projects, and almost immediately pushed the +It was clear that people were excited about adding web frontends to their Go projects, and almost immediately pushed the project beyond the proof of concept that I had created. -At the time, Wails used the [webview](https://github.com/webview/webview) project to handle the frontend, and the only -option for Windows was the IE11 renderer. Many bug reports were rooted in this limitation: poor JavaScript/CSS support -and no dev tools to debug it. This was a frustrating development experience but there wasn't much that could have been +At the time, Wails used the [webview](https://github.com/webview/webview) project to handle the frontend, and the only +option for Windows was the IE11 renderer. Many bug reports were rooted in this limitation: poor JavaScript/CSS support +and no dev tools to debug it. This was a frustrating development experience but there wasn't much that could have been done to rectify it. -For a long time, I'd firmly believed that Microsoft would eventually have to sort out their browser situation. -The world was moving on, frontend development was booming and IE wasn't cutting it. -When Microsoft announced the move to using Chromium as the basis for their new browser direction, I knew it was only a +For a long time, I'd firmly believed that Microsoft would eventually have to sort out their browser situation. +The world was moving on, frontend development was booming and IE wasn't cutting it. +When Microsoft announced the move to using Chromium as the basis for their new browser direction, I knew it was only a matter of time until Wails could use it, and move the Windows developer experience to the next level. -Today, I am pleased to announce: **Wails v2 Beta for Windows**! There's a huge amount to unpack in this release, so +Today, I am pleased to announce: **Wails v2 Beta for Windows**! There's a huge amount to unpack in this release, so grab a drink, take a seat and we'll begin... ### No CGO Dependency! -No, I'm not joking: _No_ _CGO_ _dependency_ 🤯! The thing about Windows is that, unlike MacOS and Linux, it doesn't +No, I'm not joking: *No* *CGO* *dependency* 🤯! The thing about Windows is that, unlike MacOS and Linux, it doesn't come with a default compiler. In addition, CGO requires a mingw compiler and there's a ton of different installation -options. Removing the CGO requirement has massively simplified setup, as well as making debugging an awful lot easier. -Whilst I have put a fair bit of effort in getting this working, the majority of the +options. Removing the CGO requirement has massively simplified setup, as well as making debugging an awful lot easier. +Whilst I have put a fair bit of effort in getting this working, the majority of the credit should go to [John Chadwick](https://github.com/jchv) for not only starting a couple of projects to make this -possible, but also being open to someone taking those projects and building on them. Credit also to +possible, but also being open to someone taking those projects and building on them. Credit also to [Tad Vizbaras](https://github.com/tadvi) whose [winc](https://github.com/tadvi/winc) project started me down this path. ### WebView2 Chromium Renderer -```mdx-code-block
- +
-
-``` +
Finally, Windows developers get a first class rendering engine for their applications! Gone are the days of contorting your frontend code to work on Windows. On top of that, you get a first-class developer tools experience! The WebView2 component does, however, have a requirement to have the `WebView2Loader.dll` sitting alongside the binary. -This makes distribution just that little bit more painful than we gophers are used to. All solutions and libraries -(that I know of) that use WebView2 have this dependency. +This makes distribution just that little bit more painful than we gophers are used to. All solutions and libraries +(that I know of) that use WebView2 have this dependency. -However, I'm really excited to announce that Wails applications _have no such requirement_! Thanks to the wizardry of +However, I'm really excited to announce that Wails applications *have no such requirement*! Thanks to the wizardry of [John Chadwick](https://github.com/jchv), we are able to bundle this dll inside the binary and get Windows to load it -as if it were present on disk. +as if it were present on disk. Gophers rejoice! The single binary dream lives on! ### New Features -```mdx-code-block
- +
-
-``` +
There were a lot of requests for native menu support. Wails has finally got you covered. Application menus are now available -and include support for most native menu features. This includes standard menu items, checkboxes, radio groups, submenus +and include support for most native menu features. This includes standard menu items, checkboxes, radio groups, submenus and separators. -There were a huge number of requests in v1 for the ability to have greater control of the window itself. -I'm happy to announce that there's new runtime APIs specifically for this. -It's feature-rich and supports multi-monitor configurations. There is also an improved dialogs API: Now, you can have modern, native +There were a huge number of requests in v1 for the ability to have greater control of the window itself. +I'm happy to announce that there's new runtime APIs specifically for this. +It's feature-rich and supports multi-monitor configurations. There is also an improved dialogs API: Now, you can have modern, native dialogs with rich configuration to cater for all your dialog needs. There is now the option to generate IDE configuration along with your project. This means that if you open your project in a supported IDE, it will already be configured for building and debugging your application. Currently VSCode is supported but we hope to support other IDEs such as Goland soon. -```mdx-code-block
- +
-
-``` +
-### No requirement to bundle assets +### No requirement to bundle assets -A huge pain-point of v1 was the need to condense your entire application down to single JS & CSS files. I'm happy to -announce that for v2, there is no requirement to bundle assets, in any way, shape or form. Want to load a local image? Use an -`` tag with a local src path. Want to use a cool font? Copy it in and add the path to it in your CSS. +A huge pain-point of v1 was the need to condense your entire application down to single JS & CSS files. I'm happy to +announce that for v2, there is no requirement to bundle assets, in any way, shape or form. Want to load a local image? Use an +`` tag with a local src path. Want to use a cool font? Copy it in and add the path to it in your CSS. > Wow, that sounds like a webserver... -Yes, it works just like a webserver, except it isn't. +Yes, it works just like a webserver, except it isn't. > So how do I include my assets? -You just pass a single `embed.FS` that contains all your assets into your application configuration. -They don't even need to be in the top directory - Wails will just work it out for you. +You just pass a single `embed.FS` that contains all your assets into your application configuration. +They don't even need to be in the top directory - Wails will just work it out for you. ### New Development Experience -```mdx-code-block
- +
-
-``` +
+ Now that assets don't need to be bundled, it's enabled a whole new development experience. The new `wails dev` command will build and run your application, but instead of using the assets in the `embed.FS`, it loads them directly @@ -142,71 +115,65 @@ from disk. It also provides the additional features: -- Hot reload - Any changes to frontend assets will trigger and auto reload of the application frontend -- Auto rebuild - Any changes to your Go code will rebuild and relaunch your application + - Hot reload - Any changes to frontend assets will trigger and auto reload of the application frontend + - Auto rebuild - Any changes to your Go code will rebuild and relaunch your application -In addition to this, a webserver will start on port 34115. This will serve your application to any browser that +In addition to this, a webserver will start on port 34115. This will serve your application to any browser that connects to it. All connected web browsers will respond to system events like hot reload on asset change. In Go, we are used to dealing with structs in our applications. It's often useful to send structs to our frontend -and use them as state in our application. In v1, this was a very manual process and a bit of a burden on the -developer. I'm happy to announce that in v2, any application run in dev mode will automatically generate TypeScript +and use them as state in our application. In v1, this was a very manual process and a bit of a burden on the +developer. I'm happy to announce that in v2, any application run in dev mode will automatically generate Typescript models for all structs that are input or output parameters to bound methods. This enables seamless interchange of data models between the two worlds. -In addition to this, another JS module is dynamically generated wrapping all your bound methods. This provides -JSDoc for your methods, providing code completion and hinting in your IDE. It's really cool when you get data models +In addition to this, another JS module is dynamically generated wrapping all your bound methods. This provides +JSDoc for your methods, providing code completion and hinting in your IDE. It's really cool when you get data models auto-imported when hitting tab in an auto-generated module wrapping your Go code! ### Remote Templates -```mdx-code-block
- +
-
-``` +
Getting an application up and running quickly was always a key goal for the Wails project. When we launched, we tried to cover a lot of the modern frameworks at the time: react, vue and angular. The world of frontend development is very -opinionated, fast moving and hard to keep on top of! As a result, we found our base templates getting out of date pretty +opinionated, fast moving and hard to keep on top of! As a result, we found our base templates getting out of date pretty quickly and this caused a maintenance headache. It also meant that we didn't have cool modern templates for the latest and greatest tech stacks. With v2, I wanted to empower the community by giving you the ability to create and host templates yourselves, rather -than rely on the Wails project. So now you can create projects using community supported templates! I hope this will -inspire developers to create a vibrant ecosystem of project templates. I'm really quite excited about what our developer +than rely on the Wails project. So now you can create projects using community supported templates! I hope this will +inspire developers to create a vibrant ecosystem of project templates. I'm really quite excited about what our developer community can create! ### In Conclusion -Wails v2 represents a new foundation for the project. -The aim of this release is to get feedback on the new approach, and to iron out any bugs before a full release. +Wails v2 represents a new foundation for the project. +The aim of this release is to get feedback on the new approach, and to iron out any bugs before a full release. Your input would be most welcome. Please direct any feedback to the [v2 Beta](https://github.com/wailsapp/wails/discussions/828) discussion board. -There were many twists and turns, pivots and u-turns to get to this point. This was due partly to early technical decisions -that needed changing, and partly because some core problems we had spent time building workarounds for were fixed upstream: -Go’s embed feature is a good example. Fortunately, everything came together at the right time, and today we have the -very best solution that we can have. I believe the wait has been worth it - this would not have been possible even 2 +There were many twists and turns, pivots and u-turns to get to this point. This was due partly to early technical decisions +that needed changing, and partly because some core problems we had spent time building workarounds for were fixed upstream: +Go’s embed feature is a good example. Fortunately, everything came together at the right time, and today we have the +very best solution that we can have. I believe the wait has been worth it - this would not have been possible even 2 months ago. I also need to give a huge thank you :pray: to the following people because without them, this release just wouldn't exist: -- [Misite Bao](https://github.com/misitebao) - An absolute workhorse on the Chinese translations and an incredible bug finder. +- [Misitebao](https://github.com/misitebao) - An absolute workhorse on the Chinese translations and an incredible bug finder. - [John Chadwick](https://github.com/jchv) - His amazing work on [go-webview2](https://github.com/jchv/go-webview2) and [go-winloader](https://github.com/jchv/go-winloader) have made the Windows version we have today possible. - [Tad Vizbaras](https://github.com/tadvi) - Experimenting with his [winc](https://github.com/tadvi/winc) project was the first step down the path to a pure Go Wails. - [Mat Ryer](https://github.com/matryer) - His support, encouragement and feedback has really helped drive the project forward. -And finally, I'd like to give a special thank you to all the [project sponsors](/credits#sponsors), including [JetBrains](https://www.jetbrains.com?from=Wails), +And finally, I'd like to give a special thank you to all the [project sponsors](/docs/credits#sponsors), including [JetBrains](https://www.jetbrains.com?from=Wails), whose support drive the project in many ways behind the scenes. -I look forward to seeing what people build with Wails in this next exciting phase of the project! +I look forward to seeing what people build with Wails in this next exciting phase of the project! Lea. diff --git a/website/blog/2021-11-08-v2-beta2-release-notes.mdx b/website/blog/2021-11-08-v2-beta2-release-notes.mdx deleted file mode 100644 index 2f8751c9c..000000000 --- a/website/blog/2021-11-08-v2-beta2-release-notes.mdx +++ /dev/null @@ -1,201 +0,0 @@ ---- -slug: wails-v2-beta-for-mac -title: Wails v2 Beta for MacOS -authors: [leaanthony] -tags: [wails, v2] ---- - -```mdx-code-block -
- -
-
-``` - -Today marks the first beta release of Wails v2 for Mac! It's taken quite a while to get to this point and I'm hoping -that today's release will give you something that's reasonably useful. There have been a number of twists and turns -to get to this point and I'm hoping, with your help, to iron out the crinkles and get the Mac port polished for the -final v2 release. - -You mean this isn't ready for production? For your use case, it may well be ready, but there are still a number of -known issues so keep your eye on [this project board](https://github.com/wailsapp/wails/projects/7) and if you would -like to contribute, you'd be very welcome! - -So what's new for Wails v2 for Mac vs v1? Hint: It's pretty similar to the Windows Beta :wink: - -### New Features - -```mdx-code-block -
- -
-
-``` - -There were a lot of requests for native menu support. Wails has finally got you covered. Application menus are now available -and include support for most native menu features. This includes standard menu items, checkboxes, radio groups, submenus -and separators. - -There were a huge number of requests in v1 for the ability to have greater control of the window itself. -I'm happy to announce that there's new runtime APIs specifically for this. -It's feature-rich and supports multi-monitor configurations. There is also an improved dialogs API: Now, you can have modern, native -dialogs with rich configuration to cater for all your dialog needs. - -### Mac Specific Options - -In addition to the normal application options, Wails v2 for Mac also brings some Mac extras: - -- Make your window all funky and translucent, like all the pretty swift apps! -- Highly customisable titlebar -- We support the NSAppearance options for the application -- Simple config to auto-create an "About" menu - -### No requirement to bundle assets - -A huge pain-point of v1 was the need to condense your entire application down to single JS & CSS files. I'm happy to -announce that for v2, there is no requirement to bundle assets, in any way, shape or form. Want to load a local image? Use an -`` tag with a local src path. Want to use a cool font? Copy it in and add the path to it in your CSS. - -> Wow, that sounds like a webserver... - -Yes, it works just like a webserver, except it isn't. - -> So how do I include my assets? - -You just pass a single `embed.FS` that contains all your assets into your application configuration. -They don't even need to be in the top directory - Wails will just work it out for you. - -### New Development Experience - -Now that assets don't need to be bundled, it's enabled a whole new development experience. The new `wails dev` -command will build and run your application, but instead of using the assets in the `embed.FS`, it loads them directly -from disk. - -It also provides the additional features: - -- Hot reload - Any changes to frontend assets will trigger and auto reload of the application frontend -- Auto rebuild - Any changes to your Go code will rebuild and relaunch your application - -In addition to this, a webserver will start on port 34115. This will serve your application to any browser that -connects to it. All connected web browsers will respond to system events like hot reload on asset change. - -In Go, we are used to dealing with structs in our applications. It's often useful to send structs to our frontend -and use them as state in our application. In v1, this was a very manual process and a bit of a burden on the -developer. I'm happy to announce that in v2, any application run in dev mode will automatically generate TypeScript -models for all structs that are input or output parameters to bound methods. This enables seamless interchange of data -models between the two worlds. - -In addition to this, another JS module is dynamically generated wrapping all your bound methods. This provides -JSDoc for your methods, providing code completion and hinting in your IDE. It's really cool when you get data models -auto-imported when hitting tab in an auto-generated module wrapping your Go code! - -### Remote Templates - -```mdx-code-block -
- -
-
-``` - -Getting an application up and running quickly was always a key goal for the Wails project. When we launched, we tried -to cover a lot of the modern frameworks at the time: react, vue and angular. The world of frontend development is very -opinionated, fast moving and hard to keep on top of! As a result, we found our base templates getting out of date pretty -quickly and this caused a maintenance headache. It also meant that we didn't have cool modern templates for the latest -and greatest tech stacks. - -With v2, I wanted to empower the community by giving you the ability to create and host templates yourselves, rather -than rely on the Wails project. So now you can create projects using community supported templates! I hope this will -inspire developers to create a vibrant ecosystem of project templates. I'm really quite excited about what our developer -community can create! - -### Native M1 Support - -Thanks to the amazing support of [Mat Ryer](https://github.com/matryer/), the Wails project now supports M1 native -builds: - -```mdx-code-block -
- -
-
-``` - -You can also specify `darwin/amd64` as a target too: - -```mdx-code-block -
- -
-
-``` - -Oh, I almost forgot.... you can also do `darwin/universal`.... :wink: - -```mdx-code-block -
- -
-
-``` - -### Cross Compilation to Windows - -Because Wails v2 for Windows is pure Go, you can target Windows builds without docker. - -```mdx-code-block -
- -
-
-``` - -### WKWebView Renderer - -V1 relied on a (now deprecated) WebView component. V2 uses the most recent WKWebKit component so expect the latest and greatest from Apple. - -### In Conclusion - -As I'd said in the Windows release notes, Wails v2 represents a new foundation for the project. -The aim of this release is to get feedback on the new approach, and to iron out any bugs before a full release. -Your input would be most welcome! Please direct any feedback to the [v2 Beta](https://github.com/wailsapp/wails/discussions/828) -discussion board. - -And finally, I'd like to give a special thank you to all the [project sponsors](/credits#sponsors), including [JetBrains](https://www.jetbrains.com?from=Wails), -whose support drive the project in many ways behind the scenes. - -I look forward to seeing what people build with Wails in this next exciting phase of the project! - -Lea. - -PS: Linux users, you're next! - -PPS: If you or your company find Wails useful, please consider [sponsoring the project](https://github.com/sponsors/leaanthony). Thanks! diff --git a/website/blog/2022-02-22-v2-beta3-release-notes.mdx b/website/blog/2022-02-22-v2-beta3-release-notes.mdx deleted file mode 100644 index 1471ec1d1..000000000 --- a/website/blog/2022-02-22-v2-beta3-release-notes.mdx +++ /dev/null @@ -1,142 +0,0 @@ ---- -slug: wails-v2-beta-for-linux -title: Wails v2 Beta for Linux -authors: [leaanthony] -tags: [wails, v2] ---- - -```mdx-code-block -
- -
-
-``` - -I'm pleased to finally announce that Wails v2 is now in beta for Linux! It is somewhat ironic that the very first -experiments with v2 was on Linux and yet it has ended up as the last release. That being said, the v2 we have today -is very different from those first experiments. So without further ado, let's go over the new features: - -### New Features - -```mdx-code-block -
- -
-
-``` - -There were a lot of requests for native menu support. Wails has finally got you covered. Application menus are now available -and include support for most native menu features. This includes standard menu items, checkboxes, radio groups, submenus -and separators. - -There were a huge number of requests in v1 for the ability to have greater control of the window itself. -I'm happy to announce that there's new runtime APIs specifically for this. -It's feature-rich and supports multi-monitor configurations. There is also an improved dialogs API: Now, you can have modern, native -dialogs with rich configuration to cater for all your dialog needs. - -### No requirement to bundle assets - -A huge pain-point of v1 was the need to condense your entire application down to single JS & CSS files. I'm happy to -announce that for v2, there is no requirement to bundle assets, in any way, shape or form. Want to load a local image? Use an -`` tag with a local src path. Want to use a cool font? Copy it in and add the path to it in your CSS. - -> Wow, that sounds like a webserver... - -Yes, it works just like a webserver, except it isn't. - -> So how do I include my assets? - -You just pass a single `embed.FS` that contains all your assets into your application configuration. -They don't even need to be in the top directory - Wails will just work it out for you. - -### New Development Experience - -Now that assets don't need to be bundled, it's enabled a whole new development experience. The new `wails dev` -command will build and run your application, but instead of using the assets in the `embed.FS`, it loads them directly -from disk. - -It also provides the additional features: - -- Hot reload - Any changes to frontend assets will trigger and auto reload of the application frontend -- Auto rebuild - Any changes to your Go code will rebuild and relaunch your application - -In addition to this, a webserver will start on port 34115. This will serve your application to any browser that -connects to it. All connected web browsers will respond to system events like hot reload on asset change. - -In Go, we are used to dealing with structs in our applications. It's often useful to send structs to our frontend -and use them as state in our application. In v1, this was a very manual process and a bit of a burden on the -developer. I'm happy to announce that in v2, any application run in dev mode will automatically generate TypeScript -models for all structs that are input or output parameters to bound methods. This enables seamless interchange of data -models between the two worlds. - -In addition to this, another JS module is dynamically generated wrapping all your bound methods. This provides -JSDoc for your methods, providing code completion and hinting in your IDE. It's really cool when you get data models -auto-imported when hitting tab in an auto-generated module wrapping your Go code! - -### Remote Templates - -```mdx-code-block -
- -
-
-``` - -Getting an application up and running quickly was always a key goal for the Wails project. When we launched, we tried -to cover a lot of the modern frameworks at the time: react, vue and angular. The world of frontend development is very -opinionated, fast moving and hard to keep on top of! As a result, we found our base templates getting out of date pretty -quickly and this caused a maintenance headache. It also meant that we didn't have cool modern templates for the latest -and greatest tech stacks. - -With v2, I wanted to empower the community by giving you the ability to create and host templates yourselves, rather -than rely on the Wails project. So now you can create projects using community supported templates! I hope this will -inspire developers to create a vibrant ecosystem of project templates. I'm really quite excited about what our developer -community can create! - -### Cross Compilation to Windows - -Because Wails v2 for Windows is pure Go, you can target Windows builds without docker. - -```mdx-code-block -
- -
-
-``` - -### In Conclusion - -As I'd said in the Windows release notes, Wails v2 represents a new foundation for the project. -The aim of this release is to get feedback on the new approach, and to iron out any bugs before a full release. -Your input would be most welcome! Please direct any feedback to the [v2 Beta](https://github.com/wailsapp/wails/discussions/828) -discussion board. - -Linux is **hard** to support. We expect there to be a number of quirks with the beta. Please help us to help you by -filing detailed bug reports! - -Finally, I'd like to give a special thank you to all the [project sponsors](/credits#sponsors) whose support -drive the project in many ways behind the scenes. - -I look forward to seeing what people build with Wails in this next exciting phase of the project! - -Lea. - -PS: The v2 release isn't far off now! - -PPS: If you or your company find Wails useful, please consider [sponsoring the project](https://github.com/sponsors/leaanthony). Thanks! diff --git a/website/blog/2022-09-22-v2-release-notes.mdx b/website/blog/2022-09-22-v2-release-notes.mdx deleted file mode 100644 index bcf972450..000000000 --- a/website/blog/2022-09-22-v2-release-notes.mdx +++ /dev/null @@ -1,96 +0,0 @@ ---- -slug: wails-v2-released -title: Wails v2 Released -authors: [leaanthony] -tags: [wails, v2] ---- - -```mdx-code-block -
- -
-
-``` - -# It's here! - -Today marks the release of [Wails](https://wails.io) v2. It's been about 18 months since the first v2 alpha and about a year from the first beta release. I'm truly grateful to everyone involved in the evolution of the project. - -Part of the reason it took that long was due to wanting to get to some definition of completeness before officially calling it v2. The truth is, there's never a perfect time to tag a release - there's always outstanding issues or "just one more" feature to squeeze in. What tagging an imperfect major release does do, however, is to provide a bit of stability for users of the project, as well as a bit of a reset for the developers. - -This release is more than I'd ever expected it to be. I hope it gives you as much pleasure as it has given us to develop it. - -# What _is_ Wails? - -If you are unfamiliar with Wails, it is a project that enables Go programmers to provide rich frontends for their Go programs using familiar web technologies. It's a lightweight, Go alternative to Electron. Much more information can be found on the [official site](https://wails.io/docs/introduction). - -# What's new? - -The v2 release is a huge leap forward for the project, addressing many of the pain points of v1. If you have not read any of the blog posts on the Beta releases for [macOS](/blog/wails-v2-beta-for-mac), [Windows](/blog/wails-v2-beta-for-windows) or [Linux](/blog/wails-v2-beta-for-linux), then I encourage you to do so -as it covers all the major changes in more detail. In summary: - -- Webview2 component for Windows that supports modern web standards and debugging capabilities. -- [Dark / Light theme](/docs/reference/options#theme) + [custom theming](/docs/reference/options#customtheme) on Windows. -- Windows now has no CGO requirements. -- Out-of-the-box support for Svelte, Vue, React, Preact, Lit & Vanilla project templates. -- [Vite](https://vitejs.dev/) integration providing a hot-reload development environment for your application. -- Native application [menus](/docs/guides/application-development#application-menu) and [dialogs](/docs/reference/runtime/dialog). -- Native window translucency effects for [Windows](/docs/reference/options#windowistranslucent) and [macOS](/docs/reference/options#windowistranslucent-1). Support for Mica & Acrylic backdrops. -- Easily generate an [NSIS installer](/docs/guides/windows-installer) for Windows deployments. -- A rich [runtime library](/docs/reference/runtime/intro) providing utility methods for window manipulation, eventing, dialogs, menus and logging. -- Support for [obfuscating](/docs/guides/obfuscated) your application using [garble](https://github.com/burrowers/garble). -- Support for compressing your application using [UPX](https://upx.github.io/). -- Automatic TypeScript generation of Go structs. More info [here](/docs/howdoesitwork#calling-bound-go-methods). -- No extra libraries or DLLs are required to be shipped with your application. For any platform. -- No requirement to bundle frontend assets. Just develop your application like any other web application. - -# Credit & Thanks - -Getting to v2 has been a huge effort. There have been ~2.2K commits by 89 contributors between the initial alpha and the release today, and many, many more that have provided translations, testing, feedback and help on the discussion forums as well as the issue tracker. I'm so unbelievably grateful to each one of you. I'd also like to give an extra special thank you to all the project sponsors who have provided guidance, advice and feedback. Everything you do is hugely appreciated. - -There are a few people I'd like to give special mention to: - -Firstly, a **huge** thank you to [@stffabi](https://github.com/stffabi) who has provided so many contributions which we all benefit from, as well as providing a lot of support on many issues. He has provided some key features such as the external dev server support which transformed our dev mode offering by allowing us to hook into [Vite](https://vitejs.dev/)'s superpowers. It's fair to say that Wails v2 would be a far less exciting release without his [incredible contributions](https://github.com/wailsapp/wails/commits?author=stffabi&since=2020-01-04). Thank you so much @stffabi! - -I'd also like to give a huge shout-out to [@misitebao](https://github.com/misitebao) who has tirelessly been maintaining the website, as well as providing Chinese translations, managing Crowdin and helping new translators get up to speed. This is a hugely important task, and I'm extremely grateful for all the time and effort put into this! You rock! - -Last, but not least, a huge thank you to Mat Ryer who has provided advice and support during the development of v2. Writing xBar together using an early Alpha of v2 was helpful in shaping the direction of v2, as well as give me an understanding of some design flaws in the early releases. I'm happy to announce that as of today, we will start to port xBar to Wails v2, and it will become the flagship application for the project. Cheers Mat! - -# Lessons Learnt - -There are a number of lessons learnt in getting to v2 that will shape development moving forward. - -## Smaller, Quicker, Focused Releases - -In the course of developing v2, there were many features and bug fixes that were developed on an ad-hoc basis. This led to longer release cycles and were harder to debug. Moving forward, we are going to create releases more often that will include a reduced number of features. A release will involve updates to documentation as well as thorough testing. Hopefully, these smaller, quicker, focussed releases will lead to fewer regressions and better quality documentation. - -## Encourage Engagement - -When starting this project, I wanted to immediately help everyone who had a problem. Issues were "personal" and I wanted them resolved as quickly as possible. This is unsustainable and ultimately works against the longevity of the project. Moving forward, I will be giving more space for people to get involved in answering questions and triaging issues. It would be good to get some tooling to help with this so if you have any suggestions, please join in the discussion [here](https://github.com/wailsapp/wails/discussions/1855). - -## Learning to say No - -The more people that engage with an Open Source project, the more requests there will be for additional features that may or may not be useful to the majority of people. These features will take an initial amount of time to develop and debug, and incur an ongoing maintenance cost from that point on. I myself am the most guilty of this, often wanting to "boil the sea" rather than provide the minimum viable feature. Moving forward, we will need to say "No" a bit more to adding core features and focus our energies on a way to empower developers to provide that functionality themselves. We are looking seriously into plugins for this scenario. This will allow anyone to extend the project as they see fit, as well as providing an easy way to contribute towards the project. - -# Looking to the Future - -There are so many core features we are looking at to add to Wails in the next major development cycle already. The [roadmap](https://github.com/wailsapp/wails/discussions/1484) is full of interesting ideas, and I'm keen to start work on them. One of the big asks has been for multiple window support. It's a tricky one and to do it right, and we may need to look at providing an alternative API, as the current one was not designed with this in mind. Based on some preliminary ideas and feedback, I think you'll like where we're looking to go with it. - -I'm personally very excited at the prospect of getting Wails apps running on mobile. We already have a demo project showing that it is possible to run a Wails app on Android, so I'm really keen to explore where we can go with this! - -A final point I'd like to raise is that of feature parity. It has long been a core principle that we wouldn't add anything to the project without there being full cross-platform support for it. Whilst this has proven to be (mainly) achievable so far, it has really held the project back in releasing new features. Moving forward, we will be adopting a slightly different approach: any new feature that cannot be immediately released for all platforms will be released under an experimental configuration or API. This allows early adopters on certain platforms to try the feature and provide feedback that will feed into the final design of the feature. This, of course, means that there are no guarantees of API stability until it is fully supported by all the platforms it can be supported on, but at least it will unblock development. - -# Final Words - -I'm really proud of what we've been able to achieve with the V2 release. It's amazing to see what people have already been able to build using the beta releases so far. Quality applications like [Varly](https://varly.app/), [Surge](https://getsurge.io/) and [October](https://october.utf9k.net/). I encourage you to check them out. - -This release was achieved through the hard work of many contributors. Whilst it is free to download and use, it has not come about through zero cost. Make no mistakes, this project has come at considerable cost. It has not only been my time and the time of each and every contributor, but also the cost of absence from friends and families of each of those people too. That's why I'm extremely grateful for every second that has been dedicated to making this project happen. The more contributors we have, the more this effort can be spread out and the more we can achieve together. I'd like to encourage you all to pick one thing that you can contribute, whether it is confirming someone's bug, suggesting a fix, making a documentation change or helping out someone who needs it. All of these small things have such a huge impact! It would be so awesome if you too were part of the story in getting to v3. - -Enjoy! - -‐ Lea - -PS: If you or your company find Wails useful, please consider [sponsoring the project](https://github.com/sponsors/leaanthony). Thanks! diff --git a/website/blog/2023-01-17-v3-roadmap.mdx b/website/blog/2023-01-17-v3-roadmap.mdx deleted file mode 100644 index adc53e36e..000000000 --- a/website/blog/2023-01-17-v3-roadmap.mdx +++ /dev/null @@ -1,240 +0,0 @@ ---- -slug: the-road-to-wails-v3 -title: The Road to Wails v3 -authors: [leaanthony] -tags: [wails, v3] ---- - -```mdx-code-block -
- -
-
-``` - -# Introduction - -Wails is a project that simplifies the ability to write cross-platform desktop applications using -Go. It uses native webview components for the frontend (not embedded browsers), bringing the power -of the world's most popular UI system to Go, whilst remaining lightweight. - -Version 2 was released on the 22nd of September 2022 and brought with it a lot of enhancements -including: - -- Live development, leveraging the popular Vite project -- Rich functionality for managing windows and creating menus -- Microsoft's WebView2 component -- Generation of Typescript models that mirror your Go structs -- Creating of NSIS Installer -- Obfuscated builds - -Right now, Wails v2 provides powerful tooling for creating rich, cross-platform desktop -applications. - -This blog post aims to look at where the project is at right now and what we can improve -on moving forward. - -# Where are we now? - -It's been incredible to see the popularity of Wails rising since the v2 release. I'm constantly -amazed by the creativity of the community and the wonderful things that are being built with it. -With more popularity, comes more eyes on the project. And with that, more feature requests and -bug reports. - -Over time, I've been able to identify some of the most pressing issues facing the project. -I've also been able to identify some of the things that are holding the project back. - -## Current issues - -I've identified the following areas that I feel are holding the project back: - -- The API -- Bindings generation -- The Build System - -### The API - -The API to build a Wails application currently consists of 2 parts: - -- The Application API -- The Runtime API - -The Application API famously has only 1 function: `Run()` which takes a heap of -options which govern how the application will work. Whilst this is very simple to use, -it is also very limiting. It is a "declarative" approach which hides a lot of the -underlying complexity. For instance, there is no handle to the main window, so you can't -interact with it directly. For that, you need to use the Runtime API. This is a problem -when you start to want to do more complex things like create multiple windows. - -The Runtime API provides a lot of utility functions for the developer. This includes: - -- Window management -- Dialogs -- Menus -- Events -- Logs - -There are a number of things I am not happy with the Runtime API. The first is that it -requires a "context" to be passed around. This is both frustrating and confusing for -new developers who pass in a context and then get a runtime error. - -The biggest issue with the Runtime API is that it was designed for applications that only -use a single window. Over time, the demand for multiple windows has grown and the API is -not well suited to this. - -### Thoughts on the v3 API - -Wouldn't it be great if we could do something like this? - -```go -func main() { - app := wails.NewApplication(options.App{}) - myWindow := app.NewWindow(options.Window{}) - myWindow.SetTitle("My Window") - myWindow.On(events.Window.Close, func() { - app.Quit() - }) - app.Run() -} -``` - -This programmatic approach is far more intuitive and allows the developer to interact -with the application elements directly. All current runtime methods for windows would -simply be methods on the window object. For the other runtime methods, we could move -them to the application object like so: - -```go -app := wails.NewApplication(options.App{}) -app.NewInfoDialog(options.InfoDialog{}) -app.Log.Info("Hello World") -``` - -This is a much more powerful API which will allow for more complex applications to be built. -It also allows for the creation of multiple windows, [the most up-voted feature on GitHub](https://github.com/wailsapp/wails/issues/1480): - -```go -func main() { - app := wails.NewApplication(options.App{}) - myWindow := app.NewWindow(options.Window{}) - myWindow.SetTitle("My Window") - myWindow.On(events.Window.Close, func() { - app.Quit() - }) - myWindow2 := app.NewWindow(options.Window{}) - myWindow2.SetTitle("My Window 2") - myWindow2.On(events.Window.Close, func() { - app.Quit() - }) - app.Run() -} -``` - -### Bindings generation - -One of the key features of Wails is generating bindings for your Go methods so they may be -called from Javascript. The current method for doing this is a bit of a hack. It involves -building the application with a special flag and then running the resultant binary which -uses reflection to determine what has been bound. This leads to a bit of a chicken and egg -situation: You can't build the application without the bindings and you can't generate the -bindings without building the application. There are many ways around this but the best one -would be not to use this approach at all. - -There was a number of attempts at writing a static analyser for Wails projects but they -didn't get very far. In more recent times, it has become slightly easier to do this with -more material available on the subject. - -Compared to reflection, the AST approach is much faster however it is significantly more -complicated. To start with, we may need to impose certain constraints on how to specify -bindings in the code. The goal is to support the most common use cases and then expand -it later on. - -### The Build System - -Like the declarative approach to the API, the build system was created to hide the -complexities of building a desktop application. When you run `wails build`, it does a -lot of things behind the scenes: -- Builds the backend binary for bindings and generates the bindings -- Installs the frontend dependencies -- Builds the frontend assets -- Determines if the application icon is present and if so, embeds it -- Builds the final binary -- If the build is for `darwin/universal` it builds 2 binaries, one for `darwin/amd64` and one for `darwin/arm64` and then creates a fat binary using `lipo` -- If compression is required, it compresses the binary with UPX -- Determines if this binary is to be packaged and if so: - - Ensures the icon and application manifest are compiled into the binary (Windows) - - Builds out the application bundle, generates the icon bundle and copies it, the binary and Info.plist to the application bundle (Mac) -- If an NSIS installer is required, it builds it - -This entire process, whilst very powerful, is also very opaque. It is very difficult to -customise it and it is very difficult to debug. - -To address this in v3, I would like to move to a build system that exists outside of Wails. -After using [Task](https://taskfile.dev/) for a while, I am a big fan of it. It is a great -tool for configuring build systems and should be reasonably familiar to anyone who has used -Makefiles. - -The build system would be configured using a `Taskfile.yml` file which would be generated -by default with any of the supported templates. This would have all of the steps required -to do all the current tasks, such as building or packaging the application, allowing for -easy customisation. - -There will be no external requirement for this tooling as it would form part of the Wails -CLI. This means that you can still use `wails build` and it will do all the things it does -today. However, if you want to customise the build process, you can do so by editing the -`Taskfile.yml` file. It also means you can easily understand the build steps and use your -own build system if you wish. - -The missing piece in the build puzzle is the atomic operations in the build process, such -as icon generation, compression and packaging. To require a bunch of external tooling would -not be a great experience for the developer. To address this, the Wails CLI will provide -all these capabilities as part of the CLI. This means that the builds still work as expected, -with no extra external tooling, however you can replace any step of the build with any tool -you like. - -This will be a much more transparent build system which will allow for easier customisation -and address a lot of the issues that have been raised around it. - -## The Payoff - -These positive changes will be a huge benefit to the project: -- The new API will be much more intuitive and will allow for more complex applications - to be built. -- Using static analysis for bindings generation will be much faster and reduce a lot - of the complexity around the current process. -- Using an established, external build system will make the build process completely - transparent, allowing for powerful customisation. - -Benefits to the project maintainers are: - -- The new API will be much easier to maintain and adapt to new features and platforms. -- The new build system will be much easier to maintain and extend. I hope this will lead to a new ecosystem of community driven build pipelines. -- Better separation of concerns within the project. This will make it easier to add new features and platforms. - -## The Plan - -A lot of the experimentation for this has already been done and it's looking good. -There is no current timeline for this work but I'm hoping by the end of Q1 2023, there -will be an alpha release for Mac to allow the community to test, experiment with and -provide feedback. - -## Summary - -- The v2 API is declarative, hides a lot from the developer and not suitable for features such as multiple windows. A new API will be created which will be simpler, intuitive and more powerful. -- The build system is opaque and difficult to customise so we will move to an external build system which will open it all up. -- The bindings generation is slow and complex so we will move to static analysis which will remove a lot of the complexity the current method has. - -There has been a lot of work put into the guts of v2 and it's solid. -It's now time to address the layer on top of it and make it a much better experience for the developer. - -I hope you are as excited about this as I am. I'm looking forward to hearing your thoughts and feedback. - -Regards, - -‐ Lea - -PS: If you or your company find Wails useful, please consider [sponsoring the project](https://github.com/sponsors/leaanthony). Thanks! - -PPS: Yes, that's a genuine screenshot of a multi-window application built with Wails. It's not a mockup. It's real. It's awesome. It's coming soon. \ No newline at end of file diff --git a/website/blog/2025-03-16-security-incident-response.mdx b/website/blog/2025-03-16-security-incident-response.mdx deleted file mode 100644 index e9903c570..000000000 --- a/website/blog/2025-03-16-security-incident-response.mdx +++ /dev/null @@ -1,89 +0,0 @@ ---- -slug: security-incident-response-march-2025 -title: Proactive Security Response - GitHub Actions Supply Chain Attack -authors: [leaanthony] -tags: [wails, security] ---- - -
- Security Shield -
-
- -:::note TL;DR -**Good news! Wails was NOT affected by this security incident.** Our thorough investigation confirmed that no secrets were leaked, and the Wails codebase and releases remain completely secure. We've already taken proactive measures to further strengthen our security posture. -::: - -## Introduction - -On 15th March 2025 (AEST), the Wails team was alerted to a security incident involving the `tj-actions/changed-files` GitHub Action. This widely-used action (with over 23,000 repositories depending on it) was compromised in a supply chain attack. While this action was used in some of our CI/CD workflows, we're pleased to confirm that Wails remained fully protected throughout. - -This post shares the details of the incident, our response, and the additional safeguards we've implemented to ensure the continued security of the Wails project. - -## Incident Details - -The security company StepSecurity [reported](https://www.stepsecurity.io/blog/harden-runner-detection-tj-actions-changed-files-action-is-compromised) that the `tj-actions/changed-files` GitHub Action was compromised beginning around 9:00 AM March 14th, 2025 Pacific Time (4:00 PM UTC). - -In this attack, malicious code was injected into the action that attempted to dump CI/CD secrets from GitHub Actions runner processes into public logs. The attackers modified the action's code and retroactively updated multiple version tags to reference the malicious commit. - -## Our Proactive Assessment - -Upon learning this, we immediately launched a comprehensive assessment of our systems: - -1. We identified the following Wails workflows that were using the action: - - For Wails v2: `pr-v2.yml` and `upload-source-documents.yml` - - For Wails v3: `pr-v3.yml`, `publish-npm.yml`, and `upload-source-documents.yml` - -2. Our security team conducted a thorough review of all workflow logs for the affected actions during the time period of the compromise. - -3. We're happy to confirm that **no secrets were leaked** in any of our workflow logs, and the Wails codebase remained completely secure. - -## Action Taken - -We took immediate steps to address this situation: - -1. We swiftly replaced all instances of the affected `tj-actions/changed-files` action with the secure alternative `step-security/changed-files` provided by StepSecurity. - -2. As an extra precautionary measure, we temporarily removed all secrets from our GitHub Actions workflows. - -## What This Means for You - -We want to reassure our community that: - -1. The Wails codebase was never compromised in any way. -2. No malicious code was introduced into any Wails releases. -3. This situation only potentially affected our CI/CD pipeline, not the actual Wails source code or releases. -4. No sensitive information or secrets were exposed during this time. - -**In short: All Wails releases remain secure and trustworthy, and no action is required on your part.** - -## Strengthening Our Security Posture - -To minimise exposure to similar potential incidents in the future, we're enhancing our security practices by: - -1. Implementing stricter version pinning for all third-party actions used in our workflows, preferably pinning to specific commit hashes rather than version tags. - -2. Establishing a regular security review process for our CI/CD pipelines and dependencies. - -3. Exploring the use of additional security tools like StepSecurity's Harden-Runner to provide enhanced protection for our GitHub Actions workflows. - -4. Developing a more comprehensive security incident response plan to ensure we can respond quickly and effectively to any future security concerns. - -It's worth noting that the Wails project already employs several security tools as part of our development process: - -- **Semgrep**: We use Semgrep for static code analysis to identify potential security vulnerabilities and code quality issues. -- **Snyk**: We employ Snyk to continuously monitor our dependencies for known vulnerabilities and receive alerts when security patches are needed. - -These existing security measures, combined with our enhanced preventative steps, demonstrate our ongoing commitment to maintaining the security and integrity of the Wails project. - -## Moving Forward - -The security of the Wails project and the trust of our community are our highest priorities. We remain committed to transparency and will continue to promptly address any security concerns that arise. - -We would like to thank StepSecurity for their quick response in identifying this issue and providing a secure alternative action. - -If you have any questions or concerns about this, please don't hesitate to reach out to us on [GitHub](https://github.com/wailsapp/wails) or [Discord](https://discord.gg/JDdSxwjhGf). We're always here to help. diff --git a/website/blog/authors.yml b/website/blog/authors.yml index 6212549b1..8ddd3c599 100644 --- a/website/blog/authors.yml +++ b/website/blog/authors.yml @@ -5,7 +5,7 @@ leaanthony: image_url: https://github.com/leaanthony.png misitebao: - name: Misite Bao - title: Architect + name: Misitebao + title: Front-End Architect url: https://github.com/misitebao - image_url: https://github.com/misitebao.png + image_url: https://cdn.jsdelivr.net/gh/misitebao/CDN@main/gravatar.gif diff --git a/website/bun.lockb b/website/bun.lockb deleted file mode 100644 index 63ed1b159..000000000 Binary files a/website/bun.lockb and /dev/null differ diff --git a/website/crowdin.yml b/website/crowdin.yml deleted file mode 100644 index d04258c22..000000000 --- a/website/crowdin.yml +++ /dev/null @@ -1,21 +0,0 @@ -project_id: "531392" -api_token_env: CROWDIN_PERSONAL_TOKEN -preserve_hierarchy: true -commit_message: "[ci skip]" -files: - - source: /docs/**/* - translation: /i18n/%two_letters_code%/docusaurus-plugin-content-docs/current/**/%original_file_name% - ignore: - - /**/*.json - - source: /blog/**/* - translation: /i18n/%two_letters_code%/docusaurus-plugin-content-blog/**/%original_file_name% - - source: /src/pages/**/* - translation: /i18n/%two_letters_code%/docusaurus-plugin-content-pages/**/%original_file_name% - ignore: - - /**/*.js - - /**/*.jsx - - /**/*.ts - - /**/*.tsx - - /**/*.css - - source: /i18n/en/**/*.json - translation: /i18n/%two_letters_code%/**/%original_file_name% diff --git a/website/docs/about.md b/website/docs/about.md new file mode 100644 index 000000000..856df1046 --- /dev/null +++ b/website/docs/about.md @@ -0,0 +1,70 @@ +--- +sidebar_position: 1 +--- + +# About + +## Overview + +Wails is a project that enables you to write desktop apps using Go and web technologies. + +Consider it a lightweight and fast Electron alternative for Go. You can easily build applications with the flexibility +and power of Go, combined with a rich, modern frontend. + +Wails doesn't hold back with the eye candy either! This is [xbar](https://xbarapp.com) - a desktop application for MacOS +written using Wails. It has menus, supports light and dark desktop themes, and the main window uses translucency that +gives it that 'frosty' effect of a native app. + +

+ +

+ +## Native Elements + +Wails uses a purpose built library for handling native elements such as Window, Menus, Dialogs, etc, so you can build +good-looking, feature rich desktop applications. + +**It does not embed a browser**, so it is resource efficient. Instead, it uses the native rendering engine for the +platform. On Windows, this is the new Microsoft Webview2 library, built on Chromium. + +## Go & Javascript Interoperability + +Wails automatically makes your Go methods available to Javascript, so you can call them by name from your frontend! +It even generates Typescript versions of the structs used by your Go methods, so you can pass the same data structures +between Go and Javascript. + +## Runtime Library + +Wails provides a runtime library, for both Go and Javascript, that handles a lot of the things modern applications need, +like Eventing, Logging, Dialogs, etc. + +## Live Development Experience + +### Automatic Rebuilds + +When you run your application in "dev" mode, Wails will build your application as a native desktop application, but will +read your assets from disk. It will detect any changes to your Go code and automatically rebuild and relaunch your +application. + +### Automatic Reloads + +When changes to your application assets are detected, your running application will "reload", reflecting your changes +almost immediately. + +### Develop your application in a Browser + +If you prefer to debug and develop in a browser then Wails has you covered. The running application also has a webserver +that will run your application in any browser that connects to it. It will even refresh when your assets change on disk. + +## Production-ready Native Binaries + +When you're ready to do the final build of your application, the CLI will compile it down to a single executable, with +all the assets bundled into it. On Windows and MacOS, it is possible to create a native package for distribution. The +assets used in packaging (icon, info.plist, manifest file, etc) are part of your project and may be customised, giving +you total control over how your applications are built. + +## Tooling + +The Wails CLI provides a hassle-free way to generate, build and bundle your applications. It will do the heavy lifting +of creating icons, compiling your application with optimal settings and delivering a distributable, production ready +binary. Choose from a number of starter templates to get up and running quickly! diff --git a/website/docs/appendix/_category_.json b/website/docs/appendix/_category_.json deleted file mode 100644 index 83af4ca28..000000000 --- a/website/docs/appendix/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Appendix", - "position": 70 -} diff --git a/website/docs/community/links.mdx b/website/docs/community/links.mdx index fe8b51dd0..520a428c7 100644 --- a/website/docs/community/links.mdx +++ b/website/docs/community/links.mdx @@ -7,21 +7,13 @@ sidebar_position: 2 This page serves as a list for community related links. Please submit a PR (click `Edit this page` at the bottom) to submit links. -## Awesome Wails - -The [definitive list](https://github.com/wailsapp/awesome-wails) of links related to Wails. - ## Support Channels -- [Wails Discord Server](https://discord.gg/JDdSxwjhGf) -- [Github Issues](https://github.com/wailsapp/wails/issues) -- [v2 Beta Discussion Board](https://github.com/wailsapp/wails/discussions/828) + - [Gophers Slack Channel](https://gophers.slack.com/messages/CJ4P9F7MZ/) + - [Gophers Slack Channel Invite](https://invite.slack.golangbridge.org/) + - [Github Issues](https://github.com/wailsapp/wails/issues) + - [v2 Beta Discussion Board](https://github.com/wailsapp/wails/discussions/828) ## Social Media -- [Twitter](https://twitter.com/wailsapp) -- [Wails Chinese Community QQ Group](https://qm.qq.com/cgi-bin/qm/qr?k=PmIURne5hFGNd7QWzW5qd6FV-INEjNJv&jump_from=webapi) - Group number: 1067173054 - -## Other Tutorials and Articles - -- [Building of Bulletin Board](https://blog.customct.com/building-bulletin-board) + - [Twitter](https://twitter.com/wailsapp) \ No newline at end of file diff --git a/website/docs/community/showcase/bulletinboard.mdx b/website/docs/community/showcase/bulletinboard.mdx deleted file mode 100644 index 37be75135..000000000 --- a/website/docs/community/showcase/bulletinboard.mdx +++ /dev/null @@ -1,10 +0,0 @@ -# BulletinBoard - -```mdx-code-block -

- -
-

-``` - -The [BulletinBoard](https://github.com/raguay/BulletinBoard) application is a versital message board for static messages or dialogs to get information from the user for a script. It has a TUI for creating new dialogs that can latter be used to get information from the user. It's design is to stay running on your system and show the information as needed and then hide away. I have a process for watching a file on my system and sending the contents to BulletinBoard when changed. It works great with my workflows. There is also an [Alfred workflow](https://github.com/raguay/MyAlfred/blob/master/Alfred%205/EmailIt.alfredworkflow) for sending information to the program. The workflow is also for working with [EmailIt](https://github.com/raguay/EmailIt). diff --git a/website/docs/community/showcase/cfntracker.mdx b/website/docs/community/showcase/cfntracker.mdx deleted file mode 100644 index 8fab23b75..000000000 --- a/website/docs/community/showcase/cfntracker.mdx +++ /dev/null @@ -1,39 +0,0 @@ -# CFN Tracker - -```mdx-code-block -

- -
-

-``` - -[CFN Tracker](https://github.com/williamsjokvist/cfn-tracker) - Track any Street -Fighter 6 or V CFN profile's live matches. Check -[the website](https://cfn.williamsjokvist.se/) to get started. - -## Features - -- Real-time match tracking -- Storing match logs and statistics -- Support for displaying live stats to OBS via Browser Source -- Support for both SF6 and SFV -- Ability for users to create their own OBS Browser themes with CSS - -### Major tech used alongside Wails - -- [Task](https://github.com/go-task/task) - wrapping the Wails CLI to make - common commands easy to use -- [React](https://github.com/facebook/react) - chosen for its rich ecosystem - (radix, framer-motion) -- [Bun](https://github.com/oven-sh/bun) - used for its fast dependency - resolution and build-time -- [Rod](https://github.com/go-rod/rod) - headless browser automation for - authentication and polling changes -- [SQLite](https://github.com/mattn/go-sqlite3) - used for storing matches, - sessions and profiles -- [Server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) - - a http stream to send tracking updates to OBS browser sources -- [i18next](https://github.com/i18next/) - with backend connector to serve - localization objects from the Go layer -- [xstate](https://github.com/statelyai/xstate) - state machines for auth - process and tracking diff --git a/website/docs/community/showcase/clustta.mdx b/website/docs/community/showcase/clustta.mdx deleted file mode 100644 index 7da3195df..000000000 --- a/website/docs/community/showcase/clustta.mdx +++ /dev/null @@ -1,27 +0,0 @@ ---- -title: Clustta -description: File manager and project management tool for creative professionals. -slug: /community/showcase/clustta -image: /img/showcase/clustta.png ---- - -
- Clustta screenshot -
- -[Clustta](https://clustta.com) is a file manager and project management tool designed for creative professionals. Built with Wails, it simplifies file management, collaboration, and version control for creative workflows. - -## Features - -- **File Management**: Track all projects and files with easy access even months after completion. -- **Version Control**: Save unlimited revisions with descriptive notes, without duplicating files. -- **Collaboration**: Share files or entire projects securely through simple user tags with fine-grained permissions. -- **Recovery**: Restore corrupted files from saved checkpoints if your software crashes. -- **Templates**: Quick start with preset project and task templates. -- **Kanban Boards**: Visual task tracking to keep tasks organized. -- **Dependencies**: Track and version project resources and dependencies. -- **Checkpoints**: Create memorable milestones and explore alternate creative directions non-destructively. -- **Search & Filters**: Powerful instant search with metadata filtering (task types, tags, status, file extensions). -- **Workspaces**: Save search and filter combinations for easy access to specific task sets. -- **Integrations**: Connect with creative software packages and production management tools like Blender and Kitsu. -- **Self-Hosting**: Host private instances for teams or studios on your own servers. diff --git a/website/docs/community/showcase/emailit.mdx b/website/docs/community/showcase/emailit.mdx deleted file mode 100644 index c1817b70f..000000000 --- a/website/docs/community/showcase/emailit.mdx +++ /dev/null @@ -1,10 +0,0 @@ -# EmailIt - -```mdx-code-block -

- -
-

-``` - -[EmailIt](https://github.com/raguay/EmailIt/) is a Wails 2 program that is a markdown based email sender only with nine notepads, scripts to manipulate the text, and templates. It also has a scripts terminal to run scripts in EmailIt on files in your system. The scripts and templates can be used from the commandline itself or with the Alfred, Keyboard Maestro, Dropzone, or PopClip extensions. It also supports scripts and themes downloaded form GitHub. Documentation is not complete, but the programs works. It’s built using Wails2 and Svelte, and the download is a universal macOS application. diff --git a/website/docs/community/showcase/encrypteasy.mdx b/website/docs/community/showcase/encrypteasy.mdx index 7504950ea..31d7b6ad5 100644 --- a/website/docs/community/showcase/encrypteasy.mdx +++ b/website/docs/community/showcase/encrypteasy.mdx @@ -1,11 +1,9 @@ + # EncryptEasy -```mdx-code-block -

- -
+

+

-``` **[EncryptEasy](https://www.encrypteasy.app) is a simple and easy to use PGP encryption tool, managing all your and your contacts keys. Encryption should be simple. Developed with Wails.** diff --git a/website/docs/community/showcase/espstudio.mdx b/website/docs/community/showcase/espstudio.mdx deleted file mode 100644 index 44db858f9..000000000 --- a/website/docs/community/showcase/espstudio.mdx +++ /dev/null @@ -1,13 +0,0 @@ -# ESP Studio - -```mdx-code-block -

- -
-

-``` - -[ESP Studio](https://github.com/torabian/esp-studio) - Cross platform, Desktop, Cloud, and Embedded software -for controlling ESP/Arduino devices, and building complex IOT workflows and control systems diff --git a/website/docs/community/showcase/filehound.mdx b/website/docs/community/showcase/filehound.mdx index 8c541f482..687be3870 100644 --- a/website/docs/community/showcase/filehound.mdx +++ b/website/docs/community/showcase/filehound.mdx @@ -1,11 +1,10 @@ + # FileHound Export Utility -```mdx-code-block -

- -
+

+

-``` + [FileHound Export Utility](https://www.filehound.co.uk/) FileHound is a cloud document management platform made for secure file retention, business process automation and SmartCapture capabilities. @@ -20,5 +19,5 @@ go-linq 3.2 Frontend with: Vue 2.6.11 Vuex 3.4.0 -TypeScript +Typescript Tailwind 1.9.6 diff --git a/website/docs/community/showcase/gamestacker.mdx b/website/docs/community/showcase/gamestacker.mdx deleted file mode 100644 index 46245e146..000000000 --- a/website/docs/community/showcase/gamestacker.mdx +++ /dev/null @@ -1,19 +0,0 @@ ---- -title: GameStacker -description: A modern, console-like interface that unifies your game libraries. -slug: /community/showcase/gamestacker -image: /img/showcase/gamestacker.webp ---- - -
- GameStacker main dashboard -
- -[GameStacker](https://gamestacker.io) is a modern, elegant console-like interface that unifies your entire game collection into one beautiful dashboard. - -## Features - -- **Unified Library**: Automatically detects and imports games from external libraries (such as Steam, LaunchBox, and RetroBat), bringing your modern and retro collections into a single, cohesive interface. -- **True Console Experience**: Built for controllers with responsive navigation, UI sound effects, and a dedicated in-game "Guide" overlay to control music and manage your session without alt-tabbing. -- **Achievement Integration**: Tracks your progress across supported services, allowing you to view unlocks and Gamerscore directly from the dashboard. -- **Multi-Profile Support**: Create unique profiles with custom avatars and specific color themes for a personalized experience. diff --git a/website/docs/community/showcase/grpcmd-gui.mdx b/website/docs/community/showcase/grpcmd-gui.mdx deleted file mode 100644 index 891350290..000000000 --- a/website/docs/community/showcase/grpcmd-gui.mdx +++ /dev/null @@ -1,10 +0,0 @@ -# grpcmd-gui - -```mdx-code-block -

- -
-

-``` - -[grpcmd-gui](https://grpc.md/gui) is a modern cross-platform desktop app and API client for gRPC development and testing. diff --git a/website/docs/community/showcase/hiposter.mdx b/website/docs/community/showcase/hiposter.mdx deleted file mode 100644 index c0f9052c3..000000000 --- a/website/docs/community/showcase/hiposter.mdx +++ /dev/null @@ -1,10 +0,0 @@ -# hiposter - -```mdx-code-block -

- -
-

-``` - -[hiposter](https://github.com/obity/hiposter) is a simple and efficient http API testing client tool. Based on Wails, Go and sveltejs. \ No newline at end of file diff --git a/website/docs/community/showcase/kafka-king.mdx b/website/docs/community/showcase/kafka-king.mdx deleted file mode 100644 index 0ba78a6ad..000000000 --- a/website/docs/community/showcase/kafka-king.mdx +++ /dev/null @@ -1,22 +0,0 @@ -# Kafka-King - -```mdx-code-block -

- -
-

-``` - -[Kafka-King](https://github.com/Bronya0/Kafka-King) is a kafka GUI client that supports various systems and is compact and easy to use. -This is made of Wails+vue3 - -# Kafka-King function list -- [x] View the cluster node list, support dynamic configuration of broker and topic configuration items -- [x] Supports consumer clients, consumes the specified topic, size, and timeout according to the specified group, and displays the message information in various dimensions in a table -- [x] Supports PLAIN, SSL, SASL, kerberos, sasl_plaintext, etc. etc. -- [x] Create topics (support batches), delete topics, specify replicas, partitions -- [x] Support statistics of the total number of messages, total number of submissions, and backlog for each topic based on consumer groups -- [x] Support viewing topics Detailed information (offset) of the partition, and support adding additional partitions -- [x] Support simulated producers, batch sending messages, specify headers, partitions -- [x] Health check -- [x] Support viewing consumer groups , Consumer- …… diff --git a/website/docs/community/showcase/marasi.mdx b/website/docs/community/showcase/marasi.mdx deleted file mode 100644 index 5ff137523..000000000 --- a/website/docs/community/showcase/marasi.mdx +++ /dev/null @@ -1,22 +0,0 @@ -# Marasi - -```mdx-code-block -

- -
-

-``` - -[Marasi](https://marasi.app/) is an open source application security testing proxy, it lets you intercept, inspect, modify, and extend requests as they flow through your applications. Read more about it on the [blog](https://marasi.app/blog/2025/introducing_marasi/). - -## Features - -- Desktop GUI Interface: Cross-platform desktop application built with Wails -- HTTP/HTTPS Proxy: TLS-capable proxy server with certificate management -- Request/Response Interception: Modify traffic in real-time with an intuitive interface -- Lua Extensions: Scriptable proxy behavior with built-in extensions -- Project Management: SQLite-based storage for all proxy data (requests, responses, metadata) -- Launchpad: Replay and modify HTTP requests -- Scope Management: Filter traffic with inclusion/exclusion rules -- Waypoints: Override hostnames for request routing -- Chrome Integration: Auto-configure Chrome with proxy settings \ No newline at end of file diff --git a/website/docs/community/showcase/mchat.mdx b/website/docs/community/showcase/mchat.mdx deleted file mode 100644 index aa535a6f8..000000000 --- a/website/docs/community/showcase/mchat.mdx +++ /dev/null @@ -1,10 +0,0 @@ -# Mchat - -```mdx-code-block -

- -
-

-``` - -[Official page](https://marcio199226.github.io/mchat-site/public/) Fully anonymous end2end encrypted chat. diff --git a/website/docs/community/showcase/minecraftupdater.mdx b/website/docs/community/showcase/minecraftupdater.mdx deleted file mode 100644 index 2f6c7c72b..000000000 --- a/website/docs/community/showcase/minecraftupdater.mdx +++ /dev/null @@ -1,14 +0,0 @@ -# Minecraft Updater - -```mdx-code-block -

- -
-

-``` - -[Minecraft Updater](https://github.com/Gurkengewuerz/MinecraftModUpdater) is a utility tool to update and synchronize Minecraft mods for your userbase. It’s built using Wails2 and React with [antd](https://ant.design/) as frontend framework. diff --git a/website/docs/community/showcase/minesweeper-xp.mdx b/website/docs/community/showcase/minesweeper-xp.mdx deleted file mode 100644 index f127a005f..000000000 --- a/website/docs/community/showcase/minesweeper-xp.mdx +++ /dev/null @@ -1,10 +0,0 @@ -# Minesweeper XP - -```mdx-code-block -

- -
-

-``` - -[Minesweeper-XP](https://git.new/Minesweeper-XP) allows you to experience the classic Minesweeper XP (+ 98 and 3.1) on macOS, Windows, and Linux! diff --git a/website/docs/community/showcase/modalfilemanager.mdx b/website/docs/community/showcase/modalfilemanager.mdx deleted file mode 100644 index bcd212396..000000000 --- a/website/docs/community/showcase/modalfilemanager.mdx +++ /dev/null @@ -1,14 +0,0 @@ -# Modal File Manager - -```mdx-code-block -

- -
-

-``` - -[Modal File Manager](https://github.com/raguay/ModalFileManager) is a dual pane file manager using web technologies. My original design was based on NW.js and can be found [here](https://github.com/raguay/ModalFileManager-NWjs). This version uses the same Svelte based frontend code (but it has be greatly modified since the departure from NW.js), but the backend is a [Wails 2](https://wails.io/) implementation. By using this implementation, I no longer use command line `rm`, `cp`, etc. commands, but a git install has to be on the system to download themes and extensions. It is fully coded using Go and runs much faster than the previous versions. - -This file manager is designed around the same principle as Vim: a state controlled keyboard actions. The number of states isn't fixed, but very programmable. Therefore, an infinite number of keyboard configurations can be created and used. This is the main difference from other file managers. There are themes and extensions available to download from GitHub. diff --git a/website/docs/community/showcase/mollywallet.mdx b/website/docs/community/showcase/mollywallet.mdx index 5d846d06d..b75238028 100644 --- a/website/docs/community/showcase/mollywallet.mdx +++ b/website/docs/community/showcase/mollywallet.mdx @@ -1,10 +1,9 @@ + # Molley Wallet -```mdx-code-block -

- -
+

+

-``` [Molly Wallet](https://github.com/grvlle/constellation_wallet/) the official $DAG wallet of the Constellation Network. It'll let users interact with the Hypergraph Network in various ways, not limited to producing $DAG transactions. + diff --git a/website/docs/community/showcase/october.mdx b/website/docs/community/showcase/october.mdx deleted file mode 100644 index 66d634dc5..000000000 --- a/website/docs/community/showcase/october.mdx +++ /dev/null @@ -1,14 +0,0 @@ -# October - -```mdx-code-block -

- -
-

-``` - -[October](https://october.utf9k.net) is a small Wails application that makes it really easy to extract highlights from [Kobo eReaders](https://en.wikipedia.org/wiki/Kobo_eReader) and then forward them to [Readwise](https://readwise.io). - -It has a relatively small scope with all platform versions weighing in under 10MB, and that's without enabling [UPX compression](https://upx.github.io/)! - -In contrast, the author's previous attempts with Electron quickly bloated to several hundred megabytes. diff --git a/website/docs/community/showcase/optimus.mdx b/website/docs/community/showcase/optimus.mdx index 4f87479d6..36cbf2fdf 100644 --- a/website/docs/community/showcase/optimus.mdx +++ b/website/docs/community/showcase/optimus.mdx @@ -1,10 +1,9 @@ + # Optimus -```mdx-code-block -

- -
+

+

-``` [Optimus](https://github.com/splode/optimus) is a desktop image optimization application. It supports conversion and compression between WebP, JPEG, and PNG image formats. + diff --git a/website/docs/community/showcase/portfall.mdx b/website/docs/community/showcase/portfall.mdx index 03e740f4c..211009424 100644 --- a/website/docs/community/showcase/portfall.mdx +++ b/website/docs/community/showcase/portfall.mdx @@ -1,10 +1,9 @@ + # Portfall -```mdx-code-block -

- -
+

+

-``` [Portfall](https://github.com/rekon-oss/portfall) - A desktop k8s port-forwarding portal for easy access to all your cluster UIs + diff --git a/website/docs/community/showcase/resizem.mdx b/website/docs/community/showcase/resizem.mdx deleted file mode 100644 index 27f168f48..000000000 --- a/website/docs/community/showcase/resizem.mdx +++ /dev/null @@ -1,10 +0,0 @@ -# Resizem - -```mdx-code-block -

- -
-

-``` - -[Resizem](https://github.com/barats/resizem) - is an app designed for bulk image process. It is particularly useful for users who need to resize, convert, and manage large numbers of image files at once. diff --git a/website/docs/community/showcase/restic-browser.mdx b/website/docs/community/showcase/restic-browser.mdx deleted file mode 100644 index 3646384ec..000000000 --- a/website/docs/community/showcase/restic-browser.mdx +++ /dev/null @@ -1,12 +0,0 @@ -# Restic Browser - -```mdx-code-block -

- -
-

-``` - -[Restic-Browser](https://github.com/emuell/restic-browser) - A simple, cross-platform [restic](https://github.com/restic/restic) backup GUI for browsing and restoring restic repositories. diff --git a/website/docs/community/showcase/riftshare.mdx b/website/docs/community/showcase/riftshare.mdx deleted file mode 100644 index 9928b4785..000000000 --- a/website/docs/community/showcase/riftshare.mdx +++ /dev/null @@ -1,21 +0,0 @@ -# RiftShare - -```mdx-code-block -

- -
-

-``` - -Easy, Secure, and Free file sharing for everyone. Learn more at [Riftshare.app](https://riftshare.app) - -## Features - -- Easy secure file sharing between computers both in the local network and through the internet -- Supports sending files or directories securely through the [magic wormhole protocol](https://magic-wormhole.readthedocs.io/en/latest/) -- Compatible with all other apps using magic wormhole (magic-wormhole or wormhole-william CLI, wormhole-gui, etc.) -- Automatic zipping of multiple selected files to send at once -- Full animations, progress bar, and cancellation support for sending and receiving -- Native OS File Selection -- Open files in one click once received -- Auto Update - don't worry about having the latest release! diff --git a/website/docs/community/showcase/scriptbar.mdx b/website/docs/community/showcase/scriptbar.mdx deleted file mode 100644 index 3e41eb32a..000000000 --- a/website/docs/community/showcase/scriptbar.mdx +++ /dev/null @@ -1,10 +0,0 @@ -# ScriptBar - -```mdx-code-block -

- -
-

-``` - -[ScriptBar](https://GitHub.com/raguay/ScriptBarApp) is a program to show the output of scripts or [Node-Red](https://nodered.org) server. It runs scripts defined in EmailIt program and shows the output. Scripts from xBar or TextBar can be used, but currently on the TextBar scripts work well. It also displays the output of scripts on your system. ScriptBar doesn't put them in the menubar, but has them all in a convient window for easy viewing. You can have multiple tabs to have many different things show. You can also keep the links to your most visited web sites. diff --git a/website/docs/community/showcase/snippetexpander.mdx b/website/docs/community/showcase/snippetexpander.mdx deleted file mode 100644 index 1f9fb6157..000000000 --- a/website/docs/community/showcase/snippetexpander.mdx +++ /dev/null @@ -1,27 +0,0 @@ -# Snippet Expander - -```mdx-code-block -

- -
- Screenshot of Snippet Expander's Select Snippet window -

-

- -
- Screenshot of Snippet Expander's Add Snippet screen -

-

- -
- Screenshot of Snippet Expander's Search & Paste window -

-``` - -[Snippet Expander](https://snippetexpander.org) is "Your little expandable text snippets helper", for Linux. - -Snippet Expander comprises of a GUI application built with Wails for managing snippets and settings, with a Search & Paste window mode for quickly selecting and pasting a snippet. - -The Wails based GUI, go-lang CLI and vala-lang auto expander daemon all communicate with a go-lang daemon via D-Bus. The daemon does the majority of the work, managing the database of snippets and common settings, and providing services for expanding and pasting snippets etc. - -Check out the [source code](https://git.sr.ht/~ianmjones/snippetexpander/tree/trunk/item/cmd/snippetexpandergui/app.go#L38) to see how the Wails app sends messages from the UI to the backend that are then sent to the daemon, and subscribes to a D-Bus event to monitor changes to snippets via another instance of the app or CLI and show them instantly in the UI via a Wails event. diff --git a/website/docs/community/showcase/surge.mdx b/website/docs/community/showcase/surge.mdx index c3b3fb4c0..774e86e70 100644 --- a/website/docs/community/showcase/surge.mdx +++ b/website/docs/community/showcase/surge.mdx @@ -1,10 +1,9 @@ + # Surge -```mdx-code-block -

- -
+

+

-``` -[Surge](https://getsurge.io/) is a p2p filesharing app designed to utilize blockchain technologies to enable 100% anonymous file transfers. Surge is end-to-end encrypted, decentralized and open source. +[Surge](https://surge.rule110.io/) is a p2p filesharing app designed to utilize blockchain technologies to enable 100% anonymous file transfers. Surge is end-to-end encrypted, decentralized and open source. + diff --git a/website/docs/community/showcase/tinyrdm.mdx b/website/docs/community/showcase/tinyrdm.mdx deleted file mode 100644 index e3124bab7..000000000 --- a/website/docs/community/showcase/tinyrdm.mdx +++ /dev/null @@ -1,11 +0,0 @@ -# Tiny RDM - -```mdx-code-block -

- - -
-

-``` - -The [Tiny RDM](https://redis.tinycraft.cc/) application is an open-source, modern lightweight Redis GUI. It has a beautful UI, intuitive Redis database management, and compatible with Windows, Mac, and Linux. It provides visual key-value data operations, supports various data decoding and viewing options, built-in console for executing commands, slow log queries and more. diff --git a/website/docs/community/showcase/upbeat.mdx b/website/docs/community/showcase/upbeat.mdx deleted file mode 100644 index 2f85b6cce..000000000 --- a/website/docs/community/showcase/upbeat.mdx +++ /dev/null @@ -1,18 +0,0 @@ ---- -title: UpBeat -description: An RSS/Atom Feed Reader that filters out negative news with locally run ML models. -slug: /community/showcase/upbeat -image: /img/showcase/upbeat.png ---- - -
- UpBeat screenshot -
- -[UpBeat](https://upbeat.mitchelltechnologies.co.uk) is An RSS/Atom Feed Reader for macOS that filters out negative news with locally running ML models. - -## Features - -- **Local ML**: UpBeat runs a transformer-based sentiment analysis model directly on your Mac's hardware. No waiting for a Cloud GPU to spin up before you can decide what you want to read -- **Apple Neural Engine Enabled**: UpBeat runs its ML models directly on the Neural Engine of Macs. That means you get super-fast inference, but without burning through your battery or electricity bill. -- **Widely Compatible**: Works with the vast majority of RSS + Atom versions. diff --git a/website/docs/community/showcase/wailsterm.mdx b/website/docs/community/showcase/wailsterm.mdx deleted file mode 100644 index 9924dace5..000000000 --- a/website/docs/community/showcase/wailsterm.mdx +++ /dev/null @@ -1,10 +0,0 @@ -# WailsTerm - -```mdx-code-block -

- -
-

-``` - -[WailsTerm](https://github.com/rlshukhov/wailsterm) is a simple translucent terminal app powered by Wails and Xterm.js. diff --git a/website/docs/community/showcase/wally.mdx b/website/docs/community/showcase/wally.mdx index 7408aa585..3e842af40 100644 --- a/website/docs/community/showcase/wally.mdx +++ b/website/docs/community/showcase/wally.mdx @@ -1,10 +1,9 @@ + # Wally -```mdx-code-block -

- -
+

+

-``` [Wally](https://ergodox-ez.com/pages/wally) is the official firmware flasher for [Ergodox](https://ergodox-ez.com/) keyboards. It looks great and is a fantastic example of what you can achieve with Wails: the ability to combine the power of Go and the rich graphical tools of the web development world. + diff --git a/website/docs/community/showcase/warmine.mdx b/website/docs/community/showcase/warmine.mdx deleted file mode 100644 index 46b10b5b1..000000000 --- a/website/docs/community/showcase/warmine.mdx +++ /dev/null @@ -1,19 +0,0 @@ -# Minecraft launcher for WarMine - -```mdx-code-block -

- - -
-

-``` - -[Minecraft launcher for WarMine](https://warmine.ru/) is a Wails application, that allows you to easily join modded game servers and manage your game accounts. - -The Launcher downloads the game files, checks their integrity and launches the game with a wide range of customization options for the launch arguments from the backend. - -Frontend is written in Svelte, whole launcher fits in 9MB and supports Windows 7-11. diff --git a/website/docs/community/showcase/wombat.mdx b/website/docs/community/showcase/wombat.mdx index f100c55e2..8fdbe7cd8 100644 --- a/website/docs/community/showcase/wombat.mdx +++ b/website/docs/community/showcase/wombat.mdx @@ -1,10 +1,10 @@ + # Wombat -```mdx-code-block -

- -
+

+

-``` + [Wombat](https://github.com/rogchap/wombat) is a cross platform gRPC client. + diff --git a/website/docs/community/showcase/ytd.mdx b/website/docs/community/showcase/ytd.mdx deleted file mode 100644 index 5db428f72..000000000 --- a/website/docs/community/showcase/ytd.mdx +++ /dev/null @@ -1,10 +0,0 @@ -# Ytd - -```mdx-code-block -

- -
-

-``` - -[Ytd](https://github.com/marcio199226/ytd/tree/v2-wails) is an app for downloading tracks from youtube, creating offline playlists and share them with your friends, your friends will be able to playback your playlists or download them for offline listening, has an built-in player. diff --git a/website/docs/community/templates.mdx b/website/docs/community/templates.mdx index 3b020b60b..3939c5c2d 100644 --- a/website/docs/community/templates.mdx +++ b/website/docs/community/templates.mdx @@ -5,78 +5,26 @@ sidebar_position: 1 # Templates This page serves as a list for community supported templates. Please submit a PR (click `Edit this page` at the bottom) -to include your templates. To build your own template, please see the [Templates](../guides/templates.mdx) guide. +to include your templates. To build your own template, please see the [Templates](/docs/guides/templates) guide. -To use these templates, run `wails init -n "Your Project Name" -t [the link below[@version]]` - -If there is no version suffix, the main branch code template is used by default. If there is a version suffix, the code template corresponding to the tag of this version is used. +To use these templates, run `wails init -n "Your Project Name" -t [the link below]` Example: `wails init -n "Your Project Name" -t https://github.com/misitebao/wails-template-vue` :::warning Attention -**The Wails project does not maintain, is not responsible nor liable for 3rd party templates!** + **The Wails project does not maintain, is not responsible nor liable for 3rd party templates!** -If you are unsure about a template, inspect `package.json` and `wails.json` for what scripts are run and what packages are installed. + If you are unsure about a template, inspect `package.json` and `wails.json` for what scripts are run and what packages are installed. ::: ## Vue -- [wails-template-vue](https://github.com/misitebao/wails-template-vue) - Wails template based on Vue ecology (Integrated TypeScript, Dark theme, Internationalization, Single page routing, TailwindCSS) -- [wails-template-quasar-js](https://github.com/sgosiaco/wails-template-quasar-js) - A template using JavaScript + Quasar V2 (Vue 3, Vite, Sass, Pinia, ESLint, Prettier) -- [wails-template-quasar-ts](https://github.com/sgosiaco/wails-template-quasar-ts) - A template using TypeScript + Quasar V2 (Vue 3, Vite, Sass, Pinia, ESLint, Prettier, Composition API with <script setup>) -- [wails-template-naive](https://github.com/tk103331/wails-template-naive) - Wails template based on Naive UI (A Vue 3 Component Library) -- [wails-template-primevue-sakai](https://github.com/TekWizely/wails-template-primevue-sakai) - Wails starter using [PrimeVue's Sakai Application Template](https://sakai.primevue.org) (Vite, Vue, PrimeVue, TailwindCSS, Vue Router, Themes, Dark Mode, UI Components, and more) -- [wails-template-tdesign-js](https://github.com/tongque0/wails-template-tdesign-js) - Wails template based on TDesign UI (a Vue 3 UI library by Tencent), using Vite, Pinia, Vue Router, ESLint, and Prettier. +- [wails-template-vue](https://github.com/misitebao/wails-template-vue) - A template using vue and vue-router +- [wails-vite-vue-ts](https://github.com/codydbentley/wails-vite-vue-ts) - Vue 3 TypeScript with Vite (and instructions to add features) +- [wails-vite-vue-the-works](https://github.com/codydbentley/wails-vite-vue-the-works) - Vue 3 TypeScript with Vite, Vuex, Vue Router, Sass, and ESLint + Prettier ## Angular -- [wails-template-angular](https://github.com/mateothegreat/wails-template-angular) - Angular 15+ action packed & ready to roll to production. - [wails-angular-template](https://github.com/TAINCER/wails-angular-template) - Angular with TypeScript, Sass, Hot-Reload, Code-Splitting and i18n - -## React - -- [wails-react-template](https://github.com/AlienRecall/wails-react-template) - A template using reactjs -- [wails-react-template](https://github.com/flin7/wails-react-template) - A minimal template for React that supports live development -- [wails-template-nextjs](https://github.com/LGiki/wails-template-nextjs) - A template using Next.js and TypeScript -- [wails-template-nextjs-app-router](https://github.com/thisisvk-in/wails-template-nextjs-app-router) - A template using Next.js and TypeScript with App router -- [wails-vite-react-ts-tailwind-template](https://github.com/hotafrika/wails-vite-react-ts-tailwind-template) - A template for React + TypeScript + Vite + TailwindCSS -- [Wails-vite-ts-tailwindcss-shadcn-template-2025](https://github.com/darkb0ts/Wails-vite-ts-tailwindcss-shadcn-template-2025) - A template for React + TypeScript + Vite -- [wails-vite-react-ts-tailwind-shadcnui-template](https://github.com/Mahcks/wails-vite-react-tailwind-shadcnui-ts) - A template with Vite, React, TypeScript, TailwindCSS, and shadcn/ui -- [wails-nextjs-tailwind-template](https://github.com/kairo913/wails-nextjs-tailwind-template) - A template using Next.js and Typescript with TailwindCSS - -## Svelte - -- [wails-svelte-template](https://github.com/raitonoberu/wails-svelte-template) - A template using Svelte -- [wails-vite-svelte-template](https://github.com/BillBuilt/wails-vite-svelte-template) - A template using Svelte and Vite -- [wails-vite-svelte-ts-tailwind-template](https://github.com/xvertile/wails-vite-svelte-tailwind-template) - A template using Wails, Svelte, Vite, TypeScript, and TailwindCSS v3 -- [wails-vite-svelte-tailwind-template](https://github.com/BillBuilt/wails-vite-svelte-tailwind-template) - A template using Svelte and Vite with TailwindCSS v3 -- [wails-svelte-tailwind-vite-template](https://github.com/PylotLight/wails-vite-svelte-tailwind-template/tree/master) - An updated template using Svelte v4.2.0 and Vite with TailwindCSS v3.3.3 -- [wails-sveltekit-template](https://github.com/h8gi/wails-sveltekit-template) - A template using SvelteKit -- [wails-template-sveltekit-less-prettier-eslint](https://github.com/Alex6357/wails-template-sveltekit-less-prettier-eslint) - A template using SvelteKit with less, Prettier and ESlint -- [wails-template-svelte-ts-less-prettier-eslint-vite](https://github.com/Alex6357/wails-template-svelte-ts-less-prettier-eslint-vite) - A template using Svelte5 + TypeScript + less + Prettier + ESlint + Vite - -## Solid - -- [wails-template-vite-solid-ts](https://github.com/xijaja/wails-template-solid-ts) - A template using Solid + Ts + Vite -- [wails-template-vite-solid-js](https://github.com/xijaja/wails-template-solid-js) - A template using Solid + Js + Vite - -## Elm - -- [wails-elm-template](https://github.com/benjamin-thomas/wails-elm-template) - Develop your GUI app with functional programming and a **snappy** hot-reload setup :tada: :rocket: -- [wails-template-elm-tailwind](https://github.com/rnice01/wails-template-elm-tailwind) - Combine the powers :muscle: of Elm + Tailwind CSS + Wails! Hot reloading supported. - -## HTMX - -- [wails-htmx-tailwind-daisyui-template](https://github.com/ltcovalt/wails-htmx-tailwind-daisyui-template) - HTMX template using Tailwind CSS + daisyUI for styling and the Go standard library for routing and HTML templating -- [wails-htmx-templ-chi-tailwind](https://github.com/PylotLight/wails-hmtx-templ-template) - Use a unique combination of pure htmx for interactivity plus templ for creating components and forms - -## Pure JavaScript (Vanilla) - -- [wails-pure-js-template](https://github.com/KiddoV/wails-pure-js-template) - A template with nothing but just basic JavaScript, HTML, and CSS - - -## Lit (web components) - -- [wails-lit-shoelace-esbuild-template](https://github.com/Braincompiler/wails-lit-shoelace-esbuild-template) - Wails template providing frontend with lit, Shoelace component library + pre-configured prettier and typescript. diff --git a/website/docs/credits.mdx b/website/docs/credits.mdx new file mode 100644 index 000000000..896cdceac --- /dev/null +++ b/website/docs/credits.mdx @@ -0,0 +1,104 @@ +--- +sidebar_position: 99 +--- + +# Credits + +- [Lea Anthony](https://github.com/leaanthony) - Project owner, lead developer +- [Misitebao](https://github.com/misitebao) - Chinese documentation, Windows testing, Bug finder general +- [Travis McLane](https://github.com/tmclane) - Cross-compilation work, MacOS testing +- [Byron Chris](https://github.com/bh90210) - Linux distro wizard, Linux testing + +## Sponsors + +
+ + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +`, + }} +/> + +## Contributors + +import Contributors from "react-contributors"; + + + +## Special Mentions + +- [John Chadwick](https://github.com/jchv) - His amazing work on [go-webview2](https://github.com/jchv/go-webview2) and + [go-winloader](https://github.com/jchv/go-winloader) have made the Windows version possible. +- [Tad Vizbaras](https://github.com/tadvi) - His winc project was the first step down the path to a pure Go Wails. +- [Mat Ryer](https://github.com/matryer) - For advice, support and bants. +- [Dustin Krysak](https://wiki.ubuntu.com/bashfulrobot) - His support and feedback has been invaluable. +- [Justen Walker](https://github.com/justenwalker/) - For helping wrangle COM issues which got v2 over the line. +- [Wang, Chi](https://github.com/patr0nus/) - The DeskGap project was a huge influence on the direction of Wails v2. +- [Serge Zaitsev](https://github.com/zserge) - Whilst Wails does not use the Webview project, it is still a source of inspiration. diff --git a/website/docs/gettingstarted/building.mdx b/website/docs/gettingstarted/building.mdx index c4c16ea48..e8f2e9e76 100644 --- a/website/docs/gettingstarted/building.mdx +++ b/website/docs/gettingstarted/building.mdx @@ -7,21 +7,13 @@ sidebar_position: 6 From the project directory, run `wails build`. This will compile your project and save the production-ready binary in the `build/bin` directory. -:::info Linux -If you are using a Linux distribution that does not have webkit2gtk-4.0 (such as Ubuntu 24.04), you will need to add `-tags webkit2_41`. -::: - If you run the binary, you should see the default application: -```mdx-code-block
- +
-
-``` +
+ + +For more details on compilation options, please refer to the [CLI Reference](/docs/reference/cli#build). -For more details on compilation options, please refer to the [CLI Reference](../reference/cli.mdx#build). diff --git a/website/docs/gettingstarted/development.mdx b/website/docs/gettingstarted/development.mdx index 034be31d6..5e2977f34 100644 --- a/website/docs/gettingstarted/development.mdx +++ b/website/docs/gettingstarted/development.mdx @@ -6,11 +6,10 @@ sidebar_position: 5 You can run your application in development mode by running `wails dev` from your project directory. This will do the following things: -- Build your application and run it -- Bind your Go code to the frontend so it can be called from JavaScript -- Using the power of [Vite](https://vitejs.dev/), will watch for modifications in your Go files and rebuild/re-run on change -- Sets up a [webserver](http://localhost:34115) that will serve your application over a browser. This allows you to use your favourite browser extensions. You can even call your Go code from the console + - Build your application and run it + - Watch for modifications in your Go files and rebuild/re-run on change + - Sets up a [webserver](http://localhost:34115) that will serve your application over a browser. This allows you to use your favourite browser extensions. You can even call your Go code from the console. -To get started, run `wails dev` in the project directory. More information on this can be found [here](../reference/cli.mdx#dev). +To get started, run `wails dev` in the project directory. More information on this can be found [here](/docs/reference/cli#dev). -Coming soon: Tutorial +Coming soon: Tutorial \ No newline at end of file diff --git a/website/docs/gettingstarted/firstproject.mdx b/website/docs/gettingstarted/firstproject.mdx index 5cf4dff58..014e04caa 100644 --- a/website/docs/gettingstarted/firstproject.mdx +++ b/website/docs/gettingstarted/firstproject.mdx @@ -8,92 +8,13 @@ sidebar_position: 2 Now that the CLI is installed, you can generate a new project by using the `wails init` command. -Pick your favourite framework: +To get up and running quickly, you can generate a default project by running `wails init -n myproject`. This will +create a directory called `myproject` and populate it with the default template. -```mdx-code-block -import Tabs from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; - - - - Generate a Svelte project using JavaScript with:

- - wails init -n myproject -t svelte - -If you would rather use TypeScript:
- - wails init -n myproject -t svelte-ts - -
- - Generate a React project using JavaScript with:

- - wails init -n myproject -t react - -If you would rather use TypeScript:
- - wails init -n myproject -t react-ts - -
- - Generate a Vue project using JavaScript with:

- - wails init -n myproject -t vue - -If you would rather use TypeScript:
- - wails init -n myproject -t vue-ts - -
- - Generate a Preact project using JavaScript with:

- - wails init -n myproject -t preact - -If you would rather use TypeScript:
- - wails init -n myproject -t preact-ts - -
- - Generate a Lit project using JavaScript with:

- - wails init -n myproject -t lit - -If you would rather use TypeScript:
- - wails init -n myproject -t lit-ts - -
- - Generate a Vanilla project using JavaScript with:

- - wails init -n myproject -t vanilla - -If you would rather use TypeScript:
- - wails init -n myproject -t vanilla-ts - -
-
-``` - -
- -There are also [community templates](../community/templates.mdx) available that offer different capabilities and frameworks. +Other project templates are available and can be listed using `wails init -l`. To see the other options available, you can run `wails init -help`. -More details can be found in the [CLI Reference](../reference/cli.mdx#init). +More details can be found in the [CLI Reference](/docs/reference/cli#init). ## Project Layout @@ -117,9 +38,9 @@ Wails projects have the following layout: - `/main.go` - The main application - `/frontend/` - Frontend project files - `/build/` - Project build directory -- `/build/appicon.png` - The application icon -- `/build/darwin/` - Mac specific project files -- `/build/windows/` - Windows specific project files + - `/build/appicon.png` - The application icon + - `/build/darwin/` - Mac specific project files + - `/build/windows/` - Windows specific project files - `/wails.json` - The project configuration - `/go.mod` - Go module file - `/go.sum` - Go module checksum file @@ -128,3 +49,5 @@ The `frontend` directory has nothing specific to Wails and can be any frontend p The `build` directory is used during the build process. These files may be updated to customise your builds. If files are removed from the build directory, default versions will be regenerated. + +The default module name in `go.mod` is "changeme". You should change this to something more appropriate. diff --git a/website/docs/gettingstarted/installation.mdx b/website/docs/gettingstarted/installation.mdx index 6189c6d83..5cd767d95 100644 --- a/website/docs/gettingstarted/installation.mdx +++ b/website/docs/gettingstarted/installation.mdx @@ -6,28 +6,27 @@ sidebar_position: 1 ## Supported Platforms -- Windows 10/11 AMD64/ARM64 -- MacOS 10.15+ AMD64 for development, MacOS 10.13+ for release -- MacOS 11.0+ ARM64 -- Linux AMD64/ARM64 +- Windows 10 +- MacOS x64 & arm64 (due October '21) +- Linux (due December '21) ## Dependencies Wails has a number of common dependencies that are required before installation: -- Go 1.21+ (macOS 15+ requires Go 1.23.3+) -- NPM (Node 15+) +- Go 1.17+ +- npm (Node 14+) ### Go -Download Go from the [Go Downloads Page](https://go.dev/dl/). +Download Go from the [Go Downloads Page](https://golang.org/dl/). -Ensure that you follow the official [Go installation instructions](https://go.dev/doc/install). You will also need to ensure that your `PATH` environment variable also includes the path to your `~/go/bin` directory. Restart your terminal and do the following checks: +Ensure that you follow the official [Go installation instructions](https://golang.org/doc/install#install). You will also need to ensure that your `PATH` environment variable also includes the path to your `~/go/bin` directory. Restart your terminal and do the following checks: - Check Go is installed correctly: `go version` - Check "~/go/bin" is in your PATH variable: `echo $PATH | grep go/bin` -### NPM +### npm Download NPM from the [Node Downloads Page](https://nodejs.org/en/download/). It is best to use the latest release as that is what we generally test against. @@ -37,7 +36,6 @@ Run `npm --version` to verify. You will also need to install platform specific dependencies: -```mdx-code-block import Tabs from "@theme/Tabs"; import TabItem from "@theme/TabItem"; @@ -49,55 +47,23 @@ import TabItem from "@theme/TabItem"; { label: "Linux", value: "Linux" }, ]} > - - Wails requires that the xcode command line tools are installed. This can be - done by running xcode-select --install. - + Coming Soon... - Wails requires that the WebView2 runtime is installed. Some Windows installations will already have this installed. You can check using the wails doctor command. - - - Linux requires the standard gcc build tools plus libgtk3 and libwebkit. Rather than list a ton of commands for different distros, Wails can try to determine what the installation commands are for your specific distribution. Run wails doctor after installation to be shown how to install the dependencies. If your distro/package manager is not supported, please consult the Add Linux Distro guide. -
Note:
- If you are using latest Linux version (example: Ubuntu 24.04) and it is not supporting libwebkit2gtk-4.0-dev, then you might encounter an issue in wails doctor: libwebkit not found. To resolve this issue you can install libwebkit2gtk-4.1-dev and during your build use the tag -tags webkit2_41. -

- After installing Wails via Go, ensure you run the following commands to update your PATH: -
- export PATH=$PATH:$(go env GOPATH)/bin -
- source ~/.bashrc or source ~/.zshrc + Wails requires that the WebView2{" "} + runtime is installed. Some Windows installations will already have this installed. You can check using the{" "} + wails doctor command (see below).
+ Coming Soon... -``` ## Optional Dependencies - [UPX](https://upx.github.io/) for compressing your applications. -- [NSIS](https://wails.io/docs/guides/windows-installer/) for generating Windows installers. ## Installing Wails -Run `go install github.com/wailsapp/wails/v2/cmd/wails@latest` to install the Wails CLI. - -Note: If you get an error similar to this: - -```shell -....\Go\pkg\mod\github.com\wailsapp\wails\v2@v2.1.0\pkg\templates\templates.go:28:12: pattern all:ides/*: no matching files found -``` - -please check you have Go 1.18+ installed: - -```shell -go version -``` +Run `go install github.com/wailsapp/wails/v2/cmd/wails@v2.0.0-beta.15` to install the Wails CLI. ## System Check Running `wails doctor` will check if you have the correct dependencies installed. If not, it will advise on what is missing and help on how to rectify any problems. - -## The `wails` command appears to be missing? - -If your system is reporting that the `wails` command is missing, make sure you have followed the Go installation guide -correctly. Normally, it means that the `go/bin` directory in your User's home directory is not in the `PATH` environment -variable. You will also normally need to close and reopen any open command prompts so that changes to the environment -made by the installer are reflected at the command prompt. diff --git a/website/docs/guides/angular.mdx b/website/docs/guides/angular.mdx deleted file mode 100644 index 92eec68d5..000000000 --- a/website/docs/guides/angular.mdx +++ /dev/null @@ -1,14 +0,0 @@ -# Angular - -Whilst Wails does not have an Angular template, it is possible to use Angular with Wails. - -## Dev Mode - -To get dev mode working with Angular, you need to add the following to your `wails.json`: - -```json - "frontend:build": "npx ng build", - "frontend:install": "npm install", - "frontend:dev:watcher": "npx ng serve", - "frontend:dev:serverUrl": "http://localhost:4200", -``` \ No newline at end of file diff --git a/website/docs/guides/application-development.mdx b/website/docs/guides/application-development.mdx index adefa4b04..46f088597 100644 --- a/website/docs/guides/application-development.mdx +++ b/website/docs/guides/application-development.mdx @@ -1,3 +1,4 @@ + # Application Development There are no hard and fast rules for developing applications with Wails, but there are some basic guidelines. @@ -10,10 +11,6 @@ The pattern used by the default templates are that `main.go` is used for configu The `app.go` file will define a struct that has 2 methods which act as hooks into the main application: ```go title="app.go" -import ( - "context" -) - type App struct { ctx context.Context } @@ -32,8 +29,8 @@ func (a *App) shutdown(ctx context.Context) { - The startup method is called as soon as Wails allocates the resources it needs and is a good place for creating resources, setting up event listeners and anything else the application needs at startup. - It is given a [`context.Context`](https://pkg.go.dev/context) which is usually saved in a struct field. This context is needed for calling the - [runtime](../reference/runtime/intro.mdx). If this method returns an error, the application will terminate. + It is given a `context.Context` which is usually saved in a struct field. This context is needed for calling the + [runtime](/docs/reference/runtime/intro). If this method returns an error, the application will terminate. In dev mode, the error will be output to the console. - The shutdown method will be called by Wails right at the end of the shutdown process. This is a good place to deallocate @@ -59,21 +56,17 @@ func main() { log.Fatal(err) } } + ``` -More information on application lifecycle hooks can be found [here](../howdoesitwork.mdx#application-lifecycle-callbacks). +More information on application lifecycle hooks can be found [here](/docs/howdoesitwork#application-lifecycle-callbacks). ## Binding Methods It is likely that you will want to call Go methods from the frontend. This is normally done by adding public methods to the already defined struct in `app.go`: -```go {3,21-23} title="app.go" -import ( - "context" - "fmt" -) - +```go {16-18} title="app.go" type App struct { ctx context.Context } @@ -90,7 +83,7 @@ func (a *App) shutdown(ctx context.Context) { } func (a *App) Greet(name string) string { - return fmt.Sprintf("Hello %s!", name) + return fmt.Printf("Hello %s!", name) } ``` @@ -107,113 +100,24 @@ func main() { Height: 600, OnStartup: app.startup, OnShutdown: app.shutdown, - Bind: []interface{}{ - app, - }, + Bind: []interface{}{ + app, + }, }) if err != nil { log.Fatal(err) } } + ``` This will bind all public methods in our `App` struct (it will never bind the startup and shutdown methods). -### Dealing with context when binding multiple structs - -If you want to bind methods for multiple structs but want each struct to keep a reference to the context so that you -can use the runtime functions, a good pattern is to pass the context from the `OnStartup` method to your struct instances -: - -```go -func main() { - - app := NewApp() - otherStruct := NewOtherStruct() - - err := wails.Run(&options.App{ - Title: "My App", - Width: 800, - Height: 600, - OnStartup: func(ctx context.Context){ - app.SetContext(ctx) - otherStruct.SetContext(ctx) - }, - OnShutdown: app.shutdown, - Bind: []interface{}{ - app, - otherStruct - }, - }) - if err != nil { - log.Fatal(err) - } -} -``` - -Also you might want to use Enums in your structs and have models for them on frontend. -In that case you should create array that will contain all possible enum values, instrument enum type and bind it to the app: - -```go {16-18} title="app.go" -type Weekday string - -const ( - Sunday Weekday = "Sunday" - Monday Weekday = "Monday" - Tuesday Weekday = "Tuesday" - Wednesday Weekday = "Wednesday" - Thursday Weekday = "Thursday" - Friday Weekday = "Friday" - Saturday Weekday = "Saturday" -) - -var AllWeekdays = []struct { - Value Weekday - TSName string -}{ - {Sunday, "SUNDAY"}, - {Monday, "MONDAY"}, - {Tuesday, "TUESDAY"}, - {Wednesday, "WEDNESDAY"}, - {Thursday, "THURSDAY"}, - {Friday, "FRIDAY"}, - {Saturday, "SATURDAY"}, -} -``` - -In the main application configuration, the `EnumBind` key is where we can tell Wails what we want to bind enums as well: - -```go {11-13} title="main.go" -func main() { - - app := NewApp() - - err := wails.Run(&options.App{ - Title: "My App", - Width: 800, - Height: 600, - OnStartup: app.startup, - OnShutdown: app.shutdown, - Bind: []interface{}{ - app, - }, - EnumBind: []interface{}{ - AllWeekdays, - }, - }) - if err != nil { - log.Fatal(err) - } -} -``` - -This will add missing enums to your `model.ts` file. - -More information on Binding can be found [here](../howdoesitwork.mdx#method-binding). +More information on Binding can be found [here](/docs/howdoesitwork#method-binding). ## Application Menu -Wails supports adding a menu to your application. This is done by passing a [Menu](../reference/menus.mdx#menu) struct +Wails supports adding a menu to your application. This is done by passing a [Menu](/docs/reference/menus#menu) struct to application config. It's common to use a method that returns a Menu, and even more common for that to be a method on the `App` struct used for the lifecycle hooks. @@ -229,14 +133,15 @@ func main() { OnStartup: app.startup, OnShutdown: app.shutdown, Menu: app.menu(), - Bind: []interface{}{ - app, - }, + Bind: []interface{}{ + app, + }, }) if err != nil { log.Fatal(err) } } + ``` ## Assets @@ -256,20 +161,11 @@ The second, if given, will be executed in the `frontend` directory to build the If these 2 keys aren't given, then Wails does absolutely nothing with the frontend. It is only expecting that `embed.FS`. -### AssetsHandler - -A Wails v2 app can optionally define a `http.Handler` in the `options.App`, which allows hooking into the AssetServer to -create files on the fly or process POST/PUT requests. -GET requests are always first handled by the `assets` FS. If the FS doesn't find the requested file the request will be -forwarded to the `http.Handler` for serving. Any requests other than GET will be directly processed by the `AssetsHandler` -if specified. -It's also possible to only use the `AssetsHandler` by specifying `nil` as the `Assets` option. - ## Built in Dev Server Running `wails dev` will start the built in dev server which will start a file watcher in your project directory. By default, if any file changes, wails checks if it was an application file (default: `.go`, configurable with `-e` flag). -If it was, then it will rebuild your application and relaunch it. If the changed file was in the assets, +If it was, then it will rebuild your application and relaunch it. If the changed file was in the `assetdir` directory, it will issue a reload after a short amount of time. The dev server uses a technique called "debouncing" which means it doesn't reload straight away, @@ -283,33 +179,8 @@ be saved to your project config and become the default. Some frameworks come with their own live-reloading server, however they will not be able to take advantage of the Wails Go bindings. In this scenario, it is best to run a watcher script that rebuilds the project into the build directory, which Wails will be watching. For an example, see the default svelte template that uses [rollup](https://rollupjs.org/guide/en/). - -### Create React App - -The process for a Create-React-App project is slightly more complicated. In order to support live frontend reloading the following configuration -needs to be added to your `wails.json`: - -```json - "frontend:dev:watcher": "yarn start", - "frontend:dev:serverUrl": "http://localhost:3000", -``` - -The `frontend:dev:watcher` command will start the Create-React-App development server (hosted on port `3000` typically). The `frontend:dev:serverUrl` command then -instructs Wails to serve assets from the development server when loading the frontend rather than from the build folder. In addition to the above, the -`index.html` needs to be updated with the following: - -```html - - - - - -``` - -This is required as the watcher command that rebuilds the frontend prevents Wails from injecting the required scripts. This circumvents that issue by ensuring -the scripts are always injected. With this configuration, `wails dev` can be run which will appropriately build the frontend and backend with hot-reloading enabled. -Additionally, when accessing the application from a browser the React developer tools can now be used on a non-minified version of the application for straightforward -debugging. Finally, for faster builds, `wails dev -s` can be run to skip the default building of the frontend by Wails as this is an unnecessary step. +For [create-react-app](https://create-react-app.dev/), it's possible to use +[this script](https://gist.github.com/int128/e0cdec598c5b3db728ff35758abdbafd) to achieve a similar result. ## Go Module diff --git a/website/docs/guides/crossplatform-build.mdx b/website/docs/guides/crossplatform-build.mdx deleted file mode 100644 index f6fbc0f06..000000000 --- a/website/docs/guides/crossplatform-build.mdx +++ /dev/null @@ -1,65 +0,0 @@ -# Crossplatform build with Github Actions - -To build a Wails project for all the available platforms, you need to create an application build for each operating system. One effective method to achieve this is by utilizing GitHub Actions. - -An action that facilitates building a Wails app is available at: -https://github.com/dAppServer/wails-build-action - -In case the existing action doesn't fulfill your requirements, you can select only the necessary steps from the source: -https://github.com/dAppServer/wails-build-action/blob/main/action.yml - -Below is a comprehensive example that demonstrates building an app upon the creation of a new Git tag and subsequently uploading it to the Actions artifacts: - -```yaml -name: Wails build - -on: - push: - tags: - # Match any new tag - - '*' - -env: - # Necessary for most environments as build failure can occur due to OOM issues - NODE_OPTIONS: "--max-old-space-size=4096" - -jobs: - build: - strategy: - # Failure in one platform build won't impact the others - fail-fast: false - matrix: - build: - - name: 'App' - platform: 'linux/amd64' - os: 'ubuntu-latest' - - name: 'App' - platform: 'windows/amd64' - os: 'windows-latest' - - name: 'App' - platform: 'darwin/universal' - os: 'macos-latest' - - runs-on: ${{ matrix.build.os }} - steps: - - name: Checkout - uses: actions/checkout@v2 - with: - submodules: recursive - - - name: Build wails - uses: dAppServer/wails-build-action@v2.2 - id: build - with: - build-name: ${{ matrix.build.name }} - build-platform: ${{ matrix.build.platform }} - package: false - go-version: '1.20' -``` - -This example offers opportunities for various enhancements, including: -- Caching dependencies -- Code signing -- Uploading to platforms like S3, Supabase, etc. -- Injecting secrets as environment variables -- Utilizing environment variables as build variables (such as version variable extracted from the current Git tag) diff --git a/website/docs/guides/custom-protocol-schemes.mdx b/website/docs/guides/custom-protocol-schemes.mdx deleted file mode 100644 index 216fb7100..000000000 --- a/website/docs/guides/custom-protocol-schemes.mdx +++ /dev/null @@ -1,207 +0,0 @@ -# Custom Protocol Scheme association - -Custom Protocols feature allows you to associate specific custom protocol with your app so that when users open links with this protocol, -your app is launched to handle them. This can be particularly useful to connect your desktop app with your web app. -In this guide, we'll walk through the steps to implement custom protocols in Wails app. - - -## Set Up Custom Protocol Schemes Association: -To set up custom protocol, you need to modify your application's wails.json file. -In "info" section add a "protocols" section specifying the protocols your app should be associated with. - -For example: -```json -{ - "info": { - "protocols": [ - { - "scheme": "myapp", - "description": "My App Protocol", - "role": "Editor" - } - ] - } -} -``` - -| Property | Description | -|:------------|:--------------------------------------------------------------------------------------| -| scheme | Custom Protocol scheme. e.g. myapp | -| description | Windows-only. The description. | -| role | macOS-only. The app’s role with respect to the type. Corresponds to CFBundleTypeRole. | - -## Platform Specifics: - -### macOS -When you open custom protocol with your app, the system will launch your app and call the `OnUrlOpen` function in your Wails app. Example: -```go title="main.go" -func main() { - // Create application with options - err := wails.Run(&options.App{ - Title: "wails-open-file", - Width: 1024, - Height: 768, - AssetServer: &assetserver.Options{ - Assets: assets, - }, - BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, - Mac: &mac.Options{ - OnUrlOpen: func(url string) { println(url) }, - }, - Bind: []interface{}{ - app, - }, - }) - - if err != nil { - println("Error:", err.Error()) - } -} -``` - -If you want to handle universal links as well, follow this [guide](https://developer.apple.com/documentation/xcode/supporting-universal-links-in-your-app) to add required entitlements, add required keys to Info.plist and configure `apple-app-site-association` on your website. - -Here is example for Info.plist: -```xml -NSUserActivityTypes - - NSUserActivityTypeBrowsingWeb - -``` - -And for entitlements.plist -```xml -com.apple.developer.associated-domains - - applinks:myawesomeapp.com - -``` - - -### Windows -On Windows Custom Protocol Schemes is supported only with NSIS installer. During installation, the installer will create a -registry entry for your schemes. When you open url with your app, new instance of app is launched and url is passed -as argument to your app. To handle this you should parse command line arguments in your app. Example: -```go title="main.go" -func main() { - argsWithoutProg := os.Args[1:] - - if len(argsWithoutProg) != 0 { - println("launchArgs", argsWithoutProg) - } -} -``` - -You also can enable single instance lock for your app. In this case, when you open url with your app, new instance of app is not launched -and arguments are passed to already running instance. Check single instance lock guide for details. Example: -```go title="main.go" -func main() { - // Create application with options - err := wails.Run(&options.App{ - Title: "wails-open-file", - Width: 1024, - Height: 768, - AssetServer: &assetserver.Options{ - Assets: assets, - }, - BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, - SingleInstanceLock: &options.SingleInstanceLock{ - UniqueId: "e3984e08-28dc-4e3d-b70a-45e961589cdc", - OnSecondInstanceLaunch: app.onSecondInstanceLaunch, - }, - Bind: []interface{}{ - app, - }, - }) -} -``` - -### Linux -Currently, Wails doesn't support bundling for Linux. So, you need to create file associations manually. -For example if you distribute your app as a .deb package, you can create file associations by adding required files in you bundle. -You can use [nfpm](https://nfpm.goreleaser.com/) to create .deb package for your app. - -1. Create a .desktop file for your app and specify file associations there (note that `%u` is important in Exec). Example: -```ini -[Desktop Entry] -Categories=Office -Exec=/usr/bin/wails-open-file %u -Icon=wails-open-file.png -Name=wails-open-file -Terminal=false -Type=Application -MimeType=x-scheme-handler/myapp; -``` - -2. Prepare postInstall/postRemove scripts for your package. Example: -```sh -# reload desktop database to load app in list of available -update-desktop-database /usr/share/applications -``` -3. Configure nfpm to use your scripts and files. Example: -```yaml -name: "wails-open-file" -arch: "arm64" -platform: "linux" -version: "1.0.0" -section: "default" -priority: "extra" -maintainer: "FooBarCorp " -description: "Sample Package" -vendor: "FooBarCorp" -homepage: "http://example.com" -license: "MIT" -contents: -- src: ../bin/wails-open-file - dst: /usr/bin/wails-open-file -- src: ./main.desktop - dst: /usr/share/applications/wails-open-file.desktop -- src: ../appicon.svg - dst: /usr/share/icons/hicolor/scalable/apps/wails-open-file.svg -# copy icons to Yaru theme as well. For some reason Ubuntu didn't pick up fileicons from hicolor theme -- src: ../appicon.svg - dst: /usr/share/icons/Yaru/scalable/apps/wails-open-file.svg -scripts: - postinstall: ./postInstall.sh - postremove: ./postRemove.sh -``` -6. Build your .deb package using nfpm: -```sh -nfpm pkg --packager deb --target . -``` -7. Now when your package is installed, your app will be associated with custom protocol scheme. When you open url with your app, -new instance of app is launched and file path is passed as argument to your app. -To handle this you should parse command line arguments in your app. Example: -```go title="main.go" -func main() { - argsWithoutProg := os.Args[1:] - - if len(argsWithoutProg) != 0 { - println("launchArgs", argsWithoutProg) - } -} -``` - -You also can enable single instance lock for your app. In this case, when you open url with your app, new instance of app is not launched -and arguments are passed to already running instance. Check single instance lock guide for details. Example: -```go title="main.go" -func main() { - // Create application with options - err := wails.Run(&options.App{ - Title: "wails-open-file", - Width: 1024, - Height: 768, - AssetServer: &assetserver.Options{ - Assets: assets, - }, - BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, - SingleInstanceLock: &options.SingleInstanceLock{ - UniqueId: "e3984e08-28dc-4e3d-b70a-45e961589cdc", - OnSecondInstanceLaunch: app.onSecondInstanceLaunch, - }, - Bind: []interface{}{ - app, - }, - }) -} -``` diff --git a/website/docs/guides/developing-wails.mdx b/website/docs/guides/developing-wails.mdx new file mode 100644 index 000000000..58f9e9bd8 --- /dev/null +++ b/website/docs/guides/developing-wails.mdx @@ -0,0 +1,39 @@ + +# Contributing + +This page is a guide on how to contribute to the Wails project. + +First, a word of warning: Wails v2 has been through a number of iterations and pivots. There is a lot of code that +is either on hold or deprecated. Reading the whole project and trying to understand it may be confusing. This document +aims to focus on what is current and how to understand that. + +## Bugs + +For raising bugs, please open a ticket on GitHub and give it the \[v2\] label. Include the output of `wails doctor` +in the ticket to help us understand your environment. + +For fixing bugs, please comment on a ticket that you'd like to take it on and we will put a label on the ticket. +It is best to use Windows as it is done in pure Go, making debugging much easier. + +## Features + +To request a new feature, raise a ticket so that it may be discussed. The ticket should be given the +"Feature Request" label. These will be discussed and if selected for development will be given the label +"Ready for Development". + +To implement a new feature, raise a ticket as above or select a ticket with the "Ready for Development" label. + +When raising a PR, be mindful to state what platforms the PR has been tested on. Any new feature will not be accepted unless it works +on all platforms (if it can). + +:::warning What not to do + +PRs for features with no tickets aren't helpful as there's no context to the PR and it will not be prioritised. + +::: + +## Documentation + +Contributing to the documentation is easy by clicking on the "Edit this page" link on any of the pages. Documentation +updates can be done ad-hoc, without a ticket. + diff --git a/website/docs/guides/dynamic-assets.mdx b/website/docs/guides/dynamic-assets.mdx deleted file mode 100644 index 8d1debcef..000000000 --- a/website/docs/guides/dynamic-assets.mdx +++ /dev/null @@ -1,153 +0,0 @@ -# Dynamic Assets - -:::info - -This does not work with vite v5.0.0+ and wails v2 due to changes in vite. -Changes are planned in v3 to support similar functionality under vite v5.0.0+. -If you need this feature, stay with vite v4.0.0+. -See [issue 3240](https://github.com/wailsapp/wails/issues/3240) for details - -::: - -If you want to load or generate assets for your frontend dynamically, you can achieve that using the -[AssetsHandler](../reference/options#assetshandler) option. The AssetsHandler is a generic `http.Handler` which will -be called for any non GET request on the assets server and for GET requests which can not be served from the -bundled assets because the file is not found. - -By installing a custom AssetsHandler, you can serve your own assets using a custom asset server. - -## Example - -In our example project, we will create a simple assets handler which will load files off disk: - -```go title=main.go {17-36,49} -package main - -import ( - "embed" - "fmt" - "github.com/wailsapp/wails/v2" - "github.com/wailsapp/wails/v2/pkg/options" - "github.com/wailsapp/wails/v2/pkg/options/assetserver" - "net/http" - "os" - "strings" -) - -//go:embed all:frontend/dist -var assets embed.FS - -type FileLoader struct { - http.Handler -} - -func NewFileLoader() *FileLoader { - return &FileLoader{} -} - -func (h *FileLoader) ServeHTTP(res http.ResponseWriter, req *http.Request) { - var err error - requestedFilename := strings.TrimPrefix(req.URL.Path, "/") - println("Requesting file:", requestedFilename) - fileData, err := os.ReadFile(requestedFilename) - if err != nil { - res.WriteHeader(http.StatusBadRequest) - res.Write([]byte(fmt.Sprintf("Could not load file %s", requestedFilename))) - } - - res.Write(fileData) -} - -func main() { - // Create an instance of the app structure - app := NewApp() - - // Create application with options - err := wails.Run(&options.App{ - Title: "helloworld", - Width: 1024, - Height: 768, - AssetServer: &assetserver.Options{ - Assets: assets, - Handler: NewFileLoader(), - }, - BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 255}, - OnStartup: app.startup, - Bind: []interface{}{ - app, - }, - }) - - if err != nil { - println("Error:", err) - } -} -``` - -When we run the application in dev mode using `wails dev`, we will see the following output: - -``` -DEB | [ExternalAssetHandler] Loading 'http://localhost:3001/favicon.ico' -DEB | [ExternalAssetHandler] Loading 'http://localhost:3001/favicon.ico' failed, using AssetHandler -Requesting file: favicon.ico -``` - -As you can see, the assets handler is called when the default assets server is unable to serve -the `favicon.ico` file. - -If you right click the main application and select "inspect" to bring up the devtools, you can test -this feature out by typing the following into the console: - -``` -let response = await fetch('does-not-exist.txt'); -``` - -This will generate an error in the devtools. We can see that the error is what we expect, returned by -our custom assets handler: - -```mdx-code-block -

- -

-``` - -However, if we request `go.mod`, we will see the following output: - -```mdx-code-block -

- -

-``` - -This technique can be used to load images directly into the page. If we updated our default vanilla template and -replaced the logo image: - -```html - -``` - -with: - -```html - -``` - -Then we would see the following: - -```mdx-code-block -

- -

-``` - -:::warning - -Exposing your filesystem in this way is a security risk. It is recommended that you properly manage access -to your filesystem. - -::: diff --git a/website/docs/guides/file-association.mdx b/website/docs/guides/file-association.mdx deleted file mode 100644 index 71bbff37e..000000000 --- a/website/docs/guides/file-association.mdx +++ /dev/null @@ -1,228 +0,0 @@ -# File Association - -File association feature allows you to associate specific file types with your app so that when users open those files, -your app is launched to handle them. This can be particularly useful for text editors, image viewers, or any application -that works with specific file formats. In this guide, we'll walk through the steps to implement file association in Wails app. - - -## Set Up File Association: -To set up file association, you need to modify your application's wails.json file. -In "info" section add a "fileAssociations" section specifying the file types your app should be associated with. - -For example: -```json -{ - "info": { - "fileAssociations": [ - { - "ext": "wails", - "name": "Wails", - "description": "Wails Application File", - "iconName": "wailsFileIcon", - "role": "Editor" - }, - { - "ext": "jpg", - "name": "JPEG", - "description": "Image File", - "iconName": "jpegFileIcon", - "role": "Editor" - } - ] - } -} -``` - -| Property | Description | -|:------------|:---------------------------------------------------------------------------------------------------------------------------------------------------| -| ext | The extension (minus the leading period). e.g. png | -| name | The name. e.g. PNG File | -| iconName | The icon name without extension. Icons should be located in build folder. Proper icons will be generated from .png file for both macOS and Windows | -| description | Windows-only. The description. It is displayed on the `Type` column on Windows Explorer. | -| role | macOS-only. The app’s role with respect to the type. Corresponds to CFBundleTypeRole. | - -## Platform Specifics: - -### macOS -When you open file (or files) with your app, the system will launch your app and call the `OnFileOpen` function in your Wails app. Example: -```go title="main.go" -func main() { - // Create application with options - err := wails.Run(&options.App{ - Title: "wails-open-file", - Width: 1024, - Height: 768, - AssetServer: &assetserver.Options{ - Assets: assets, - }, - BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, - Mac: &mac.Options{ - OnFileOpen: func(filePaths []string) { println(filestring) }, - }, - Bind: []interface{}{ - app, - }, - }) - - if err != nil { - println("Error:", err.Error()) - } -} -``` - - -### Windows -On Windows file association is supported only with NSIS installer. During installation, the installer will create a -registry entry for your file associations. When you open file with your app, new instance of app is launched and file path is passed -as argument to your app. To handle this you should parse command line arguments in your app. Example: -```go title="main.go" -func main() { - argsWithoutProg := os.Args[1:] - - if len(argsWithoutProg) != 0 { - println("launchArgs", argsWithoutProg) - } -} -``` - -You also can enable single instance lock for your app. In this case, when you open file with your app, new instance of app is not launched -and arguments are passed to already running instance. Check single instance lock guide for details. Example: -```go title="main.go" -func main() { - // Create application with options - err := wails.Run(&options.App{ - Title: "wails-open-file", - Width: 1024, - Height: 768, - AssetServer: &assetserver.Options{ - Assets: assets, - }, - BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, - SingleInstanceLock: &options.SingleInstanceLock{ - UniqueId: "e3984e08-28dc-4e3d-b70a-45e961589cdc", - OnSecondInstanceLaunch: app.onSecondInstanceLaunch, - }, - Bind: []interface{}{ - app, - }, - }) -} -``` - -### Linux -Currently, Wails doesn't support bundling for Linux. So, you need to create file associations manually. -For example if you distribute your app as a .deb package, you can create file associations by adding required files in you bundle. -You can use [nfpm](https://nfpm.goreleaser.com/) to create .deb package for your app. - -1. Create a .desktop file for your app and specify file associations there. Example: -```ini -[Desktop Entry] -Categories=Office -Exec=/usr/bin/wails-open-file %u -Icon=wails-open-file.png -Name=wails-open-file -Terminal=false -Type=Application -MimeType=application/x-wails;application/x-test -``` - -2. Create mime types file. Example: -```xml - - - - Wails Application File - - - -``` - -3. Create icons for your file types. SVG icons are recommended. -4. Prepare postInstall/postRemove scripts for your package. Example: -```sh -# reload mime types to register file associations -update-mime-database /usr/share/mime -# reload desktop database to load app in list of available -update-desktop-database /usr/share/applications -# update icons -update-icon-caches /usr/share/icons/* -``` -5. Configure nfpm to use your scripts and files. Example: -```yaml -name: "wails-open-file" -arch: "arm64" -platform: "linux" -version: "1.0.0" -section: "default" -priority: "extra" -maintainer: "FooBarCorp " -description: "Sample Package" -vendor: "FooBarCorp" -homepage: "http://example.com" -license: "MIT" -contents: -- src: ../bin/wails-open-file - dst: /usr/bin/wails-open-file -- src: ./main.desktop - dst: /usr/share/applications/wails-open-file.desktop -- src: ./application-wails-mime.xml - dst: /usr/share/mime/packages/application-x-wails.xml -- src: ./application-test-mime.xml - dst: /usr/share/mime/packages/application-x-test.xml -- src: ../appicon.svg - dst: /usr/share/icons/hicolor/scalable/apps/wails-open-file.svg -- src: ../wailsFileIcon.svg - dst: /usr/share/icons/hicolor/scalable/mimetypes/application-x-wails.svg -- src: ../testFileIcon.svg - dst: /usr/share/icons/hicolor/scalable/mimetypes/application-x-test.svg -# copy icons to Yaru theme as well. For some reason Ubuntu didn't pick up fileicons from hicolor theme -- src: ../appicon.svg - dst: /usr/share/icons/Yaru/scalable/apps/wails-open-file.svg -- src: ../wailsFileIcon.svg - dst: /usr/share/icons/Yaru/scalable/mimetypes/application-x-wails.svg -- src: ../testFileIcon.svg - dst: /usr/share/icons/Yaru/scalable/mimetypes/application-x-test.svg -scripts: - postinstall: ./postInstall.sh - postremove: ./postRemove.sh -``` -6. Build your .deb package using nfpm: -```sh -nfpm pkg --packager deb --target . -``` -7. Now when your package is installed, your app will be associated with specified file types. When you open file with your app, -new instance of app is launched and file path is passed as argument to your app. -To handle this you should parse command line arguments in your app. Example: -```go title="main.go" -func main() { - argsWithoutProg := os.Args[1:] - - if len(argsWithoutProg) != 0 { - println("launchArgs", argsWithoutProg) - } -} -``` - -You also can enable single instance lock for your app. In this case, when you open file with your app, new instance of app is not launched -and arguments are passed to already running instance. Check single instance lock guide for details. Example: -```go title="main.go" -func main() { - // Create application with options - err := wails.Run(&options.App{ - Title: "wails-open-file", - Width: 1024, - Height: 768, - AssetServer: &assetserver.Options{ - Assets: assets, - }, - BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, - SingleInstanceLock: &options.SingleInstanceLock{ - UniqueId: "e3984e08-28dc-4e3d-b70a-45e961589cdc", - OnSecondInstanceLaunch: app.onSecondInstanceLaunch, - }, - Bind: []interface{}{ - app, - }, - }) -} -``` diff --git a/website/docs/guides/frameless.mdx b/website/docs/guides/frameless.mdx index 07d8d2d25..3bd48ca3a 100644 --- a/website/docs/guides/frameless.mdx +++ b/website/docs/guides/frameless.mdx @@ -1,11 +1,15 @@ + # Frameless Applications -Wails supports application that have no frames. This can be achieved by using the [frameless](../reference/options.mdx#frameless) -field in [Application Options](../reference/options.mdx#application-options). +Wails supports applications with no frame. This can be achieved by using the [frameless](/docs/reference/options#frameless) +field in [Application Options](/docs/reference/options#application-options). -Wails offers a simple solution for dragging the window: Any HTML element that has the CSS style `--wails-draggable:drag` will -act as a "drag handle". This property applies to all child elements. If you need to indicate that a nested element -should not drag, then use the attribute '--wails-draggable:no-drag' on that element. +Wails offers a simple solution for dragging the window: Any HTML element that has the attribute "data-wails-drag" will +act as a "drag handle". This property applies to all nested elements. If you need to indicate that a nested element +should not drag, then use the attribute 'data-wails-no-drag' on that element. + +The default vanilla template uses this, even though it is not frameless. The whole `body` element is tagged as draggable. +The `
` is tagged as being not draggable. ```html @@ -13,9 +17,9 @@ should not drag, then use the attribute '--wails-draggable:no-drag' on that elem - + -
+
@@ -26,67 +30,6 @@ should not drag, then use the attribute '--wails-draggable:no-drag' on that elem ``` -For some projects, using a CSS variable may not be possible due to dynamic styling. In this case, you can use the -`CSSDragProperty` and `CSSDragValue` application options to define a property and value that will be used to indicate -draggable regions: - -```go title=main.go -package main - -import ( - "embed" - - "github.com/wailsapp/wails/v2" - "github.com/wailsapp/wails/v2/pkg/options" - "github.com/wailsapp/wails/v2/pkg/options/assetserver" -) - -//go:embed all:frontend/dist -var assets embed.FS - -func main() { - // Create an instance of the app structure - app := NewApp() - - // Create application with options - err := wails.Run(&options.App{ - Title: "alwaysontop", - Width: 1024, - Height: 768, - AssetServer: &assetserver.Options{ - Assets: assets, - }, - Frameless: true, - CSSDragProperty: "widows", - CSSDragValue: "1", - Bind: []interface{}{ - app, - }, - }) - - if err != nil { - println("Error:", err) - } -} -``` - -```html title=index.html - - - - - - alwaysontop - - -
- - - -``` - :::info Fullscreen - -If you allow your application to go fullscreen, this drag functionality will be disabled. - + If you allow your application to go fullscreen, this drag functionality will be disabled. ::: diff --git a/website/docs/guides/frontend.mdx b/website/docs/guides/frontend.mdx index 2c3c78e42..84489cd99 100644 --- a/website/docs/guides/frontend.mdx +++ b/website/docs/guides/frontend.mdx @@ -1,31 +1,33 @@ + # Frontend ## Script Injection -When Wails serves your `index.html`, by default, it will inject 2 script entries into the `` tag to load `/wails/ipc.js` +When Wails serves your `index.html`, by default, it will inject 2 script entries into the `` tag to load `/wails/bindings.js` and `/wails/runtime.js`. These files install the bindings and runtime respectively. The code below shows where these are injected by default: ```html - - injection example - - - - + + injection example + + + + - - -
Please enter your name below 👇
-
- - -
+ + +
Please enter your name below 👇
+
+ + +
+ + + - - ``` @@ -34,40 +36,42 @@ The code below shows where these are injected by default: To provide more flexibility to developers, there is a meta tag that may be used to customise this behaviour: ```html - + ``` The options are as follows: -| Value | Description | -| ------------------- | ------------------------------------------------ | -| noautoinjectruntime | Disable the autoinjection of `/wails/runtime.js` | -| noautoinjectipc | Disable the autoinjection of `/wails/ipc.js` | -| noautoinject | Disable all autoinjection of scripts | +| Value | Description | +| -------------------- | ------------------------------------------------- | +| noautoinjectruntime | Disable the autoinjection of `/wails/runtime.js` | +| noautoinjectipc | Disable the autoinjection of `/wails/ipc.js` | +| noautoinject | Disable all autoinjection of scripts | -Multiple options may be used provided they are comma separated. +Multiple options may be used provided they are comma seperated. This code is perfectly valid and operates the same as the autoinjection version: ```html - - injection example - - - - - -
Please enter your name below 👇
-
- - -
+ + injection example + + + + + + +
Please enter your name below 👇
+
+ + +
+ + + + + - - - - -``` +``` \ No newline at end of file diff --git a/website/docs/guides/ides.mdx b/website/docs/guides/ides.mdx index 5fe5a7bb9..fda70ebf6 100644 --- a/website/docs/guides/ides.mdx +++ b/website/docs/guides/ides.mdx @@ -1,20 +1,16 @@ + # IDEs Wails aims to provide a great development experience. To that aim, we now support generating IDE specific configuration to provide smoother project setup. -Currently, we support [Visual Studio Code](https://code.visualstudio.com/) and [Goland](https://www.jetbrains.com/go/). +Currently, we support [Visual Studio Code](https://code.visualstudio.com/) but aim to support other IDEs such as Goland. ## Visual Studio Code -```mdx-code-block

- +

-``` When generating a project using the `-ide vscode` flags, IDE files will be created alongside the other project files. These files are placed into the `.vscode` directory and provide the correct configuration for debugging your application. @@ -23,44 +19,37 @@ The 2 files generated are `tasks.json` and `launch.json`. Below are the files ge ```json title="tasks.json" { - "version": "2.0.0", - "tasks": [ - { - "label": "build", - "type": "shell", - "options": { - "cwd": "${workspaceFolder}" - }, - "command": "go", - "args": [ - "build", - "-tags", - "dev", - "-gcflags", - "all=-N -l", - "-o", - "build/bin/myproject.exe" - ] - } - ] + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "type": "shell", + "options": { + "cwd": "${workspaceFolder}" + }, + "command": "go", + "args": ["build", "-tags", "dev", "-gcflags", "all=-N -l", "-o", "build/bin/myproject.exe"] + }, + ] } ``` ```json title="launch.json" { - "version": "0.2.0", - "configurations": [ - { - "name": "Wails: Debug myproject", - "type": "go", - "request": "launch", - "mode": "exec", - "program": "${workspaceFolder}/build/bin/myproject.exe", - "preLaunchTask": "build", - "cwd": "${workspaceFolder}", - "env": {} - } - ] + "version": "0.2.0", + "configurations": [ + { + "name": "Wails: Debug myproject", + "type": "go", + "request": "launch", + "mode": "exec", + "program": "${workspaceFolder}/build/bin/myproject.exe", + "preLaunchTask": "build", + "cwd": "${workspaceFolder}", + "env": {}, + "args": ["-assetdir", "frontend/src"] + }, + ] } ``` @@ -72,55 +61,51 @@ add the install and build steps: ```json title="tasks.json" { - "version": "2.0.0", - "tasks": [ - { - "label": "npm install", - "type": "npm", - "script": "install", - "options": { - "cwd": "${workspaceFolder}/frontend" - }, - "presentation": { - "clear": true, - "panel": "shared", - "showReuseMessage": false - }, - "problemMatcher": [] - }, - { - "label": "npm run build", - "type": "npm", - "script": "build", - "options": { - "cwd": "${workspaceFolder}/frontend" - }, - "presentation": { - "clear": true, - "panel": "shared", - "showReuseMessage": false - }, - "problemMatcher": [] - }, - { - "label": "build", - "type": "shell", - "options": { - "cwd": "${workspaceFolder}" - }, - "command": "go", - "args": [ - "build", - "-tags", - "dev", - "-gcflags", - "all=-N -l", - "-o", - "build/bin/vscode.exe" - ], - "dependsOn": ["npm install", "npm run build"] - } - ] + "version": "2.0.0", + "tasks": [ + { + "label": "npm install", + "type": "npm", + "script": "install", + "options": { + "cwd": "${workspaceFolder}/frontend" + }, + "presentation": { + "clear": true, + "panel": "shared", + "showReuseMessage": false + }, + "problemMatcher": [] + }, + { + "label": "npm run build", + "type": "npm", + "script": "build", + "options": { + "cwd": "${workspaceFolder}/frontend" + }, + "presentation": { + "clear": true, + "panel": "shared", + "showReuseMessage": false + }, + "problemMatcher": [] + }, + { + "label": "build", + "type": "shell", + "options": { + "cwd": "${workspaceFolder}" + }, + "command": "go", + "args": ["build", "-tags", "dev", "-gcflags", "all=-N -l", "-o", "build/bin/vscode.exe"], + "dependsOn":[ + "npm install", + "npm run build" + ] + + }, + ] } ``` @@ -128,4 +113,4 @@ add the install and build steps: In the future, we hope to generate a `tasks.json` that includes the install and build steps automatically. -::: +::: \ No newline at end of file diff --git a/website/docs/guides/linux-distro-support.mdx b/website/docs/guides/linux-distro-support.mdx deleted file mode 100644 index b64ed0c03..000000000 --- a/website/docs/guides/linux-distro-support.mdx +++ /dev/null @@ -1,110 +0,0 @@ -# Linux Distro Support - -## Overview - -Wails offers Linux support but providing installation instructions for all available distributions is an impossible task. -Instead, Wails tries to determine if the packages you need to develop applications are available via your system's package -manager. Currently, we support the following package managers: - -- apt -- dnf -- emerge -- eopkg -- nixpkgs -- pacman -- zypper - -## Adding package names - -There may be circumstances where your distro uses one of the supported package managers but the package name -is different. For example, you may use an Ubuntu derivative, but the package name for gtk may be different. Wails -attempts to find the correct package by iterating through a list of package names. -The list of packages are stored in the packagemanager specific file in the `v2/internal/system/packagemanager` -directory. In our example, this would be `v2/internal/system/packagemanager/apt.go`. - -In this file, the list of packages are defined by the `Packages()` method: - -```go -func (a *Apt) Packages() packagemap { - return packagemap{ - "libgtk-3": []*Package{ - {Name: "libgtk-3-dev", SystemPackage: true, Library: true}, - }, - "libwebkit": []*Package{ - {Name: "libwebkit2gtk-4.0-dev", SystemPackage: true, Library: true}, - }, - "gcc": []*Package{ - {Name: "build-essential", SystemPackage: true}, - }, - "pkg-config": []*Package{ - {Name: "pkg-config", SystemPackage: true}, - }, - "npm": []*Package{ - {Name: "npm", SystemPackage: true}, - }, - "docker": []*Package{ - {Name: "docker.io", SystemPackage: true, Optional: true}, - }, - } -} -``` - -Let's assume that in our linux distro, `libgtk-3` is packaged under the name `lib-gtk3-dev`. -We could add support for this by adding the following line: - -```go {5} -func (a *Apt) Packages() packagemap { - return packagemap{ - "libgtk-3": []*Package{ - {Name: "libgtk-3-dev", SystemPackage: true, Library: true}, - {Name: "lib-gtk3-dev", SystemPackage: true, Library: true}, - }, - "libwebkit": []*Package{ - {Name: "libwebkit2gtk-4.0-dev", SystemPackage: true, Library: true}, - }, - "gcc": []*Package{ - {Name: "build-essential", SystemPackage: true}, - }, - "pkg-config": []*Package{ - {Name: "pkg-config", SystemPackage: true}, - }, - "npm": []*Package{ - {Name: "npm", SystemPackage: true}, - }, - "docker": []*Package{ - {Name: "docker.io", SystemPackage: true, Optional: true}, - }, - } -} -``` - -## Adding new package managers - -To add a new package manager, perform the following steps: - -- Create a new file in `v2/internal/system/packagemanager` called `.go`, where `` is the name of the package manager. -- Define a struct that conforms to the package manager interface defined in `pm.go`: - -```go -type PackageManager interface { - Name() string - Packages() packagemap - PackageInstalled(*Package) (bool, error) - PackageAvailable(*Package) (bool, error) - InstallCommand(*Package) string -} -``` - -- `Name()` should return the name of the package manager -- `Packages()` should return a `packagemap`, that provides candidate filenames for dependencies -- `PackageInstalled()` should return `true` if the given package is installed -- `PackageAvailable()` should return `true` if the given package is not installed but available for installation -- `InstallCommand()` should return the exact command to install the given package name - -Take a look at the other package managers code to get an idea how this works. - -:::info Remember - -If you add support for a new package manager, don't forget to also update this page! - -::: diff --git a/website/docs/guides/linux.mdx b/website/docs/guides/linux.mdx deleted file mode 100644 index 2cfc2e62a..000000000 --- a/website/docs/guides/linux.mdx +++ /dev/null @@ -1,126 +0,0 @@ -# Linux - -This page has miscellaneous guides related to developing Wails applications for Linux. - -## Video tag doesn't fire "ended" event - -When using a video tag, the "ended" event is not fired when the video is finished playing. This is a bug -in WebkitGTK, however you can use the following workaround to fix it: - -```js -videoTag.addEventListener("timeupdate", (event) => { - if (event.target.duration - event.target.currentTime < 0.2) { - let ended = new Event("ended"); - event.target.dispatchEvent(ended); - } -}); -``` - -Source: [Lyimmi](https://github.com/Lyimmi) on the -[discussions board](https://github.com/wailsapp/wails/issues/1729#issuecomment-1212291275) - -## GStreamer error when using Audio or Video elements - -If you are seeing the following error when including `